aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING2
-rw-r--r--configure.ac2
-rw-r--r--contrib/debian/copyright2
-rwxr-xr-xcontrib/devtools/clang-format-diff.py4
-rwxr-xr-xcontrib/devtools/optimize-pngs.py2
-rwxr-xr-xcontrib/zmq/zmq_sub.py2
-rw-r--r--doc/release-notes.md10
-rwxr-xr-xqa/pull-tester/rpc-tests.py2
-rwxr-xr-xqa/rpc-tests/bumpfee.py317
-rwxr-xr-xqa/rpc-tests/fundrawtransaction.py30
-rwxr-xr-xqa/rpc-tests/importmulti.py14
-rwxr-xr-xqa/rpc-tests/listsinceblock.py80
-rwxr-xr-xqa/rpc-tests/p2p-feefilter.py4
-rwxr-xr-xqa/rpc-tests/p2p-segwit.py2
-rwxr-xr-xqa/rpc-tests/pruning.py2
-rwxr-xr-xqa/rpc-tests/segwit.py2
-rw-r--r--src/clientversion.h2
-rw-r--r--src/net.cpp25
-rw-r--r--src/net.h2
-rw-r--r--src/qt/bitcoingui.cpp15
-rw-r--r--src/qt/bitcoingui.h2
-rw-r--r--src/qt/bitcoinstrings.cpp7
-rw-r--r--src/qt/clientmodel.h2
-rw-r--r--src/qt/locale/bitcoin_af_ZA.ts20
-rw-r--r--src/qt/locale/bitcoin_ca.ts4
-rw-r--r--src/qt/locale/bitcoin_ca_ES.ts4
-rw-r--r--src/qt/locale/bitcoin_cs.ts4
-rw-r--r--src/qt/locale/bitcoin_da.ts4
-rw-r--r--src/qt/locale/bitcoin_de.ts4
-rw-r--r--src/qt/locale/bitcoin_en.ts73
-rw-r--r--src/qt/locale/bitcoin_en_GB.ts4
-rw-r--r--src/qt/locale/bitcoin_es.ts44
-rw-r--r--src/qt/locale/bitcoin_es_ES.ts4
-rw-r--r--src/qt/locale/bitcoin_fi.ts4
-rw-r--r--src/qt/locale/bitcoin_fr.ts32
-rw-r--r--src/qt/locale/bitcoin_it.ts4
-rw-r--r--src/qt/locale/bitcoin_ja.ts24
-rw-r--r--src/qt/locale/bitcoin_ko_KR.ts4
-rw-r--r--src/qt/locale/bitcoin_nb.ts4
-rw-r--r--src/qt/locale/bitcoin_nl.ts4
-rw-r--r--src/qt/locale/bitcoin_pl.ts166
-rw-r--r--src/qt/locale/bitcoin_pt_BR.ts20
-rw-r--r--src/qt/locale/bitcoin_pt_PT.ts4
-rw-r--r--src/qt/locale/bitcoin_ru.ts4
-rw-r--r--src/qt/locale/bitcoin_sv.ts4
-rw-r--r--src/qt/locale/bitcoin_tr.ts4
-rw-r--r--src/qt/locale/bitcoin_uk.ts4
-rw-r--r--src/qt/locale/bitcoin_zh_CN.ts4
-rw-r--r--src/qt/locale/bitcoin_zh_TW.ts24
-rw-r--r--src/qt/modaloverlay.cpp6
-rw-r--r--src/qt/modaloverlay.h3
-rw-r--r--src/qt/sendcoinsdialog.cpp3
-rw-r--r--src/qt/test/rpcnestedtests.cpp2
-rw-r--r--src/rpc/client.cpp1
-rw-r--r--src/rpc/server.cpp14
-rw-r--r--src/rpc/server.h5
-rw-r--r--src/test/addrman_tests.cpp2
-rw-r--r--src/test/cuckoocache_tests.cpp2
-rw-r--r--src/test/dbwrapper_tests.cpp2
-rw-r--r--src/test/limitedmap_tests.cpp2
-rw-r--r--src/test/scheduler_tests.cpp4
-rw-r--r--src/test/script_tests.cpp2
-rw-r--r--src/test/test_bitcoin.cpp2
-rw-r--r--src/txmempool.cpp23
-rw-r--r--src/txmempool.h25
-rw-r--r--src/validation.cpp81
-rw-r--r--src/validationinterface.h11
-rw-r--r--src/wallet/rpcwallet.cpp315
-rw-r--r--src/wallet/wallet.cpp108
-rw-r--r--src/wallet/wallet.h14
70 files changed, 1392 insertions, 242 deletions
diff --git a/COPYING b/COPYING
index c6be8e5470..c6203c0f76 100644
--- a/COPYING
+++ b/COPYING
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2009-2016 The Bitcoin Core developers
+Copyright (c) 2009-2017 The Bitcoin Core developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/configure.ac b/configure.ac
index 4723c69d5d..346695043d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5,7 +5,7 @@ define(_CLIENT_VERSION_MINOR, 13)
define(_CLIENT_VERSION_REVISION, 99)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, false)
-define(_COPYRIGHT_YEAR, 2016)
+define(_COPYRIGHT_YEAR, 2017)
define(_COPYRIGHT_HOLDERS,[The %s developers])
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]])
AC_INIT([Bitcoin Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/bitcoin/bitcoin/issues],[bitcoin],[https://bitcoincore.org/])
diff --git a/contrib/debian/copyright b/contrib/debian/copyright
index 0fa06f1aa9..72d64ce62d 100644
--- a/contrib/debian/copyright
+++ b/contrib/debian/copyright
@@ -5,7 +5,7 @@ Upstream-Contact: Satoshi Nakamoto <satoshin@gmx.com>
Source: https://github.com/bitcoin/bitcoin
Files: *
-Copyright: 2009-2016, Bitcoin Core Developers
+Copyright: 2009-2017, Bitcoin Core Developers
License: Expat
Comment: The Bitcoin Core Developers encompasses the current developers listed on bitcoin.org,
as well as the numerous contributors to the project.
diff --git a/contrib/devtools/clang-format-diff.py b/contrib/devtools/clang-format-diff.py
index 13d2573b9f..7ea49b65e1 100755
--- a/contrib/devtools/clang-format-diff.py
+++ b/contrib/devtools/clang-format-diff.py
@@ -128,7 +128,7 @@ def main():
line_count = int(match.group(3))
if line_count == 0:
continue
- end_line = start_line + line_count - 1;
+ end_line = start_line + line_count - 1
lines_by_file.setdefault(filename, []).extend(
['-lines', str(start_line) + ':' + str(end_line)])
@@ -147,7 +147,7 @@ def main():
stderr=None, stdin=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
- sys.exit(p.returncode);
+ sys.exit(p.returncode)
if not args.i:
with open(filename) as f:
diff --git a/contrib/devtools/optimize-pngs.py b/contrib/devtools/optimize-pngs.py
index 0f653e010b..9286ab731f 100755
--- a/contrib/devtools/optimize-pngs.py
+++ b/contrib/devtools/optimize-pngs.py
@@ -39,7 +39,7 @@ for folder in folders:
if extension.lower() == '.png':
print("optimizing "+file+"..."),
file_path = os.path.join(absFolder, file)
- fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)};
+ fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)}
fileMetaMap['contentHashPre'] = content_hash(file_path)
pngCrushOutput = ""
diff --git a/contrib/zmq/zmq_sub.py b/contrib/zmq/zmq_sub.py
index 6f57aa47e9..5707188f23 100755
--- a/contrib/zmq/zmq_sub.py
+++ b/contrib/zmq/zmq_sub.py
@@ -22,7 +22,7 @@ try:
msg = zmqSubSocket.recv_multipart()
topic = str(msg[0])
body = msg[1]
- sequence = "Unknown";
+ sequence = "Unknown"
if len(msg[-1]) == 4:
msgSequence = struct.unpack('<I', msg[-1])[-1]
sequence = str(msgSequence)
diff --git a/doc/release-notes.md b/doc/release-notes.md
index bbda55854f..0ea9e1949e 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -128,6 +128,16 @@ Call "getmininginfo" loses the "testnet" field in favor of the more generic "cha
### Wallet
+0.14.0 Fundrawtransaction change address reuse
+==============================================
+
+Before 0.14, `fundrawtransaction` was by default wallet stateless. In almost all cases `fundrawtransaction` does add a change-output to the outputs of the funded transaction. Before 0.14, the used keypool key was never marked as change-address key and directly returned to the keypool (leading to address reuse).
+Before 0.14, calling `getnewaddress` directly after `fundrawtransaction` did generate the same address as the change-output address.
+
+Since 0.14, fundrawtransaction does reserve the change-output-key from the keypool by default (optional by setting `reserveChangeKey`, default = `true`)
+
+Users should also consider using `getrawchangeaddress()` in conjunction with `fundrawtransaction`'s `changeAddress` option.
+
### GUI
### Tests
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index 83b6bdfe48..26bc6a73df 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -151,7 +151,9 @@ testScripts = [
'signmessages.py',
'nulldummy.py',
'import-rescan.py',
+ 'bumpfee.py',
'rpcnamedargs.py',
+ 'listsinceblock.py',
]
if ENABLE_ZMQ:
testScripts.append('zmq_test.py')
diff --git a/qa/rpc-tests/bumpfee.py b/qa/rpc-tests/bumpfee.py
new file mode 100755
index 0000000000..0ebd79f7f3
--- /dev/null
+++ b/qa/rpc-tests/bumpfee.py
@@ -0,0 +1,317 @@
+#!/usr/bin/env python3
+# Copyright (c) 2016 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+from segwit import send_to_witness
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework import blocktools
+from test_framework.mininode import CTransaction
+from test_framework.util import *
+from test_framework.util import *
+
+import io
+import time
+
+# Sequence number that is BIP 125 opt-in and BIP 68-compliant
+BIP125_SEQUENCE_NUMBER = 0xfffffffd
+
+WALLET_PASSPHRASE = "test"
+WALLET_PASSPHRASE_TIMEOUT = 3600
+
+
+class BumpFeeTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = True
+
+ def setup_network(self, split=False):
+ extra_args = [["-debug", "-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)]
+ for i in range(self.num_nodes)]
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, extra_args)
+
+ # Encrypt wallet for test_locked_wallet_fails test
+ self.nodes[1].encryptwallet(WALLET_PASSPHRASE)
+ bitcoind_processes[1].wait()
+ self.nodes[1] = start_node(1, self.options.tmpdir, extra_args[1])
+ self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
+
+ connect_nodes_bi(self.nodes, 0, 1)
+ self.is_network_split = False
+ self.sync_all()
+
+ def run_test(self):
+ peer_node, rbf_node = self.nodes
+ rbf_node_address = rbf_node.getnewaddress()
+
+ # fund rbf node with 10 coins of 0.001 btc (100,000 satoshis)
+ print("Mining blocks...")
+ peer_node.generate(110)
+ self.sync_all()
+ for i in range(25):
+ peer_node.sendtoaddress(rbf_node_address, 0.001)
+ self.sync_all()
+ peer_node.generate(1)
+ self.sync_all()
+ assert_equal(rbf_node.getbalance(), Decimal("0.025"))
+
+ print("Running tests")
+ dest_address = peer_node.getnewaddress()
+ test_small_output_fails(rbf_node, dest_address)
+ test_dust_to_fee(rbf_node, dest_address)
+ test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address)
+ test_segwit_bumpfee_succeeds(rbf_node, dest_address)
+ test_nonrbf_bumpfee_fails(peer_node, dest_address)
+ test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address)
+ test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address)
+ test_settxfee(rbf_node, dest_address)
+ test_rebumping(rbf_node, dest_address)
+ test_rebumping_not_replaceable(rbf_node, dest_address)
+ test_unconfirmed_not_spendable(rbf_node, rbf_node_address)
+ test_locked_wallet_fails(rbf_node, dest_address)
+ print("Success")
+
+
+def test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address):
+ rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
+ rbftx = rbf_node.gettransaction(rbfid)
+ sync_mempools((rbf_node, peer_node))
+ assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool()
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ assert bumped_tx["fee"] - abs(rbftx["fee"]) > 0
+ # check that bumped_tx propogates, original tx was evicted and has a wallet conflict
+ sync_mempools((rbf_node, peer_node))
+ assert bumped_tx["txid"] in rbf_node.getrawmempool()
+ assert bumped_tx["txid"] in peer_node.getrawmempool()
+ assert rbfid not in rbf_node.getrawmempool()
+ assert rbfid not in peer_node.getrawmempool()
+ oldwtx = rbf_node.gettransaction(rbfid)
+ assert len(oldwtx["walletconflicts"]) > 0
+ # check wallet transaction replaces and replaced_by values
+ bumpedwtx = rbf_node.gettransaction(bumped_tx["txid"])
+ assert_equal(oldwtx["replaced_by_txid"], bumped_tx["txid"])
+ assert_equal(bumpedwtx["replaces_txid"], rbfid)
+
+
+def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
+ # Create a transaction with segwit output, then create an RBF transaction
+ # which spends it, and make sure bumpfee can be called on it.
+
+ segwit_in = next(u for u in rbf_node.listunspent() if u["amount"] == Decimal("0.001"))
+ segwit_out = rbf_node.validateaddress(rbf_node.getnewaddress())
+ rbf_node.addwitnessaddress(segwit_out["address"])
+ segwitid = send_to_witness(
+ version=0,
+ node=rbf_node,
+ utxo=segwit_in,
+ pubkey=segwit_out["pubkey"],
+ encode_p2sh=False,
+ amount=Decimal("0.0009"),
+ sign=True)
+
+ rbfraw = rbf_node.createrawtransaction([{
+ 'txid': segwitid,
+ 'vout': 0,
+ "sequence": BIP125_SEQUENCE_NUMBER
+ }], {dest_address: Decimal("0.0005"),
+ get_change_address(rbf_node): Decimal("0.0003")})
+ rbfsigned = rbf_node.signrawtransaction(rbfraw)
+ rbfid = rbf_node.sendrawtransaction(rbfsigned["hex"])
+ assert rbfid in rbf_node.getrawmempool()
+
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ assert bumped_tx["txid"] in rbf_node.getrawmempool()
+ assert rbfid not in rbf_node.getrawmempool()
+
+
+def test_nonrbf_bumpfee_fails(peer_node, dest_address):
+ # cannot replace a non RBF transaction (from node which did not enable RBF)
+ not_rbfid = create_fund_sign_send(peer_node, {dest_address: 0.00090000})
+ assert_raises_message(JSONRPCException, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid)
+
+
+def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
+ # cannot bump fee unless the tx has only inputs that we own.
+ # here, the rbftx has a peer_node coin and then adds a rbf_node input
+ # Note that this test depends upon the RPC code checking input ownership prior to change outputs
+ # (since it can't use fundrawtransaction, it lacks a proper change output)
+ utxos = [node.listunspent()[-1] for node in (rbf_node, peer_node)]
+ inputs = [{
+ "txid": utxo["txid"],
+ "vout": utxo["vout"],
+ "address": utxo["address"],
+ "sequence": BIP125_SEQUENCE_NUMBER
+ } for utxo in utxos]
+ output_val = sum(utxo["amount"] for utxo in utxos) - Decimal("0.001")
+ rawtx = rbf_node.createrawtransaction(inputs, {dest_address: output_val})
+ signedtx = rbf_node.signrawtransaction(rawtx)
+ signedtx = peer_node.signrawtransaction(signedtx["hex"])
+ rbfid = rbf_node.sendrawtransaction(signedtx["hex"])
+ assert_raises_message(JSONRPCException, "Transaction contains inputs that don't belong to this wallet",
+ rbf_node.bumpfee, rbfid)
+
+
+def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address):
+ # cannot bump fee if the transaction has a descendant
+ # parent is send-to-self, so we don't have to check which output is change when creating the child tx
+ parent_id = create_fund_sign_send(rbf_node, {rbf_node_address: 0.00050000})
+ tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000})
+ tx = rbf_node.signrawtransaction(tx)
+ txid = rbf_node.sendrawtransaction(tx["hex"])
+ assert_raises_message(JSONRPCException, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
+
+
+def test_small_output_fails(rbf_node, dest_address):
+ # cannot bump fee with a too-small output
+ rbfid = spend_one_input(rbf_node,
+ Decimal("0.00100000"),
+ {dest_address: 0.00080000,
+ get_change_address(rbf_node): Decimal("0.00010000")})
+ rbf_node.bumpfee(rbfid, {"totalFee": 20000})
+
+ rbfid = spend_one_input(rbf_node,
+ Decimal("0.00100000"),
+ {dest_address: 0.00080000,
+ get_change_address(rbf_node): Decimal("0.00010000")})
+ assert_raises_message(JSONRPCException, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 20001})
+
+
+def test_dust_to_fee(rbf_node, dest_address):
+ # check that if output is reduced to dust, it will be converted to fee
+ # the bumped tx sets fee=9900, but it converts to 10,000
+ rbfid = spend_one_input(rbf_node,
+ Decimal("0.00100000"),
+ {dest_address: 0.00080000,
+ get_change_address(rbf_node): Decimal("0.00010000")})
+ fulltx = rbf_node.getrawtransaction(rbfid, 1)
+ bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 19900})
+ full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1)
+ assert_equal(bumped_tx["fee"], Decimal("0.00020000"))
+ assert_equal(len(fulltx["vout"]), 2)
+ assert_equal(len(full_bumped_tx["vout"]), 1) #change output is eliminated
+
+
+def test_settxfee(rbf_node, dest_address):
+ # check that bumpfee reacts correctly to the use of settxfee (paytxfee)
+ # increase feerate by 2.5x, test that fee increased at least 2x
+ rbf_node.settxfee(Decimal("0.00001000"))
+ rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
+ rbftx = rbf_node.gettransaction(rbfid)
+ rbf_node.settxfee(Decimal("0.00002500"))
+ bumped_tx = rbf_node.bumpfee(rbfid)
+ assert bumped_tx["fee"] > 2 * abs(rbftx["fee"])
+ rbf_node.settxfee(Decimal("0.00000000")) # unset paytxfee
+
+
+def test_rebumping(rbf_node, dest_address):
+ # check that re-bumping the original tx fails, but bumping the bumper succeeds
+ rbf_node.settxfee(Decimal("0.00001000"))
+ rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
+ bumped = rbf_node.bumpfee(rbfid, {"totalFee": 1000})
+ assert_raises_message(JSONRPCException, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 2000})
+ rbf_node.bumpfee(bumped["txid"], {"totalFee": 2000})
+
+
+def test_rebumping_not_replaceable(rbf_node, dest_address):
+ # check that re-bumping a non-replaceable bump tx fails
+ rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
+ bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False})
+ assert_raises_message(JSONRPCException, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
+ {"totalFee": 20000})
+
+
+def test_unconfirmed_not_spendable(rbf_node, rbf_node_address):
+ # check that unconfirmed outputs from bumped transactions are not spendable
+ rbfid = create_fund_sign_send(rbf_node, {rbf_node_address: 0.00090000})
+ rbftx = rbf_node.gettransaction(rbfid)["hex"]
+ assert rbfid in rbf_node.getrawmempool()
+ bumpid = rbf_node.bumpfee(rbfid)["txid"]
+ assert bumpid in rbf_node.getrawmempool()
+ assert rbfid not in rbf_node.getrawmempool()
+
+ # check that outputs from the bump transaction are not spendable
+ # due to the replaces_txid check in CWallet::AvailableCoins
+ assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == bumpid], [])
+
+ # submit a block with the rbf tx to clear the bump tx out of the mempool,
+ # then call abandon to make sure the wallet doesn't attempt to resubmit the
+ # bump tx, then invalidate the block so the rbf tx will be put back in the
+ # mempool. this makes it possible to check whether the rbf tx outputs are
+ # spendable before the rbf tx is confirmed.
+ block = submit_block_with_tx(rbf_node, rbftx)
+ rbf_node.abandontransaction(bumpid)
+ rbf_node.invalidateblock(block.hash)
+ assert bumpid not in rbf_node.getrawmempool()
+ assert rbfid in rbf_node.getrawmempool()
+
+ # check that outputs from the rbf tx are not spendable before the
+ # transaction is confirmed, due to the replaced_by_txid check in
+ # CWallet::AvailableCoins
+ assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == rbfid], [])
+
+ # check that the main output from the rbf tx is spendable after confirmed
+ rbf_node.generate(1)
+ assert_equal(
+ sum(1 for t in rbf_node.listunspent(minconf=0, include_unsafe=False)
+ if t["txid"] == rbfid and t["address"] == rbf_node_address and t["spendable"]), 1)
+
+
+def test_locked_wallet_fails(rbf_node, dest_address):
+ rbfid = create_fund_sign_send(rbf_node, {dest_address: 0.00090000})
+ rbf_node.walletlock()
+ assert_raises_message(JSONRPCException, "Please enter the wallet passphrase with walletpassphrase first.",
+ rbf_node.bumpfee, rbfid)
+
+
+def create_fund_sign_send(node, outputs):
+ rawtx = node.createrawtransaction([], outputs)
+ fundtx = node.fundrawtransaction(rawtx)
+ signedtx = node.signrawtransaction(fundtx["hex"])
+ txid = node.sendrawtransaction(signedtx["hex"])
+ return txid
+
+
+def spend_one_input(node, input_amount, outputs):
+ input = dict(sequence=BIP125_SEQUENCE_NUMBER, **next(u for u in node.listunspent() if u["amount"] == input_amount))
+ rawtx = node.createrawtransaction([input], outputs)
+ signedtx = node.signrawtransaction(rawtx)
+ txid = node.sendrawtransaction(signedtx["hex"])
+ return txid
+
+
+def get_change_address(node):
+ """Get a wallet change address.
+
+ There is no wallet RPC to access unused change addresses, so this creates a
+ dummy transaction, calls fundrawtransaction to give add an input and change
+ output, then returns the change address."""
+ dest_address = node.getnewaddress()
+ dest_amount = Decimal("0.00012345")
+ rawtx = node.createrawtransaction([], {dest_address: dest_amount})
+ fundtx = node.fundrawtransaction(rawtx)
+ info = node.decoderawtransaction(fundtx["hex"])
+ return next(address for out in info["vout"]
+ if out["value"] != dest_amount for address in out["scriptPubKey"]["addresses"])
+
+
+def submit_block_with_tx(node, tx):
+ ctx = CTransaction()
+ ctx.deserialize(io.BytesIO(hex_str_to_bytes(tx)))
+
+ tip = node.getbestblockhash()
+ height = node.getblockcount() + 1
+ block_time = node.getblockheader(tip)["mediantime"] + 1
+ block = blocktools.create_block(int(tip, 16), blocktools.create_coinbase(height), block_time)
+ block.vtx.append(ctx)
+ block.rehash()
+ block.hashMerkleRoot = block.calc_merkle_root()
+ block.solve()
+ error = node.submitblock(bytes_to_hex_str(block.serialize(True)))
+ if error is not None:
+ raise Exception(error)
+ return block
+
+
+if __name__ == "__main__":
+ BumpFeeTest().main()
diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py
index b97e9aecdf..7396ba46a4 100755
--- a/qa/rpc-tests/fundrawtransaction.py
+++ b/qa/rpc-tests/fundrawtransaction.py
@@ -226,7 +226,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert(False)
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0})
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
- out = dec_tx['vout'][0];
+ out = dec_tx['vout'][0]
assert_equal(change, out['scriptPubKey']['addresses'][0])
@@ -651,7 +651,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(len(self.nodes[3].listunspent(1)), 1)
inputs = []
- outputs = {self.nodes[2].getnewaddress() : 1}
+ outputs = {self.nodes[3].getnewaddress() : 1}
rawtx = self.nodes[3].createrawtransaction(inputs, outputs)
result = self.nodes[3].fundrawtransaction(rawtx) # uses min_relay_tx_fee (set by settxfee)
result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2*min_relay_tx_fee})
@@ -660,6 +660,32 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
+ #############################
+ # Test address reuse option #
+ #############################
+
+ result3 = self.nodes[3].fundrawtransaction(rawtx, {"reserveChangeKey": False})
+ res_dec = self.nodes[0].decoderawtransaction(result3["hex"])
+ changeaddress = ""
+ for out in res_dec['vout']:
+ if out['value'] > 1.0:
+ changeaddress += out['scriptPubKey']['addresses'][0]
+ assert(changeaddress != "")
+ nextaddr = self.nodes[3].getnewaddress()
+ # frt should not have removed the key from the keypool
+ assert(changeaddress == nextaddr)
+
+ result3 = self.nodes[3].fundrawtransaction(rawtx)
+ res_dec = self.nodes[0].decoderawtransaction(result3["hex"])
+ changeaddress = ""
+ for out in res_dec['vout']:
+ if out['value'] > 1.0:
+ changeaddress += out['scriptPubKey']['addresses'][0]
+ assert(changeaddress != "")
+ nextaddr = self.nodes[3].getnewaddress()
+ # Now the change address key should be removed from the keypool
+ assert(changeaddress != nextaddr)
+
######################################
# Test subtractFeeFromOutputs option #
######################################
diff --git a/qa/rpc-tests/importmulti.py b/qa/rpc-tests/importmulti.py
index 5c536f2f49..e100a3af9d 100755
--- a/qa/rpc-tests/importmulti.py
+++ b/qa/rpc-tests/importmulti.py
@@ -108,7 +108,7 @@ class ImportMultiTest (BitcoinTestFramework):
"scriptPubKey": address['scriptPubKey'],
"pubkeys": [ address['pubkey'] ],
"internal": True
- }];
+ }]
result = self.nodes[1].importmulti(request)
assert_equal(result[0]['success'], True)
address_assert = self.nodes[1].validateaddress(address['address'])
@@ -121,7 +121,7 @@ class ImportMultiTest (BitcoinTestFramework):
request = [{
"scriptPubKey": address['scriptPubKey'],
"pubkeys": [ address['pubkey'] ]
- }];
+ }]
result = self.nodes[1].importmulti(request)
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -8)
@@ -197,7 +197,7 @@ class ImportMultiTest (BitcoinTestFramework):
self.nodes[1].generate(100)
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
- transaction = self.nodes[1].gettransaction(transactionid);
+ transaction = self.nodes[1].gettransaction(transactionid)
print("Should import a p2sh")
result = self.nodes[1].importmulti([{
@@ -222,7 +222,7 @@ class ImportMultiTest (BitcoinTestFramework):
self.nodes[1].generate(100)
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
- transaction = self.nodes[1].gettransaction(transactionid);
+ transaction = self.nodes[1].gettransaction(transactionid)
print("Should import a p2sh with respective redeem script")
result = self.nodes[1].importmulti([{
@@ -246,7 +246,7 @@ class ImportMultiTest (BitcoinTestFramework):
self.nodes[1].generate(100)
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
- transaction = self.nodes[1].gettransaction(transactionid);
+ transaction = self.nodes[1].gettransaction(transactionid)
print("Should import a p2sh with respective redeem script and private keys")
result = self.nodes[1].importmulti([{
@@ -270,7 +270,7 @@ class ImportMultiTest (BitcoinTestFramework):
self.nodes[1].generate(100)
transactionid = self.nodes[1].sendtoaddress(multi_sig_script['address'], 10.00)
self.nodes[1].generate(1)
- transaction = self.nodes[1].gettransaction(transactionid);
+ transaction = self.nodes[1].gettransaction(transactionid)
print("Should import a p2sh with respective redeem script and private keys")
result = self.nodes[1].importmulti([{
@@ -312,7 +312,7 @@ class ImportMultiTest (BitcoinTestFramework):
"scriptPubKey": address['scriptPubKey'],
"pubkeys": [ address2['pubkey'] ],
"internal": True
- }];
+ }]
result = self.nodes[1].importmulti(request)
assert_equal(result[0]['success'], False)
assert_equal(result[0]['error']['code'], -5)
diff --git a/qa/rpc-tests/listsinceblock.py b/qa/rpc-tests/listsinceblock.py
new file mode 100755
index 0000000000..ca67b8eceb
--- /dev/null
+++ b/qa/rpc-tests/listsinceblock.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+class ListSinceBlockTest (BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 4
+
+ def run_test (self):
+ '''
+ `listsinceblock` did not behave correctly when handed a block that was
+ no longer in the main chain:
+
+ ab0
+ / \
+ aa1 [tx0] bb1
+ | |
+ aa2 bb2
+ | |
+ aa3 bb3
+ |
+ bb4
+
+ Consider a client that has only seen block `aa3` above. It asks the node
+ to `listsinceblock aa3`. But at some point prior the main chain switched
+ to the bb chain.
+
+ Previously: listsinceblock would find height=4 for block aa3 and compare
+ this to height=5 for the tip of the chain (bb4). It would then return
+ results restricted to bb3-bb4.
+
+ Now: listsinceblock finds the fork at ab0 and returns results in the
+ range bb1-bb4.
+
+ This test only checks that [tx0] is present.
+ '''
+
+ assert_equal(self.is_network_split, False)
+ self.nodes[2].generate(101)
+ self.sync_all()
+
+ assert_equal(self.nodes[0].getbalance(), 0)
+ assert_equal(self.nodes[1].getbalance(), 0)
+ assert_equal(self.nodes[2].getbalance(), 50)
+ assert_equal(self.nodes[3].getbalance(), 0)
+
+ # Split network into two
+ self.split_network()
+ assert_equal(self.is_network_split, True)
+
+ # send to nodes[0] from nodes[2]
+ senttx = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+
+ # generate on both sides
+ lastblockhash = self.nodes[1].generate(6)[5]
+ self.nodes[2].generate(7)
+ print('lastblockhash=%s' % (lastblockhash))
+
+ self.sync_all()
+
+ self.join_network()
+
+ # listsinceblock(lastblockhash) should now include tx, as seen from nodes[0]
+ lsbres = self.nodes[0].listsinceblock(lastblockhash)
+ found = False
+ for tx in lsbres['transactions']:
+ if tx['txid'] == senttx:
+ found = True
+ break
+ assert_equal(found, True)
+
+if __name__ == '__main__':
+ ListSinceBlockTest().main()
diff --git a/qa/rpc-tests/p2p-feefilter.py b/qa/rpc-tests/p2p-feefilter.py
index 96d99d38a7..86ce0b42e6 100755
--- a/qa/rpc-tests/p2p-feefilter.py
+++ b/qa/rpc-tests/p2p-feefilter.py
@@ -21,9 +21,9 @@ def allInvsMatch(invsExpected, testnode):
for x in range(60):
with mininode_lock:
if (sorted(invsExpected) == sorted(testnode.txinvs)):
- return True;
+ return True
time.sleep(1)
- return False;
+ return False
# TestNode: bare-bones "peer". Used to track which invs are received from a node
# and to send the node feefilter messages.
diff --git a/qa/rpc-tests/p2p-segwit.py b/qa/rpc-tests/p2p-segwit.py
index 51adec5cae..a7858ad3d8 100755
--- a/qa/rpc-tests/p2p-segwit.py
+++ b/qa/rpc-tests/p2p-segwit.py
@@ -1662,7 +1662,7 @@ class SegWitTest(BitcoinTestFramework):
# too many sigops (contributing to legacy sigop count).
checksig_count = (extra_sigops_available // 4) + 1
scriptPubKey_checksigs = CScript([OP_CHECKSIG]*checksig_count)
- tx2.vout.append(CTxOut(0, scriptPubKey_checksigs));
+ tx2.vout.append(CTxOut(0, scriptPubKey_checksigs))
tx2.vin.pop()
tx2.wit.vtxinwit.pop()
tx2.vout[0].nValue -= tx.vout[-2].nValue
diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py
index 05e72e6078..60a1a86fa8 100755
--- a/qa/rpc-tests/pruning.py
+++ b/qa/rpc-tests/pruning.py
@@ -331,7 +331,7 @@ class PruneTest(BitcoinTestFramework):
print ("Syncing node 5 to test wallet")
connect_nodes(self.nodes[0], 5)
nds = [self.nodes[0], self.nodes[5]]
- sync_blocks(nds)
+ sync_blocks(nds, wait=5, timeout=300)
try:
stop_node(self.nodes[5],5) #stop and start to trigger rescan
start_node(5, self.options.tmpdir, ["-debug=1","-prune=550"])
diff --git a/qa/rpc-tests/segwit.py b/qa/rpc-tests/segwit.py
index be6fae5088..299f5387e7 100755
--- a/qa/rpc-tests/segwit.py
+++ b/qa/rpc-tests/segwit.py
@@ -39,7 +39,7 @@ def addlength(script):
return scriptlen + script
def create_witnessprogram(version, node, utxo, pubkey, encode_p2sh, amount):
- pkscript = witness_script(version, pubkey);
+ pkscript = witness_script(version, pubkey)
if (encode_p2sh):
p2sh_hash = bytes_to_hex_str(ripemd160(sha256(hex_str_to_bytes(pkscript))))
pkscript = "a914"+p2sh_hash+"87"
diff --git a/src/clientversion.h b/src/clientversion.h
index 0cd7e517ee..0b27bb1bdf 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -26,7 +26,7 @@
* Copyright year (2009-this)
* Todo: update this when changing our copyright comments in the source
*/
-#define COPYRIGHT_YEAR 2016
+#define COPYRIGHT_YEAR 2017
#endif //HAVE_CONFIG_H
diff --git a/src/net.cpp b/src/net.cpp
index 97480df131..1563a0963f 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -1147,12 +1147,10 @@ void CConnman::ThreadSocketHandler()
// * Hand off all complete messages to the processor, to be handled without
// blocking here.
{
- TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend) {
- if (!pnode->vSendMsg.empty()) {
- FD_SET(pnode->hSocket, &fdsetSend);
- continue;
- }
+ LOCK(pnode->cs_vSend);
+ if (!pnode->vSendMsg.empty()) {
+ FD_SET(pnode->hSocket, &fdsetSend);
+ continue;
}
}
{
@@ -1272,12 +1270,10 @@ void CConnman::ThreadSocketHandler()
continue;
if (FD_ISSET(pnode->hSocket, &fdsetSend))
{
- TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend) {
- size_t nBytes = SocketSendData(pnode);
- if (nBytes) {
- RecordBytesSent(nBytes);
- }
+ LOCK(pnode->cs_vSend);
+ size_t nBytes = SocketSendData(pnode);
+ if (nBytes) {
+ RecordBytesSent(nBytes);
}
}
@@ -1875,9 +1871,8 @@ void CConnman::ThreadMessageHandler()
// Send messages
{
- TRY_LOCK(pnode->cs_vSend, lockSend);
- if (lockSend)
- GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc);
+ LOCK(pnode->cs_sendProcessing);
+ GetNodeSignals().SendMessages(pnode, *this, flagInterruptMsgProc);
}
if (flagInterruptMsgProc)
return;
diff --git a/src/net.h b/src/net.h
index a9da38146b..505962f51a 100644
--- a/src/net.h
+++ b/src/net.h
@@ -618,6 +618,8 @@ public:
std::list<CNetMessage> vProcessMsg;
size_t nProcessQueueSize;
+ CCriticalSection cs_sendProcessing;
+
std::deque<CInv> vRecvGetData;
uint64_t nRecvBytes;
std::atomic<int> nRecvVersion;
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index a3cb376bcf..f86b09644b 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -31,6 +31,7 @@
#include "macdockiconhandler.h"
#endif
+#include "chainparams.h"
#include "init.h"
#include "ui_interface.h"
#include "util.h"
@@ -748,6 +749,15 @@ void BitcoinGUI::setNetworkActive(bool networkActive)
updateNetworkState();
}
+void BitcoinGUI::updateHeadersSyncProgressLabel()
+{
+ int64_t headersTipTime = clientModel->getHeaderTipTime();
+ int headersTipHeight = clientModel->getHeaderTipHeight();
+ int estHeadersLeft = (GetTime() - headersTipTime) / Params().GetConsensus().nPowTargetSpacing;
+ if (estHeadersLeft > HEADER_HEIGHT_DELTA_SYNC)
+ progressBarLabel->setText(tr("Syncing Headers (%1%)...").arg(QString::number(100.0 / (headersTipHeight+estHeadersLeft)*headersTipHeight, 'f', 1)));
+}
+
void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header)
{
if (modalOverlay)
@@ -768,9 +778,11 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
switch (blockSource) {
case BLOCK_SOURCE_NETWORK:
if (header) {
+ updateHeadersSyncProgressLabel();
return;
}
progressBarLabel->setText(tr("Synchronizing with network..."));
+ updateHeadersSyncProgressLabel();
break;
case BLOCK_SOURCE_DISK:
if (header) {
@@ -786,8 +798,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
if (header) {
return;
}
- // Case: not Importing, not Reindexing and no network connection
- progressBarLabel->setText(tr("No block source available..."));
+ progressBarLabel->setText(tr("Connecting to peers..."));
break;
}
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index c8b6ce5474..62d419d3ef 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -149,6 +149,8 @@ private:
/** Update UI with latest network info from model. */
void updateNetworkState();
+ void updateHeadersSyncProgressLabel();
+
Q_SIGNALS:
/** Signal raised when a URI was entered or dragged to the GUI */
void receivedURI(const QString &uri);
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index 64bc7dac03..a1e5cccc0b 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -78,6 +78,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Execute command when the best block changes (%s in cmd is replaced by block "
"hash)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Extra transactions to keep in memory for compact block reconstructions "
+"(default: %u)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Fees (in %s/kB) smaller than this are considered zero fee for relaying, "
"mining and transaction creation (default: %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -95,6 +98,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"If paytxfee is not set, include enough fee so transactions begin "
"confirmation on average within n blocks (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"If this block is in the chain assume that it and its ancestors are valid and "
+"potentially skip their script verification (0 to verify all, default: %s, "
+"testnet: %s)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay "
"fee of %s to prevent stuck transactions)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index c01c1a84cf..2c10e633b8 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -66,7 +66,7 @@ public:
//! Return true if core is doing initial block download
bool inInitialBlockDownload() const;
- //! Return true if core is importing blocks
+ //! Returns enum BlockSource of the current importing/syncing state
enum BlockSource getBlockSource() const;
//! Return true if network activity in core is enabled
bool getNetworkActive() const;
diff --git a/src/qt/locale/bitcoin_af_ZA.ts b/src/qt/locale/bitcoin_af_ZA.ts
index 1db5008384..1679482c77 100644
--- a/src/qt/locale/bitcoin_af_ZA.ts
+++ b/src/qt/locale/bitcoin_af_ZA.ts
@@ -10,9 +10,21 @@
<translation>Maak 'n kopie van die huidige adres na die stelsel klipbord</translation>
</message>
<message>
+ <source>&amp;Copy</source>
+ <translation>&amp;Kopie</translation>
+ </message>
+ <message>
+ <source>Delete the currently selected address from the list</source>
+ <translation>Verwyder die huidiglik gekieste address van die lys</translation>
+ </message>
+ <message>
<source>&amp;Delete</source>
<translation>&amp;Verwyder</translation>
</message>
+ <message>
+ <source>Choose the address to send coins to</source>
+ <translation>Kies die address na wie die muntstukke gestuur moet word</translation>
+ </message>
</context>
<context>
<name>AddressTableModel</name>
@@ -411,6 +423,14 @@
<translation>Kopieer bedrag</translation>
</message>
<message>
+ <source>%1 to %2</source>
+ <translation>%1 tot %2</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>of</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(geen etiket)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts
index c09d857632..fd5a197c3e 100644
--- a/src/qt/locale/bitcoin_ca.ts
+++ b/src/qt/locale/bitcoin_ca.ts
@@ -2822,10 +2822,6 @@
<translation>Poda: la darrera sincronització del moneder va més enllà de les dades podades. Cal que activeu -reindex (baixeu tota la cadena de blocs de nou en cas de node podat)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduïu els requisits d'emmagatzematge podant (suprimint) els blocs antics. Aquest mode és incompatible amb -txindex i -rescan. Avís: la reversió d'aquest paràmetre implica haver de tornar a baixar la cadena de blocs sencera. (per defecte: 0 = inhabilita la poda de blocs, &gt;%u = mida objectiu en MiB per utilitzar en els fitxers de blocs)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Els rescanejos no són possible en el mode de poda. Caldrà que utilitzeu -reindex, que tornarà a baixar la cadena de blocs sencera.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts
index 838190b10e..f88508a10f 100644
--- a/src/qt/locale/bitcoin_ca_ES.ts
+++ b/src/qt/locale/bitcoin_ca_ES.ts
@@ -2822,10 +2822,6 @@
<translation>Poda: la darrera sincronització del moneder va més enllà de les dades podades. Cal que activeu -reindex (baixeu tota la cadena de blocs de nou en cas de node podat)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduïu els requisits d'emmagatzematge podant (suprimint) els blocs antics. Aquest mode és incompatible amb -txindex i -rescan. Avís: la reversió d'aquest paràmetre implica haver de tornar a baixar la cadena de blocs sencera. (per defecte: 0 = inhabilita la poda de blocs, &gt;%u = mida objectiu en MiB per utilitzar en els fitxers de blocs)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Els rescanejos no són possible en el mode de poda. Caldrà que utilitzeu -reindex, que tornarà a baixar la cadena de blocs sencera.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts
index 3b5d7947f6..2e911af14c 100644
--- a/src/qt/locale/bitcoin_cs.ts
+++ b/src/qt/locale/bitcoin_cs.ts
@@ -3022,10 +3022,6 @@
<translation>Prořezávání: poslední synchronizace peněženky proběhla před už prořezanými daty. Je třeba provést -reindex (tedy v případě prořezávacího režimu stáhnout znovu celý řetězec bloků)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Omezit nároky na úložný prostor prořezáváním (mazáním) starých bloků. Tento režim není slučitelný s -txindex ani -rescan. Upozornění: opětovná změna tohoto nastavení bude vyžadovat nové stažení celého řetězce bloků. (výchozí: 0 = bloky neprořezávat, &gt;%u = cílová velikost souborů s bloky, v MiB)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>V prořezávacím režimu není možné přeskenovávat řetězec bloků. Musíš provést -reindex, což znovu stáhne celý řetězec bloků.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts
index 0b49b5aefc..75eb5ae94d 100644
--- a/src/qt/locale/bitcoin_da.ts
+++ b/src/qt/locale/bitcoin_da.ts
@@ -3030,10 +3030,6 @@
<translation>Beskæring: Seneste synkronisering rækker udover beskårne data. Du er nødt til at bruge -reindex (downloade hele blokkæden igen i fald af beskåret knude)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reducér lagringskravene ved at beskære (slette) gamle blokke. Denne tilstand er ikke kompatibel med -txindex og -rescan. Advarsel: Fortrydelse af denne indstilling kræver gendownload af hele blokkæden. (standard: 0 = deaktivér beskæring af blokke, &gt;%u = målstørrelse i MiB der skal bruges på blokfiler)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Genindlæsninger er ikke mulige i beskåret tilstand. Du er nødt til at bruge -reindex, hvilket vil downloade hele blokkæden igen.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts
index 1dfd77cf61..59a45e3175 100644
--- a/src/qt/locale/bitcoin_de.ts
+++ b/src/qt/locale/bitcoin_de.ts
@@ -3006,10 +3006,6 @@
<translation>Prune (Kürzung): Die letzte Syncronisation der Wallet liegt vor gekürzten (gelöschten) Blöcken. Es ist ein -reindex (download der gesamten Blockkette) notwendig.</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Speicherplatzanforderung durch kürzen (löschen) alter Blöcke reduzieren. Dieser Modus ist nicht mit -txindex und -rescan kompatibel. Warnung: Die Umkehr dieser Einstellung erfordert das erneute Herunterladen der gesamten Blockkette. (Standard: 0 = deaktiviert das Kürzen von Blöcken, &gt;%u = Zielgröße in MiB, die für Blockdateien verwendet werden darf)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Rescans sind im pruned mode nicht möglich. Ein -reindex ist notwendig, welcher die gesmate Blockkette erneut herunterlädt.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 60dcc9f701..dcfd86f366 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -304,12 +304,12 @@
<translation>Sign &amp;message...</translation>
</message>
<message>
- <location line="+417"/>
+ <location line="+427"/>
<source>Synchronizing with network...</source>
<translation>Synchronizing with network...</translation>
</message>
<message>
- <location line="-495"/>
+ <location line="-505"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@@ -419,12 +419,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+53"/>
+ <location line="+27"/>
+ <source>Syncing Headers (%1%)...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+37"/>
<source>Reindexing blocks on disk...</source>
<translation>Reindexing blocks on disk...</translation>
</message>
<message>
- <location line="-497"/>
+ <location line="-508"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -454,12 +459,12 @@
<translation>&amp;Verify message...</translation>
</message>
<message>
- <location line="+504"/>
+ <location line="+514"/>
<source>Bitcoin</source>
<translation>Bitcoin</translation>
</message>
<message>
- <location line="-729"/>
+ <location line="-739"/>
<source>Wallet</source>
<translation>Wallet</translation>
</message>
@@ -552,7 +557,7 @@
</translation>
</message>
<message>
- <location line="+49"/>
+ <location line="+60"/>
<source>Indexing blocks on disk...</source>
<translation type="unfinished"></translation>
</message>
@@ -561,13 +566,8 @@
<source>Processing blocks on disk...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <location line="+11"/>
- <source>No block source available...</source>
- <translation>No block source available...</translation>
- </message>
<message numerus="yes">
- <location line="+9"/>
+ <location line="+19"/>
<source>Processed %n block(s) of transaction history.</source>
<translation>
<numerusform>Processed %n block of transaction history.</numerusform>
@@ -610,7 +610,7 @@
<translation>Up to date</translation>
</message>
<message>
- <location line="-428"/>
+ <location line="-438"/>
<source>Show the %1 help message to get a list with possible Bitcoin command-line options</source>
<translation type="unfinished"></translation>
</message>
@@ -620,7 +620,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+255"/>
+ <location line="+227"/>
+ <source>Connecting to peers...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+38"/>
<source>Catching up...</source>
<translation>Catching up...</translation>
</message>
@@ -3862,7 +3867,7 @@
<context>
<name>bitcoin-core</name>
<message>
- <location filename="../bitcoinstrings.cpp" line="+311"/>
+ <location filename="../bitcoinstrings.cpp" line="+318"/>
<source>Options:</source>
<translation>Options:</translation>
</message>
@@ -3887,7 +3892,7 @@
<translation>Accept command line and JSON-RPC commands</translation>
</message>
<message>
- <location line="-214"/>
+ <location line="-221"/>
<source>Accept connections from outside (default: 1 if no -proxy or -connect/-noconnect)</source>
<translation type="unfinished"></translation>
</message>
@@ -3902,12 +3907,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+34"/>
+ <location line="+37"/>
<source>If &lt;category&gt; is not supplied or if &lt;category&gt; = 1, output all debugging information.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+32"/>
+ <location line="+36"/>
<source>Prune configured below the minimum of %d MiB. Please use a higher number.</source>
<translation type="unfinished"></translation>
</message>
@@ -3947,7 +3952,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-353"/>
+ <location line="-360"/>
<source>Bitcoin Core</source>
<translation type="unfinished">Bitcoin Core</translation>
</message>
@@ -3997,7 +4002,17 @@
<translation>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</translation>
</message>
<message>
- <location line="+29"/>
+ <location line="+6"/>
+ <source>Extra transactions to keep in memory for compact block reconstructions (default: %u)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+20"/>
+ <source>If this block is in the chain assume that it and its ancestors are valid and potentially skip their script verification (0 to verify all, default: %s, testnet: %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
<source>Maximum allowed median peer time offset adjustment. Local perspective of time may be influenced by peers forward or backward by this amount. (default: %u seconds)</source>
<translation type="unfinished"></translation>
</message>
@@ -4402,7 +4417,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-351"/>
+ <location line="-358"/>
<source>Allow JSON-RPC connections from specified source. Valid for &lt;ip&gt; are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times</source>
<translation type="unfinished"></translation>
</message>
@@ -4437,7 +4452,7 @@
<translation>Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)</translation>
</message>
<message>
- <location line="+9"/>
+ <location line="+12"/>
<source>Fees (in %s/kB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4447,7 +4462,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+7"/>
<source>Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
<translation type="unfinished"></translation>
</message>
@@ -4667,12 +4682,12 @@
<translation>Password for JSON-RPC connections</translation>
</message>
<message>
- <location line="-235"/>
+ <location line="-242"/>
<source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source>
<translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation>
</message>
<message>
- <location line="+163"/>
+ <location line="+170"/>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
@@ -4682,7 +4697,7 @@
<translation>Loading addresses...</translation>
</message>
<message>
- <location line="-284"/>
+ <location line="-291"/>
<source>(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source>
<translation type="unfinished"></translation>
</message>
@@ -4702,7 +4717,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+21"/>
+ <location line="+24"/>
<source>Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -4717,7 +4732,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+11"/>
+ <location line="+15"/>
<source>Maintain a full transaction index, used by the getrawtransaction rpc call (default: %u)</source>
<translation type="unfinished"></translation>
</message>
diff --git a/src/qt/locale/bitcoin_en_GB.ts b/src/qt/locale/bitcoin_en_GB.ts
index 1676f67979..df3aad5087 100644
--- a/src/qt/locale/bitcoin_en_GB.ts
+++ b/src/qt/locale/bitcoin_en_GB.ts
@@ -1874,10 +1874,6 @@
<translation>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts
index 5ba44a954c..b1e35148d7 100644
--- a/src/qt/locale/bitcoin_es.ts
+++ b/src/qt/locale/bitcoin_es.ts
@@ -1705,6 +1705,10 @@
<translation>Prohibir para</translation>
</message>
<message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Unbano</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Bienvenido a la consola RPC %1.</translation>
</message>
@@ -1717,6 +1721,14 @@
<translation>Escriba &lt;b&gt;help&lt;/b&gt; para ver un resumen de los comandos disponibles.</translation>
</message>
<message>
+ <source>WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.</source>
+ <translation>ADVERTENCIA: Los estafadores han sido activados, diciéndoles a los usuarios que escriban comandos aquí, robando el contenido de sus monederos. No utilice esta consola sin entender completamente la repercusión de un comando.</translation>
+ </message>
+ <message>
+ <source>Network activity disabled</source>
+ <translation>Actividad de red deshabilitada</translation>
+ </message>
+ <message>
<source>%1 B</source>
<translation>%1 B</translation>
</message>
@@ -1836,6 +1848,10 @@
<translation>Eliminar</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>Copiar URI</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>Copiar capa</translation>
</message>
@@ -2061,6 +2077,10 @@
<translation>Polvo:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Objetivo de tiempo de confirmación</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Vaciar &amp;todo</translation>
</message>
@@ -2153,6 +2173,10 @@
<translation>¡Falló la creación de transacción!</translation>
</message>
<message>
+ <source>The transaction was rejected with the following reason: %1</source>
+ <translation>Se ha rechazado la transacción por la siguiente razón: %1</translation>
+ </message>
+ <message>
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation>Una comisión mayor que %1 se considera una cuota irracionalmente alta.</translation>
</message>
@@ -2160,10 +2184,18 @@
<source>Payment request expired.</source>
<translation>Solicitud de pago caducada.</translation>
</message>
+ <message numerus="yes">
+ <source>%n block(s)</source>
+ <translation><numerusform>%n bloque</numerusform><numerusform>%n bloques</numerusform></translation>
+ </message>
<message>
<source>Pay only the required fee of %1</source>
<translation>Pagar únicamente la comisión solicitada de %1</translation>
</message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Estimado para empezar la confirmación dentro de %n bloque.</numerusform><numerusform>Estimado para empezar la confirmación dentro de %n bloques.</numerusform></translation>
+ </message>
<message>
<source>Warning: Invalid Bitcoin address</source>
<translation>Alerta: dirección Bitcoin inválida</translation>
@@ -2173,6 +2205,14 @@
<translation>Alerta: dirección cambiada desconocida</translation>
</message>
<message>
+ <source>Confirm custom change address</source>
+ <translation>Confirmar dirección de cambio personalizada</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>La dirección que ha seleccionado para cambiar no es parte de este monedero. ninguno o todos los fondos de su monedero pueden ser enviados a esta dirección. ¿Está seguro?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(sin etiqueta)</translation>
</message>
@@ -2960,10 +3000,6 @@
<translation>Poda: la ultima sincronizacion del monedero sobrepasa los datos podados. Necesitas reindexar con -reindex (o descargar la cadena de bloques de nuevo en el caso de un nodo podado)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduce los requisitos de almacenaje podando (eliminando) los bloques viejos. Este modo es incompatible con -txindex y -rescan. Advertencia: Revertir este ajuste requiere volver a descargar la cadena de bloques al completo. (predeterminado: 0 = deshabilitar la poda de bloques, &gt;%u = objetivo de tamaño en MiB para usar para los archivos de bloques)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Nos es posible re-escanear en modo podado.Necesitas utilizar -reindex el cual descargara la cadena de bloques al completo de nuevo.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_es_ES.ts b/src/qt/locale/bitcoin_es_ES.ts
index c971d664d8..996b209ea2 100644
--- a/src/qt/locale/bitcoin_es_ES.ts
+++ b/src/qt/locale/bitcoin_es_ES.ts
@@ -2840,10 +2840,6 @@
<translation>Poda: la ultima sincronizacion de la cartera sobrepasa los datos podados. Necesitas reindexar con -reindex (o descargar la cadena de bloques de nuevo en el caso de un nodo podado)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduce los requisitos de almacenaje podando (eliminando) los bloques viejos. Este modo es incompatible con -txindex y -rescan. Advertencia: Revertir este ajuste requiere volver a descargar la cadena de bloques al completo. (predeterminado: 0 = deshabilitar la poda de bloques, &gt;%u = objetivo de tamaño en MiB para usar para los archivos de bloques)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Nos es posible re-escanear en modo podado.Necesitas utilizar -reindex el cual descargara la cadena de bloques al completo de nuevo.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts
index db643e73d2..ba8880c4aa 100644
--- a/src/qt/locale/bitcoin_fi.ts
+++ b/src/qt/locale/bitcoin_fi.ts
@@ -1758,10 +1758,6 @@
<translation>Karsinta: viime lompakon synkronisointi menee karsitun datan taakse. Sinun tarvitsee ajaa -reindex (lataa koko lohkoketju uudelleen tapauksessa jossa karsiva noodi)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Vähennä levytilan tarvetta karsimalla (poistamalla) vanhoja lohkoja. Tämä tila ei ole yhteensopiva -txindex ja -rescan -parametrien kanssa. Varoitus: Tämän asetuksen peruutus vaatii koko lohkoketjun uudelleenlataamisen. (oletus: 0 = poista karsinta käytöstä, &gt;%u = kohdekoko muodossa MiB jota käytetään lohkotiedostoille) </translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Uudelleenskannaukset eivät ole mahdollisia karsivassa tilassa. Sinun täytyy käyttää -reindex joka lataa koko lohkoketjun uudelleen.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts
index eef88b43a3..23b4d2a66f 100644
--- a/src/qt/locale/bitcoin_fr.ts
+++ b/src/qt/locale/bitcoin_fr.ts
@@ -1998,11 +1998,11 @@
</message>
<message>
<source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
- <translation>Si cette option est activée, et l'adresse de monnaie rendue est vide ou invalide, la monnaie sera envoyée vers une adresse nouvellement générée.</translation>
+ <translation>Si cette option est activée et l'adresse de monnaie est vide ou invalide, la monnaie sera envoyée vers une adresse nouvellement générée.</translation>
</message>
<message>
<source>Custom change address</source>
- <translation>Adresse personnalisée de monnaie rendue</translation>
+ <translation>Adresse personnalisée de monnaie</translation>
</message>
<message>
<source>Transaction Fee:</source>
@@ -2202,7 +2202,15 @@
</message>
<message>
<source>Warning: Unknown change address</source>
- <translation>Avertissement : adresse de monnaie rendue inconnue</translation>
+ <translation>Avertissement : adresse de monnaie inconnue</translation>
+ </message>
+ <message>
+ <source>Confirm custom change address</source>
+ <translation>Confimer l'adresse personnalisée de monnaie</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>L'adresse que vous avez sélectionnée pour la monnaie ne fait pas partie de ce porte-monnaie. Les fonds de ce porte-monnaie peuvent en partie ou en totalité être envoyés vers cette adresse. Êtes-vous certain ?</translation>
</message>
<message>
<source>(no label)</source>
@@ -2307,7 +2315,7 @@
</message>
<message>
<source>Do not shut down the computer until this window disappears.</source>
- <translation>Ne pas fermer l'ordinateur jusqu'à la disparition de cette fenêtre.</translation>
+ <translation>Ne pas éteindre l'ordinateur jusqu'à la disparition de cette fenêtre.</translation>
</message>
</context>
<context>
@@ -3022,10 +3030,6 @@
<translation>Élagage : la dernière synchronisation de porte-monnaie va par-delà les données élaguées. Vous devez -reindex (réindexer, télécharger de nouveau toute la chaîne de blocs en cas de nœud élagué)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Réduire les exigences de stockage en élaguant (supprimant) les anciens blocs. Ce mode est incompatible avec -txindex et -rescan. Avertissement : ramener ce paramètre à sa valeur antérieure exige un nouveau téléchargement de la chaîne de blocs en entier (par défaut : 0 = désactiver l'élagage des blocs, &gt;%u = taille cible en Mio à utiliser pour les fichiers de blocs).</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Les rebalayages sont impossibles en mode élagage. Vous devrez utiliser -reindex, ce qui téléchargera de nouveau la chaîne de blocs en entier.</translation>
</message>
@@ -3106,6 +3110,14 @@
<translation>Si vous trouvez %s utile, vous pouvez y contribuer. Vous trouverez davantage d'informations à propos du logiciel sur %s.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Réduire les exigences de stockage en activant l'élagage (suppression) des anciens blocs. Cela permet d'appeler le RPC « pruneblockchain » pour supprimer des blocs précis et active l'élagage automatique des anciens blocs si une taille cible en Mio est fournie. Ce mode n'est pas compatible avec -txindex et -rescan. Avertissement : ramener ce paramètre à sa valeur antérieure exige de retélécharger l'intégralité de la chaîne de blocs (par défaut : 0 = désactiver l'élagage des blocs, 1 = permettre l'élagage manuel par RPC, &gt;%u = élaguer automatiquement les fichiers de blocs pour rester en deçà de la taille cible précisée en Mio).</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Définir le taux minimal de frais (en %s/ko) pour les transactions à inclure dans la création de blocs (par défaut : %s)</translation>
+ </message>
+ <message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation>Définir le nombre de fils de vérification des scripts (%u à %d, 0 = auto, &lt; 0 = laisser ce nombre de cœurs inutilisés, par défaut : %d)</translation>
</message>
@@ -3126,6 +3138,10 @@
<translation>Utiliser l'UPnP pour mapper le port d'écoute (par défaut : 1 en écoute et sans -proxy)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>Nom d'utilisateur et mot de passe haché pour les connexions JSON-RPC. Le champ &lt;userpw&gt; est au format : &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Un script python canonique est inclus dans share/rpcuser. Le client se connecte ensuite normalement en utilisant la paire d'arguments rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt;. Cette option peut être spécifiée plusieurs fois.</translation>
+ </message>
+ <message>
<source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
<translation>Un porte-monnaie ne créera aucune transaction qui enfreint les limites de chaîne de la réserve de mémoire (par défaut : %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts
index 76cfdfafa5..1e359e52e5 100644
--- a/src/qt/locale/bitcoin_it.ts
+++ b/src/qt/locale/bitcoin_it.ts
@@ -1943,10 +1943,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Prune: l'ultima sincronizzazione del wallet risulta essere oltre la riduzione dei dati. È necessario eseguire un -reindex (scaricare nuovamente la blockchain in caso di nodo pruned)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Riduce i requisiti di spazio di archiviazione attraverso la rimozione dei vecchi blocchi (pruning). Questa modalità è incompatibile con l'opzione -txindex e -rescan. Attenzione: ripristinando questa opzione l'intera blockchain dovrà essere riscaricata. (default: 0 = disabilita il pruning, &gt;%u = dimensione desiderata in MiB per i file dei blocchi)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Non è possibile un Rescan in modalità pruned. Sarà necessario utilizzare -reindex che farà scaricare nuovamente tutta la blockchain.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts
index 3b56a76855..0f3c9e596a 100644
--- a/src/qt/locale/bitcoin_ja.ts
+++ b/src/qt/locale/bitcoin_ja.ts
@@ -2205,6 +2205,14 @@
<translation>警告:未知のおつりアドレスです</translation>
</message>
<message>
+ <source>Confirm custom change address</source>
+ <translation>カスタムおつりアドレスを確認</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>おつりとして指定されたアドレスはこのウォレットに属さないもののようです。このウォレットの一部またはすべての資産がこのアドレスへ送金されます。よろしいですか?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(ラベル無し)</translation>
</message>
@@ -3022,10 +3030,6 @@
<translation>剪定: 最後のウォレット同期ポイントは、選定されたデータよりも過去のものとなっています。-reindexをする必要があります (剪定されたノードの場合、ブロックチェイン全体をダウンロードします)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>古いブロックを剪定する (削除する) ことで記憶容量の必要量を削減する。このモードを有効にすると-txindexや-rescanと互換性がなくなります。警告: この設定の再有効化には全ブロックチェインの再ダウンロードが必要となります。(規定値: 0 = ブロックの剪定無効、&gt;%u = ブロックファイルに使用するMiB単位の目標サイズ)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>剪定モードでは再スキャンを行うことはできません。-reindexを指定し、ブロックチェイン全体を再ダウンロードする必要があります。</translation>
</message>
@@ -3106,6 +3110,14 @@
<translation>%s が有用だと感じられた方はぜひプロジェクトへの貢献をお願いします。ソフトウェアのより詳細な情報については %s をご覧ください。</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>古いブロックの剪定 (削除) を有効にすることでストレージの必要量を削減する。これにより pruneblockchain RPC を呼び出すことで指定されたブロックを削除することができます。またターゲットサイズが MiB 単位で指定された場合には古いブロックの自動剪定が有効となります。このモードは -txindex および -rescan オプションと互換性がありません。警告: この設定を最有効化するにはすべてのブロックチェーンの再ダウンロードが必要となります。(デフォルト: 0 = ブロックの剪定を無効化する, 1 = RPC 経由での手動剪定を許可する, &gt;%u = MiB 単位で指定されたターゲットサイズを常に下回るようにブロックファイルを自動的に剪定する)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>ブロック生成時に取り込まれるトランザクションの最低手数料率 (%s/kB 単位)。(デフォルト: %s)</translation>
+ </message>
+ <message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation>スクリプト検証スレッドを設定 (%uから%dの間, 0 = 自動, &lt;0 = たくさんのコアを自由にしておく, 初期値: %d)</translation>
</message>
@@ -3126,6 +3138,10 @@
<translation>リスン ポートの割当に UPnP を使用 (初期値: リスン中および-proxyが指定されていない場合は1)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>JSON-RPC 接続時のユーザ名とハッシュ化されたパスワード。&lt;userpw&gt; フィールドのフォーマットは &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;。標準的な Python スクリプトが share/rpcuser 内に含まれています。クライアントは通常の場合には rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; を利用して接続を行います。このオプションは複数回指定できます。</translation>
+ </message>
+ <message>
<source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
<translation>ウォレットがmempoolチェーン制限数を超えてトランザクションを作らないようにする (初期値: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts
index a80c6ccc45..b5af4602c8 100644
--- a/src/qt/locale/bitcoin_ko_KR.ts
+++ b/src/qt/locale/bitcoin_ko_KR.ts
@@ -2278,10 +2278,6 @@
<translation>블록 축소: 마지막 지갑 동기화 지점이 축소된 데이터보다 과거의 것 입니다. -reindex가 필요합니다 (정지된 노드의 경우 모든 블록체인을 재다운로드합니다)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>오래된 블록을 제거(축소)하여 디스크 용량을 줄입니다. 이 모드는 -txindex 와 -rescan 과 호환되지 않습니다. 경고: 이 모드를 취소하면 모든 블록체인을 다시 다운로드 받아야 합니다. (기본값:0 = 블록 축소 비활성화, &gt;%u = 블록파일에 사용할 용량을 MiB단위로 지정)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>블록 축소 모드에서는 재검색이 불가능 합니다. -reindex 명령을 사용해서 모든 블록체인을 다시 다운로드 해야 합니다.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts
index f98cdd32d2..1f76fdb0b3 100644
--- a/src/qt/locale/bitcoin_nb.ts
+++ b/src/qt/locale/bitcoin_nb.ts
@@ -1710,10 +1710,6 @@
<translation>Beskjæring: siste lommeboksynkronisering går utenfor beskjærte data. Du må bruke -reindex (laster ned hele blokkjeden igjen for beskjærte noder)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduser lagringsbehovet ved beskjæring (sletting) av gamle blokker. Denne modusen er ikke kompatibel med -txindex og -rescan. Advarsel: Tilbakestilling av denne innstillingen krever at hele blokkjeden må lastes ned på nytt. (Standardverdi: 0 = deaktiver beskjæring av blokker, &gt;%u = mål for størrelse i MiB å bruke for blokkfiler)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Omsøk er ikke mulig i beskjært modus. Du vil måtte bruke -reindex som vil laste nede hele blokkjeden på nytt.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts
index 8a09bed2ce..9094cd40a5 100644
--- a/src/qt/locale/bitcoin_nl.ts
+++ b/src/qt/locale/bitcoin_nl.ts
@@ -2838,10 +2838,6 @@
<translation>Snoei: laatste portemoneesynchronisatie gaat verder dan de gesnoeide data. U moet -reindex gebruiken (download opnieuw de gehele blokketen voor een weggesnoeide node)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Beperk benodigde opslag door snoeien (verwijderen) van oude blokken. Deze modus is niet-compatibele met -txindex en -rescan. Waarschuwing: Terugzetten van deze instellingen vereist opnieuw downloaden van gehele de blokketen. (standaard:0 = uitzetten snoeimodus, &gt;%u = doelgrootte in MiB voor blokbestanden)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Herscannen is niet mogelijk in de snoeimodus. U moet -reindex gebruiken dat de hele blokketen opnieuw zal downloaden.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts
index b7369c5093..ab6fb41870 100644
--- a/src/qt/locale/bitcoin_pl.ts
+++ b/src/qt/locale/bitcoin_pl.ts
@@ -1209,7 +1209,47 @@
<source>Cannot start bitcoin: click-to-pay handler</source>
<translation>Nie można uruchomić protokołu bitcoin: kliknij-by-zapłacić</translation>
</message>
- </context>
+ <message>
+ <source>URI handling</source>
+ <translation>Obsługa URI</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Żądanie płatności upłynęło.</translation>
+ </message>
+ <message>
+ <source>Payment request is not initialized.</source>
+ <translation>Żądanie płatności nie jest zainicjowane.</translation>
+ </message>
+ <message>
+ <source>Unverified payment requests to custom payment scripts are unsupported.</source>
+ <translation>Niezweryfikowane żądania płatności do własnych skryptów płatności są niewspierane.</translation>
+ </message>
+ <message>
+ <source>Invalid payment request.</source>
+ <translation>Nieprawidłowe żądanie płatności</translation>
+ </message>
+ <message>
+ <source>Refund from %1</source>
+ <translation>Zwrot z %1</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Żądanie płatności nie może zostać przetworzone.</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Błędna odpowiedź z serwera %1</translation>
+ </message>
+ <message>
+ <source>Network request error</source>
+ <translation>Błąd żądania sieci</translation>
+ </message>
+ <message>
+ <source>Payment acknowledged</source>
+ <translation>Płatność potwierdzona</translation>
+ </message>
+</context>
<context>
<name>PeerTableModel</name>
<message>
@@ -1220,7 +1260,15 @@
<source>Node/Service</source>
<translation>Węzeł/Usługi</translation>
</message>
- </context>
+ <message>
+ <source>NodeId</source>
+ <translation>Identyfikator węzła</translation>
+ </message>
+ <message>
+ <source>Ping</source>
+ <translation>Ping</translation>
+ </message>
+</context>
<context>
<name>QObject</name>
<message>
@@ -1259,6 +1307,14 @@
<source>%1 ms</source>
<translation>%1 ms</translation>
</message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation><numerusform>%n sekunda</numerusform><numerusform>%n sekund</numerusform><numerusform>%n sekund</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation><numerusform>%n minuta</numerusform><numerusform>%n minut</numerusform><numerusform>%n minut</numerusform></translation>
+ </message>
<message>
<source>%1 and %2</source>
<translation>%1 i %2</translation>
@@ -1266,10 +1322,30 @@
</context>
<context>
<name>QObject::QObject</name>
- </context>
+ <message>
+ <source>Error: %1</source>
+ <translation>Błąd: %1</translation>
+ </message>
+</context>
<context>
<name>QRImageWidget</name>
- </context>
+ <message>
+ <source>&amp;Save Image...</source>
+ <translation>&amp;Zapisz obraz...</translation>
+ </message>
+ <message>
+ <source>&amp;Copy Image</source>
+ <translation>&amp;Kopiuj obraz</translation>
+ </message>
+ <message>
+ <source>Save QR Code</source>
+ <translation>Zapisz Kod QR</translation>
+ </message>
+ <message>
+ <source>PNG Image (*.png)</source>
+ <translation>Obraz PNG (*.png)</translation>
+ </message>
+</context>
<context>
<name>RPCConsole</name>
<message>
@@ -1429,6 +1505,10 @@
<translation>Czas odpowiedzi</translation>
</message>
<message>
+ <source>Min Ping</source>
+ <translation>Minimalny czas odpowiedzi</translation>
+ </message>
+ <message>
<source>Time Offset</source>
<translation>Przesunięcie czasu</translation>
</message>
@@ -1489,6 +1569,18 @@
<translation>1 &amp;rok</translation>
</message>
<message>
+ <source>&amp;Disconnect</source>
+ <translation>&amp;Rozłącz</translation>
+ </message>
+ <message>
+ <source>Ban for</source>
+ <translation>Zbanuj na</translation>
+ </message>
+ <message>
+ <source>&amp;Unban</source>
+ <translation>&amp;Odblokuj</translation>
+ </message>
+ <message>
<source>Welcome to the %1 RPC console.</source>
<translation>Witaj w konsoli %1 RPC.</translation>
</message>
@@ -1620,10 +1712,18 @@
<translation>Usuń</translation>
</message>
<message>
+ <source>Copy URI</source>
+ <translation>Kopiuj URI:</translation>
+ </message>
+ <message>
<source>Copy label</source>
<translation>Kopiuj etykietę</translation>
</message>
<message>
+ <source>Copy message</source>
+ <translation>Kopiuj wiadomość</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>Kopiuj kwotę</translation>
</message>
@@ -1647,13 +1747,33 @@
<translation>&amp;Zapisz obraz...</translation>
</message>
<message>
+ <source>Request payment to %1</source>
+ <translation>Zażądaj płatności do %1</translation>
+ </message>
+ <message>
+ <source>Payment information</source>
+ <translation>Informacje o płatności</translation>
+ </message>
+ <message>
+ <source>URI</source>
+ <translation>URI</translation>
+ </message>
+ <message>
<source>Address</source>
<translation>Adres</translation>
</message>
<message>
+ <source>Amount</source>
+ <translation>Kwota</translation>
+ </message>
+ <message>
<source>Label</source>
<translation>Etykieta</translation>
</message>
+ <message>
+ <source>Message</source>
+ <translation>Wiadomość</translation>
+ </message>
</context>
<context>
<name>RecentRequestsTableModel</name>
@@ -1666,10 +1786,22 @@
<translation>Etykieta</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>Wiadomość</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(brak etykiety)</translation>
</message>
- </context>
+ <message>
+ <source>(no message)</source>
+ <translation>(brak wiadomości)</translation>
+ </message>
+ <message>
+ <source>Requested</source>
+ <translation>Zażądano</translation>
+ </message>
+</context>
<context>
<name>SendCoinsDialog</name>
<message>
@@ -1797,6 +1929,10 @@
<translation>Pył:</translation>
</message>
<message>
+ <source>Confirmation time target:</source>
+ <translation>Docelowy czas potwierdzenia:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>Wyczyść &amp;wszystko</translation>
</message>
@@ -1841,6 +1977,14 @@
<translation>Skopiuj resztę</translation>
</message>
<message>
+ <source>%1 to %2</source>
+ <translation>%1 do %2</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Żądanie płatności upłynęło.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(brak etykiety)</translation>
</message>
@@ -2078,6 +2222,14 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<source>label</source>
<translation>etykieta</translation>
</message>
+ <message>
+ <source>Message</source>
+ <translation>Wiadomość</translation>
+ </message>
+ <message>
+ <source>Amount</source>
+ <translation>Kwota</translation>
+ </message>
</context>
<context>
<name>TransactionDescDialog</name>
@@ -2251,10 +2403,6 @@ Zwróć uwagę, że poprawnie zweryfikowana wiadomość potwierdza to, że nadaw
<translation>Prune: ostatnia synchronizacja portfela jest za danymi. Muszisz -reindexować (pobrać cały ciąg bloków ponownie w przypadku przyciętego węzła)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Zredukuj wymaganą ilość miejsca na dysku poprzez usuwanie starych bloków. Ten tryb jest niekompatybilny z -txindex oraz -rescan. Ostrzeżenie: Wycofanie tego ustawienia wymaga ponownego pobrania całego łańcucha bloków. (domyślnie: 0 = wyłącz usuwanie bloków, &gt;%u = docelowy rozmiar w MiB jaki wykorzystać na pliki z blokami)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Ponowne skanowanie nie jest możliwe w trybie przycinania. Będzie trzeba użyć -reindex, co pobierze ponownie cały łańcuch bloków.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts
index 4d49399c11..e9ef5258f6 100644
--- a/src/qt/locale/bitcoin_pt_BR.ts
+++ b/src/qt/locale/bitcoin_pt_BR.ts
@@ -2201,6 +2201,10 @@
<translation>Confirmar endereço de troco personalizado</translation>
</message>
<message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>O endereço selecionado para o troco não pertence a esta carteira. Alguns ou todos os fundos da sua carteira modem ser mandados para esse endereço. Tem certeza?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(sem rótuo)</translation>
</message>
@@ -3018,10 +3022,6 @@
<translation>Prune: A ultima sincronização da carteira foi além do dado comprimido. Você precisa reindexar (fazer o download de toda a blockchain novamente)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduza o armazenamento de dados apagando os blocos mais antigos. Esse modo é incompatível com -txindex e -rescan. Cuidado: Reverter essa configuração requer um novo download de toda a blockchain. (Padrão: 0 = desabilitado, &gt;%u = tamanho em MiB para o uso de blocos cortados)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Rescans não são possíveis no modo prune. Você precisa usar -reindex, que irá fazer o download de toda a blockchain novamente.</translation>
</message>
@@ -3102,6 +3102,14 @@
<translation>Por favor contribua se você entender que %s é útil. Visite %s para mais informações sobre o software.</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>Reduz o requerimente de espaço habiitando o pruning (apagando) blocos antigos. Isso permite o chamar o comando pruneblockchain via RPC para apagar blocos específicos, e habiita o pruning automático de blocos antigos se o tamanho em MiB for atingido. Esse modo é incompatíve com -txindex e -rescan. Aviso: Reverter essa configuração requer re-baixar o blockchain inteiro. (padrão: 0 = disabilitado, 1 = permite o pruning manua via RPC, &gt;%u = pruna os blocos para ficar abaixo do expecificado, em MiB)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>Taxa (em %s/KiB) a ser adicionada às transações que você mandar (padrão: %s)</translation>
+ </message>
+ <message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation>Define o número de threads de verificação de script (%u a %d, 0 = automático, &lt;0 = número de cores deixados livres, padrão: %d)</translation>
</message>
@@ -3122,6 +3130,10 @@
<translation>Use UPnP para mapear a porta escutada (padrão: 1 quando escutando e sem -proxy)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>Nome de usuário e hash da senha para conexões JSON-RPC. O campo &lt;userpw&gt; vem com o formato: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. Um script python canônico é incluído em share/rpcuser. O cliente pode conectar normalmente usando o rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt;. Esta opção pode ser especificado multiplas vezes</translation>
+ </message>
+ <message>
<source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
<translation>A carteira não irá criar transações que vioem o imite de memória (padrão: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts
index 7bfb3e710d..785cc537b7 100644
--- a/src/qt/locale/bitcoin_pt_PT.ts
+++ b/src/qt/locale/bitcoin_pt_PT.ts
@@ -2163,10 +2163,6 @@
<translation>Suprimir: a última sincronização da carteira vai além dos dados suprimidos. O que precisa para -reindex (transferir novamente toda a cadeia de blocos, no caso de nó suprimido)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Reduza os requisitos de armazenamento podando (eliminando) blocos antigos. Este modo é incompatível com -txindex e -rescan. Aviso: Reverter esta opção requer um novo descarregamento da cadeia de blocos completa. (padrão: 0 = desactivar poda de blocos, &gt;%u = tamanho desejado em MiB para utilizar em ficheiros de blocos)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Reanálises não são possíveis no modo de suprimir. Para isso terá de utilizar -reindex que irá transferir novamente toda a cadeia de blocos.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts
index 11fa2f7fea..8dd94ff220 100644
--- a/src/qt/locale/bitcoin_ru.ts
+++ b/src/qt/locale/bitcoin_ru.ts
@@ -3030,10 +3030,6 @@
<translation>Удаление: последняя синхронизация кошелька вышла за рамки удаленных данных. Вам нужен -reindex (скачать всю цепь блоков в случае удаленного узла)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Уменьшить размер хранилища за счёт удаления (обрезания) старых блоков. Этот режим несовместим с -txindex и -rescan. Внимание: переключение этой опции обратно потребует полной загрузки цепи блоков. (по умолчанию: 0 = отключить удаление блоков, &gt;%u = целевой размер в Мб для файлов блоков)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Повторное сканирование не возможно в режиме удаления. Вам надо будет использовать -reindex, который загрузит заново всю цепь блоков.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts
index 4d45d20cbf..fc7ccdeba2 100644
--- a/src/qt/locale/bitcoin_sv.ts
+++ b/src/qt/locale/bitcoin_sv.ts
@@ -2007,10 +2007,6 @@ Var vänlig och försök igen.</translation>
<translation>Beskärning: sista plånbokssynkroniseringen ligger utanför beskuren data. Du måste använda -reindex (ladda ner hela blockkedjan igen eftersom noden beskurits)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Minska lagringsbehovet genom att beskära (ta bort) gamla block. Detta läge är inkompatibelt med -txindex och -rescan. Varning: Ändras denna inställning måste hela blockkedjan laddas ner igen. (förvalt: 0 = inaktivera beskärning av block, &gt;%u = målstorlek i MiB att använda för blockfiler)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Omskanningar kan inte göras i beskuret läge. Du måste använda -reindex vilket kommer ladda ner hela blockkedjan igen.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts
index d1249d09be..ae565ee665 100644
--- a/src/qt/locale/bitcoin_tr.ts
+++ b/src/qt/locale/bitcoin_tr.ts
@@ -1938,10 +1938,6 @@
<translation>Budama: son cüzdan eşleşmesi budanmış verilerin ötesine gitmektedir. -reindex kullanmanız gerekmektedir (Budanmış düğüm ise tüm blok zincirini tekrar indirmeniz gerekir.)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Depolama gerekliliğini eski blokları budayarak (silerek) düşür. Bu kip -txindex ve -rescan ile uyumsuzdur. İkaz: Bu ayarı geri almak tüm blok zincirini yeniden indirmeyi gerektirir. (varsayılan: 0 = blokları silmeyi devre dışı bırak, &gt;%u = MiB olarak blok dosyaları için kullanılacak hedef boyut)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Tekrar taramalar budanmış kipte mümkün değildir. Tüm blok zincirini tekrar indirecek olan -reindex seçeneğini kullanmanız gerekecektir.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts
index 9c46c18224..a817c1baf2 100644
--- a/src/qt/locale/bitcoin_uk.ts
+++ b/src/qt/locale/bitcoin_uk.ts
@@ -1678,10 +1678,6 @@
<translation>Операція відсікання: остання синхронізація вмісту гаманцю не обмежується діями над скороченими данними. Вам необхідно зробити переіндексацію -reindex (заново завантажити веcь ланцюжок блоків в разі появи скороченого ланцюга)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>Зменшити вимоги до наявного простору на носії даних за допомогою скорочення ланцюжка (видалення старих блоків). Цей режим несумісний з параметрами -txindex та -rescan. Увага: при поверненні до типового значення видалені частини ланцюжка буде повторно завантажено. (типово: 0 = вимкнути скорочення ланцюжка, &gt;%u = очікуваний розмір файлів блоків в МіБ)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>Неможливо провести повторне сканування зі скороченим ланцюжком. Вам необхідно використати -reindex для завантаження повного ланцюжка блоків.</translation>
</message>
diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts
index 8267a4f0e3..e76d605a80 100644
--- a/src/qt/locale/bitcoin_zh_CN.ts
+++ b/src/qt/locale/bitcoin_zh_CN.ts
@@ -2971,10 +2971,6 @@
<translation>修剪:最后的钱包同步超过了修剪的数据。你需要通过 -reindex (重新下载整个区块链以防修剪节点)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>通过修剪(删除)旧数据块减少存储需求。此模式与 -txindex 和 -rescan不兼容。警告:还原此设置需要重新下载整个区块链。(默认: 0 = 禁用修剪数据块, &gt;%u = 数据块文件目标大小,单位 MiB)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>无法在开启修剪的状态下重扫描,请使用 -reindex重新下载完整的区块链。</translation>
</message>
diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts
index bdcf966297..4a8b1474d8 100644
--- a/src/qt/locale/bitcoin_zh_TW.ts
+++ b/src/qt/locale/bitcoin_zh_TW.ts
@@ -2201,6 +2201,14 @@
<translation>警告: 不明的找零位址</translation>
</message>
<message>
+ <source>Confirm custom change address</source>
+ <translation>自定找零位址確認</translation>
+ </message>
+ <message>
+ <source>The address you selected for change is not part of this wallet. Any or all funds in your wallet may be sent to this address. Are you sure?</source>
+ <translation>選擇的找零位址並不屬於這個錢包。部份或是全部的錢會被送到這個位址去。你確定嗎?</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>(無標記)</translation>
</message>
@@ -3019,10 +3027,6 @@
<translation>修剪模式:錢包的最後同步狀態是在被修剪掉的區塊資料中。你需要用 -reindex 參數執行(會重新下載整個區塊鏈)</translation>
</message>
<message>
- <source>Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
- <translation>修剪(刪除)掉老舊區塊來減少需要的儲存空間。這種模式會關閉錢包功能,並且和 -txindex 及 -rescan 參數不相容。警告: 從這種模式還原會需要重新下載一整個區塊鏈。(預設值: 0 表示不修剪區塊,&gt;%u 表示為區塊檔案的目標大小,單位是百萬位元組 MiB)</translation>
- </message>
- <message>
<source>Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.</source>
<translation>在修剪模式下沒辦法重新掃描區塊鏈。你需要配合使用 -reindex 參數來重新下載整個區塊鏈。</translation>
</message>
@@ -3103,6 +3107,14 @@
<translation>如果你覺得 %s 有用,可以幫助我們。關於這個軟體的更多資訊請見 %s。</translation>
</message>
<message>
+ <source>Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, &gt;%u = automatically prune block files to stay under the specified target size in MiB)</source>
+ <translation>修剪(刪除)掉老舊區塊以降低需要的儲存空間。這樣會增加一個 RPC 指令 pruneblockchain,可以使用它來刪除指定的區塊;也可以指定目標儲存空間大小,以啟用對老舊區塊的自動修剪功能。這個模式跟 -txindex 和 -rescan 參數不相容。警告: 還原回不修剪模式會需要重新下載一整個區塊鏈。(預設值: 0 表示不修剪區塊,1 表示允許使用 RPC 指令做修剪,&gt;%u 的值表示為區塊資料的目標大小,單位是百萬位元組,MiB)</translation>
+ </message>
+ <message>
+ <source>Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)</source>
+ <translation>設定製造區塊時,所要包含交易每千位元組的最低手續費(單位是 %s)。(預設值: %s)</translation>
+ </message>
+ <message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation>設定指令碼驗證的執行緒數目 (%u 到 %d,0 表示程式自動決定,小於 0 表示保留處理器核心不用的數目,預設值: %d)</translation>
</message>
@@ -3123,6 +3135,10 @@
<translation>是否要使用「通用即插即用」協定(UPnP),來設定聽候連線的通訊埠的對應(預設值: 當有聽候連線且沒有指定 -proxy 參數時為 1)</translation>
</message>
<message>
+ <source>Username and hashed password for JSON-RPC connections. The field &lt;userpw&gt; comes in the format: &lt;USERNAME&gt;:&lt;SALT&gt;$&lt;HASH&gt;. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=&lt;USERNAME&gt;/rpcpassword=&lt;PASSWORD&gt; pair of arguments. This option can be specified multiple times</source>
+ <translation>JSON-RPC 連線要用的使用者名稱和雜湊密碼。&lt;userpw&gt; 的格式是:&lt;使用者名稱&gt;:&lt;調味值&gt;$&lt;雜湊值&gt;。在 share/rpcuser 目錄下有一個示範的 python 程式。之後客戶端程式就可以用這對參數正常連線:rpcuser=&lt;使用者名稱&gt; 和 rpcpassword=&lt;密碼&gt;。這個選項可以給很多次。</translation>
+ </message>
+ <message>
<source>Wallet will not create transactions that violate mempool chain limits (default: %u)</source>
<translation>錢包軟體不會產生違反記憶池交易鏈限制的交易(預設值: %u)</translation>
</message>
diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp
index 89fb159956..4779ffa43f 100644
--- a/src/qt/modaloverlay.cpp
+++ b/src/qt/modaloverlay.cpp
@@ -7,6 +7,8 @@
#include "guiutil.h"
+#include "chainparams.h"
+
#include <QResizeEvent>
#include <QPropertyAnimation>
@@ -125,11 +127,11 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri
// estimate the number of headers left based on nPowTargetSpacing
// and check if the gui is not aware of the the best header (happens rarely)
- int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / 600;
+ int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
bool hasBestHeader = bestHeaderHeight >= count;
// show remaining number of blocks
- if (estimateNumHeadersLeft < 24 && hasBestHeader) {
+ if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
} else {
ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1)...").arg(bestHeaderHeight));
diff --git a/src/qt/modaloverlay.h b/src/qt/modaloverlay.h
index 70d37b87ad..21ccdbd839 100644
--- a/src/qt/modaloverlay.h
+++ b/src/qt/modaloverlay.h
@@ -8,6 +8,9 @@
#include <QDateTime>
#include <QWidget>
+//! The required delta of headers to the estimated number of available headers until we show the IBD progress
+static constexpr int HEADER_HEIGHT_DELTA_SYNC = 24;
+
namespace Ui {
class ModalOverlay;
}
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 5aeda7a30d..1e2842df73 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -16,6 +16,7 @@
#include "walletmodel.h"
#include "base58.h"
+#include "chainparams.h"
#include "wallet/coincontrol.h"
#include "validation.h" // mempool and minRelayTxFee
#include "ui_interface.h"
@@ -608,7 +609,7 @@ void SendCoinsDialog::updateGlobalFeeVariables()
CoinControlDialog::coinControl->nMinimumTotalFee = 0;
// show the estimated reuquired time for confirmation
- ui->confirmationTargetLabel->setText(GUIUtil::formatDurationStr(nConfirmTarget*600)+" / "+tr("%n block(s)", "", nConfirmTarget));
+ ui->confirmationTargetLabel->setText(GUIUtil::formatDurationStr(nConfirmTarget * Params().GetConsensus().nPowTargetSpacing) + " / " + tr("%n block(s)", "", nConfirmTarget));
}
else
{
diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp
index fbec5722b6..bd496f149c 100644
--- a/src/qt/test/rpcnestedtests.cpp
+++ b/src/qt/test/rpcnestedtests.cpp
@@ -29,7 +29,7 @@ static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
static const CRPCCommand vRPCCommands[] =
{
- { "test", "rpcNestedTest", &rpcNestedTest_rpc, true },
+ { "test", "rpcNestedTest", &rpcNestedTest_rpc, true, {} },
};
void RPCNestedTests::rpcNestedTests()
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index 5d3c458455..5bdd84e555 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -117,6 +117,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "setnetworkactive", 0, "state" },
{ "getmempoolancestors", 1, "verbose" },
{ "getmempooldescendants", 1, "verbose" },
+ { "bumpfee", 1, "options" },
// Echo with conversion (For testing only)
{ "echojson", 0, "arg0" },
{ "echojson", 1, "arg1" },
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 1b94e10071..283d458c8d 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -79,16 +79,20 @@ void RPCTypeCheck(const UniValue& params,
break;
const UniValue& v = params[i];
- if (!((v.type() == t) || (fAllowNull && (v.isNull()))))
- {
- string err = strprintf("Expected type %s, got %s",
- uvTypeName(t), uvTypeName(v.type()));
- throw JSONRPCError(RPC_TYPE_ERROR, err);
+ if (!(fAllowNull && v.isNull())) {
+ RPCTypeCheckArgument(v, t);
}
i++;
}
}
+void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected)
+{
+ if (value.type() != typeExpected) {
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected), uvTypeName(value.type())));
+ }
+}
+
void RPCTypeCheckObj(const UniValue& o,
const map<string, UniValueType>& typesExpected,
bool fAllowNull,
diff --git a/src/rpc/server.h b/src/rpc/server.h
index fed3d8c90f..52f82866dc 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -78,6 +78,11 @@ bool RPCIsInWarmup(std::string *statusOut);
void RPCTypeCheck(const UniValue& params,
const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);
+/**
+ * Type-check one argument; throws JSONRPCError if wrong type given.
+ */
+void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected);
+
/*
Check for expected keys/value types in an Object.
*/
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 48313915e7..322addc9f6 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -297,7 +297,7 @@ BOOST_AUTO_TEST_CASE(addrman_find)
// Test 18; Find does not discriminate by port number.
CAddrInfo* info2 = addrman.Find(addr2);
BOOST_CHECK(info2);
- if (info2)
+ if (info2 && info1)
BOOST_CHECK(info2->ToString() == info1->ToString());
// Test 19: Find returns another IP matching what we searched on.
diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp
index 1bc50d5ea9..00446aa11e 100644
--- a/src/test/cuckoocache_tests.cpp
+++ b/src/test/cuckoocache_tests.cpp
@@ -15,7 +15,7 @@
* with deterministic seeds)
* 2) Some test methods are templated to allow for easier testing
* against new versions / comparing
- * 3) Results should be treated as a regression test, ie, did the behavior
+ * 3) Results should be treated as a regression test, i.e., did the behavior
* change significantly from what was expected. This can be OK, depending on
* the nature of the change, but requires updating the tests to reflect the new
* expected behavior. For example improving the hit rate may cause some tests
diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp
index e5cb48ffcf..d5d158027b 100644
--- a/src/test/dbwrapper_tests.cpp
+++ b/src/test/dbwrapper_tests.cpp
@@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch)
BOOST_CHECK(dbw.Read(key2, res));
BOOST_CHECK_EQUAL(res.ToString(), in2.ToString());
- // key3 never should've been written
+ // key3 should've never been written
BOOST_CHECK(dbw.Read(key3, res) == false);
}
}
diff --git a/src/test/limitedmap_tests.cpp b/src/test/limitedmap_tests.cpp
index 55b9be5b00..b071ab117b 100644
--- a/src/test/limitedmap_tests.cpp
+++ b/src/test/limitedmap_tests.cpp
@@ -27,7 +27,7 @@ BOOST_AUTO_TEST_CASE(limitedmap_test)
// make sure that the size is updated
BOOST_CHECK(map.size() == 1);
- // make sure that the new items is in the map
+ // make sure that the new item is in the map
BOOST_CHECK(map.count(-1) == 1);
// insert 10 new items
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index e1b0ab9258..e4ddf9d618 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -47,8 +47,8 @@ BOOST_AUTO_TEST_CASE(manythreads)
//
// So... ten shared counters, which if all the tasks execute
// properly will sum to the number of tasks done.
- // Each task adds or subtracts from one of the counters a
- // random amount, and then schedules another task 0-1000
+ // Each task adds or subtracts a random amount from one of the
+ // counters, and then schedules another task 0-1000
// microseconds in the future to subtract or add from
// the counter -random_amount+1, so in the end the shared
// counters should sum to the number of initial tasks performed.
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 6f057f43b4..32184165f7 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -465,7 +465,7 @@ public:
std::string JSONPrettyPrint(const UniValue& univalue)
{
std::string ret = univalue.write(4);
- // Workaround for libunivalue pretty printer, which puts a space between comma's and newlines
+ // Workaround for libunivalue pretty printer, which puts a space between commas and newlines
size_t pos = 0;
while ((pos = ret.find(" \n", pos)) != std::string::npos) {
ret.replace(pos, 2, "\n");
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index f0eaab2217..4785415e3c 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -147,7 +147,7 @@ CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CT
}
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn, CTxMemPool *pool) {
- // Hack to assume either its completely dependent on other mempool txs or not at all
+ // Hack to assume either it's completely dependent on other mempool txs or not at all
CAmount inChainValue = pool && pool->HasNoInputsOf(txn) ? txn.GetValueOut() : 0;
return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight,
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 5b085f492d..54400caccc 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -393,6 +393,7 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n)
bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate)
{
+ NotifyEntryAdded(entry.GetSharedTx());
// Add to memory pool without checking anything.
// Used by main.cpp AcceptToMemoryPool(), which DOES do
// all the appropriate checks.
@@ -449,8 +450,9 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
return true;
}
-void CTxMemPool::removeUnchecked(txiter it)
+void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
{
+ NotifyEntryRemoved(it->GetSharedTx(), reason);
const uint256 hash = it->GetTx().GetHash();
BOOST_FOREACH(const CTxIn& txin, it->GetTx().vin)
mapNextTx.erase(txin.prevout);
@@ -502,7 +504,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants
}
}
-void CTxMemPool::removeRecursive(const CTransaction &origTx)
+void CTxMemPool::removeRecursive(const CTransaction &origTx, MemPoolRemovalReason reason)
{
// Remove transaction from memory pool
{
@@ -529,7 +531,8 @@ void CTxMemPool::removeRecursive(const CTransaction &origTx)
BOOST_FOREACH(txiter it, txToRemove) {
CalculateDescendants(it, setAllRemoves);
}
- RemoveStaged(setAllRemoves, false);
+
+ RemoveStaged(setAllRemoves, false, reason);
}
}
@@ -567,7 +570,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
for (txiter it : txToRemove) {
CalculateDescendants(it, setAllRemoves);
}
- RemoveStaged(setAllRemoves, false);
+ RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG);
}
void CTxMemPool::removeConflicts(const CTransaction &tx)
@@ -581,7 +584,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx)
if (txConflict != tx)
{
ClearPrioritisation(txConflict.GetHash());
- removeRecursive(txConflict);
+ removeRecursive(txConflict, MemPoolRemovalReason::CONFLICT);
}
}
}
@@ -610,7 +613,7 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
if (it != mapTx.end()) {
setEntries stage;
stage.insert(it);
- RemoveStaged(stage, true);
+ RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK);
}
removeConflicts(*tx);
ClearPrioritisation(tx->GetHash());
@@ -989,11 +992,11 @@ size_t CTxMemPool::DynamicMemoryUsage() const {
return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 15 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + memusage::DynamicUsage(vTxHashes) + cachedInnerUsage;
}
-void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants) {
+void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason) {
AssertLockHeld(cs);
UpdateForRemoveFromMempool(stage, updateDescendants);
BOOST_FOREACH(const txiter& it, stage) {
- removeUnchecked(it);
+ removeUnchecked(it, reason);
}
}
@@ -1009,7 +1012,7 @@ int CTxMemPool::Expire(int64_t time) {
BOOST_FOREACH(txiter removeit, toremove) {
CalculateDescendants(removeit, stage);
}
- RemoveStaged(stage, false);
+ RemoveStaged(stage, false, MemPoolRemovalReason::EXPIRY);
return stage.size();
}
@@ -1118,7 +1121,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<uint256>* pvNoSpendsRe
BOOST_FOREACH(txiter iter, stage)
txn.push_back(iter->GetTx());
}
- RemoveStaged(stage, false);
+ RemoveStaged(stage, false, MemPoolRemovalReason::SIZELIMIT);
if (pvNoSpendsRemaining) {
BOOST_FOREACH(const CTransaction& tx, txn) {
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
diff --git a/src/txmempool.h b/src/txmempool.h
index ffb1c1309b..f842a07dd6 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -25,6 +25,8 @@
#include "boost/multi_index/ordered_index.hpp"
#include "boost/multi_index/hashed_index.hpp"
+#include <boost/signals2/signal.hpp>
+
class CAutoFile;
class CBlockIndex;
@@ -333,6 +335,19 @@ struct TxMempoolInfo
int64_t nFeeDelta;
};
+/** Reason why a transaction was removed from the mempool,
+ * this is passed to the notification signal.
+ */
+enum class MemPoolRemovalReason {
+ UNKNOWN = 0, //! Manually removed or unknown reason
+ EXPIRY, //! Expired from mempool
+ SIZELIMIT, //! Removed in size limiting
+ REORG, //! Removed for reorganization
+ BLOCK, //! Removed for block
+ CONFLICT, //! Removed for conflict with in-block transaction
+ REPLACED //! Removed for replacement
+};
+
/**
* CTxMemPool stores valid-according-to-the-current-best-chain transactions
* that may be included in the next block.
@@ -521,10 +536,11 @@ public:
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool validFeeEstimate = true);
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate = true);
- void removeRecursive(const CTransaction &tx);
+ void removeRecursive(const CTransaction &tx, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags);
void removeConflicts(const CTransaction &tx);
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight);
+
void clear();
void _clear(); //lock free
bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb);
@@ -551,7 +567,7 @@ public:
* Set updateDescendants to true when removing a tx that was in a block, so
* that any in-mempool descendants have their ancestor state updated.
*/
- void RemoveStaged(setEntries &stage, bool updateDescendants);
+ void RemoveStaged(setEntries &stage, bool updateDescendants, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
/** When adding transactions from a disconnected block back to the mempool,
* new mempool entries may have children in the mempool (which is generally
@@ -647,6 +663,9 @@ public:
size_t DynamicMemoryUsage() const;
+ boost::signals2::signal<void (CTransactionRef)> NotifyEntryAdded;
+ boost::signals2::signal<void (CTransactionRef, MemPoolRemovalReason)> NotifyEntryRemoved;
+
private:
/** UpdateForDescendants is used by UpdateTransactionsFromBlock to update
* the descendants for a single transaction that has been added to the
@@ -683,7 +702,7 @@ private:
* transactions in a chain before we've updated all the state for the
* removal.
*/
- void removeUnchecked(txiter entry);
+ void removeUnchecked(txiter entry, MemPoolRemovalReason reason = MemPoolRemovalReason::UNKNOWN);
};
/**
diff --git a/src/validation.cpp b/src/validation.cpp
index bb13cbaadb..e6bc2288d2 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -157,6 +157,39 @@ namespace {
set<int> setDirtyFileInfo;
} // anon namespace
+/* Use this class to start tracking transactions that are removed from the
+ * mempool and pass all those transactions through SyncTransaction when the
+ * object goes out of scope. This is currently only used to call SyncTransaction
+ * on conflicts removed from the mempool during block connection. Applied in
+ * ActivateBestChain around ActivateBestStep which in turn calls:
+ * ConnectTip->removeForBlock->removeConflicts
+ */
+class MemPoolConflictRemovalTracker
+{
+private:
+ std::vector<CTransactionRef> conflictedTxs;
+ CTxMemPool &pool;
+
+public:
+ MemPoolConflictRemovalTracker(CTxMemPool &_pool) : pool(_pool) {
+ pool.NotifyEntryRemoved.connect(boost::bind(&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
+ }
+
+ void NotifyEntryRemoved(CTransactionRef txRemoved, MemPoolRemovalReason reason) {
+ if (reason == MemPoolRemovalReason::CONFLICT) {
+ conflictedTxs.push_back(txRemoved);
+ }
+ }
+
+ ~MemPoolConflictRemovalTracker() {
+ pool.NotifyEntryRemoved.disconnect(boost::bind(&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
+ for (const auto& tx : conflictedTxs) {
+ GetMainSignals().SyncTransaction(*tx, NULL, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
+ }
+ conflictedTxs.clear();
+ }
+};
+
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
{
// Find the first block the caller has in the main chain
@@ -921,12 +954,13 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
- if (!tx.HasWitness() && CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) &&
- !CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata)) {
+ CValidationState stateDummy; // Want reported failures to be from first CheckInputs
+ if (!tx.HasWitness() && CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) &&
+ !CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata)) {
// Only the witness is missing, so the transaction itself may be fine.
state.SetCorruptionPossible();
}
- return false;
+ return false; // state filled in by CheckInputs
}
// Check again against just the consensus-critical mandatory script
@@ -955,7 +989,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if (plTxnReplaced)
plTxnReplaced->push_back(it->GetSharedTx());
}
- pool.RemoveStaged(allConflicting, false);
+ pool.RemoveStaged(allConflicting, false, MemPoolRemovalReason::REPLACED);
// This transaction should only count for fee estimation if
// the node is not behind and it is not dependent on any other
@@ -2027,7 +2061,7 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode, int n
setDirtyBlockIndex.erase(it++);
}
if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) {
- return AbortNode(state, "Files to write to block index database");
+ return AbortNode(state, "Failed to write to block index database");
}
}
// Finally remove any pruned files
@@ -2165,7 +2199,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
// ignore validation errors in resurrected transactions
CValidationState stateDummy;
if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, it, false, NULL, NULL, true)) {
- mempool.removeRecursive(tx);
+ mempool.removeRecursive(tx, MemPoolRemovalReason::REORG);
} else if (mempool.exists(tx.GetHash())) {
vHashUpdate.push_back(tx.GetHash());
}
@@ -2452,6 +2486,14 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
bool fInitialDownload;
{
LOCK(cs_main);
+ { // TODO: Tempoarily ensure that mempool removals are notified before
+ // connected transactions. This shouldn't matter, but the abandoned
+ // state of transactions in our wallet is currently cleared when we
+ // receive another notification and there is a race condition where
+ // notification of a connected conflict might cause an outside process
+ // to abandon a transaction and then have it inadvertantly cleared by
+ // the notification that the conflicted transaction was evicted.
+ MemPoolConflictRemovalTracker mrt(mempool);
CBlockIndex *pindexOldTip = chainActive.Tip();
if (pindexMostWork == NULL) {
pindexMostWork = FindMostWorkChain();
@@ -2473,20 +2515,23 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
pindexNewTip = chainActive.Tip();
pindexFork = chainActive.FindFork(pindexOldTip);
fInitialDownload = IsInitialBlockDownload();
+
+ // throw all transactions though the signal-interface
+
+ } // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
+
+ // Transactions in the connnected block are notified
+ for (const auto& pair : connectTrace.blocksConnected) {
+ assert(pair.second);
+ const CBlock& block = *(pair.second);
+ for (unsigned int i = 0; i < block.vtx.size(); i++)
+ GetMainSignals().SyncTransaction(*block.vtx[i], pair.first, i);
+ }
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
// Notifications/callbacks that can run without cs_main
- // throw all transactions though the signal-interface
- // while _not_ holding the cs_main lock
- for (const auto& pair : connectTrace.blocksConnected) {
- assert(pair.second);
- const CBlock& block = *(pair.second);
- for (unsigned int i = 0; i < block.vtx.size(); i++)
- GetMainSignals().SyncTransaction(*block.vtx[i], pair.first, i);
- }
-
// Notify external listeners about the new tip.
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
@@ -3597,7 +3642,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 1: verify block validity
if (nCheckLevel >= 1 && !CheckBlock(block, state, chainparams.GetConsensus()))
- return error("%s: *** found bad block at %d, hash=%s (%s)\n", __func__,
+ return error("%s: *** found bad block at %d, hash=%s (%s)\n", __func__,
pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state));
// check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) {
@@ -3768,7 +3813,7 @@ bool LoadBlockIndex(const CChainParams& chainparams)
return true;
}
-bool InitBlockIndex(const CChainParams& chainparams)
+bool InitBlockIndex(const CChainParams& chainparams)
{
LOCK(cs_main);
@@ -4202,7 +4247,7 @@ void DumpMempool(void)
{
LOCK(mempool.cs);
for (const auto &i : mempool.mapDeltas) {
- mapDeltas[i.first] = i.second.first;
+ mapDeltas[i.first] = i.second.second;
}
vinfo = mempool.infoAll();
}
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 594072719c..a2e76f2036 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -50,9 +50,16 @@ protected:
struct CMainSignals {
/** Notifies listeners of updated block chain tip */
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
- /** A posInBlock value for SyncTransaction which indicates the transaction was conflicted, disconnected, or not in a block */
+ /** A posInBlock value for SyncTransaction calls for tranactions not
+ * included in connected blocks such as transactions removed from mempool,
+ * accepted to mempool or appearing in disconnected blocks.*/
static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1;
- /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */
+ /** Notifies listeners of updated transaction data (transaction, and
+ * optionally the block it is found in). Called with block data when
+ * transaction is included in a connected block, and without block data when
+ * transaction was accepted to mempool, removed from mempool (only when
+ * removal was due to conflict from connected block), or appeared in a
+ * disconnected block.*/
boost::signals2::signal<void (const CTransaction &, const CBlockIndex *pindex, int posInBlock)> SyncTransaction;
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 2428ef04e2..6d08f60483 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -11,8 +11,10 @@
#include "init.h"
#include "validation.h"
#include "net.h"
+#include "policy/policy.h"
#include "policy/rbf.h"
#include "rpc/server.h"
+#include "script/sign.h"
#include "timedata.h"
#include "util.h"
#include "utilmoneystr.h"
@@ -1679,7 +1681,7 @@ UniValue listsinceblock(const JSONRPCRequest& request)
LOCK2(cs_main, pwalletMain->cs_wallet);
- CBlockIndex *pindex = NULL;
+ const CBlockIndex *pindex = NULL;
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
@@ -1690,7 +1692,16 @@ UniValue listsinceblock(const JSONRPCRequest& request)
blockId.SetHex(request.params[0].get_str());
BlockMap::iterator it = mapBlockIndex.find(blockId);
if (it != mapBlockIndex.end())
+ {
pindex = it->second;
+ if (chainActive[pindex->nHeight] != pindex)
+ {
+ // the block being asked for is a part of a deactivated chain;
+ // we don't want to depend on its perceived height in the block
+ // chain, we want to instead use the last common ancestor
+ pindex = chainActive.FindFork(pindex);
+ }
+ }
}
if (request.params.size() > 1)
@@ -1701,9 +1712,10 @@ UniValue listsinceblock(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
}
- if(request.params.size() > 2)
- if(request.params[2].get_bool())
- filter = filter | ISMINE_WATCH_ONLY;
+ if (request.params.size() > 2 && request.params[2].get_bool())
+ {
+ filter = filter | ISMINE_WATCH_ONLY;
+ }
int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
@@ -2364,9 +2376,9 @@ UniValue listunspent(const JSONRPCRequest& request)
if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (request.fHelp || request.params.size() > 3)
+ if (request.fHelp || request.params.size() > 4)
throw runtime_error(
- "listunspent ( minconf maxconf [\"addresses\",...] )\n"
+ "listunspent ( minconf maxconf [\"addresses\",...] [include_unsafe] )\n"
"\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filter to only include txouts paid to specified addresses.\n"
@@ -2378,6 +2390,10 @@ UniValue listunspent(const JSONRPCRequest& request)
" \"address\" (string) bitcoin address\n"
" ,...\n"
" ]\n"
+ "4. include_unsafe (bool, optional, default=true) Include outputs that are not safe to spend\n"
+ " because they come from unconfirmed untrusted transactions or unconfirmed\n"
+ " replacement transactions (cases where we are less sure that a conflicting\n"
+ " transaction won't be mined).\n"
"\nResult\n"
"[ (array of json object)\n"
" {\n"
@@ -2401,18 +2417,21 @@ UniValue listunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
);
- RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
-
int nMinDepth = 1;
- if (request.params.size() > 0)
+ if (request.params.size() > 0 && !request.params[0].isNull()) {
+ RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
nMinDepth = request.params[0].get_int();
+ }
int nMaxDepth = 9999999;
- if (request.params.size() > 1)
+ if (request.params.size() > 1 && !request.params[1].isNull()) {
+ RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
nMaxDepth = request.params[1].get_int();
+ }
set<CBitcoinAddress> setAddress;
- if (request.params.size() > 2) {
+ if (request.params.size() > 2 && !request.params[2].isNull()) {
+ RPCTypeCheckArgument(request.params[2], UniValue::VARR);
UniValue inputs = request.params[2].get_array();
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
@@ -2425,11 +2444,17 @@ UniValue listunspent(const JSONRPCRequest& request)
}
}
+ bool include_unsafe = true;
+ if (request.params.size() > 3 && !request.params[3].isNull()) {
+ RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
+ include_unsafe = request.params[3].get_bool();
+ }
+
UniValue results(UniValue::VARR);
vector<COutput> vecOutputs;
assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet);
- pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
+ pwalletMain->AvailableCoins(vecOutputs, !include_unsafe, NULL, true);
BOOST_FOREACH(const COutput& out, vecOutputs) {
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
continue;
@@ -2496,6 +2521,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
" \"changePosition\" (numeric, optional, default random) The index of the change output\n"
" \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n"
" \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n"
+ " \"reserveChangeKey\" (boolean, optional, default true) Reserves the change output key from the keypool\n"
" \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific feerate (" + CURRENCY_UNIT + " per KB)\n"
" \"subtractFeeFromOutputs\" (array, optional) A json array of integers.\n"
" The fee will be equally deducted from the amount of each specified output.\n"
@@ -2528,6 +2554,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
int changePosition = -1;
bool includeWatching = false;
bool lockUnspents = false;
+ bool reserveChangeKey = true;
CFeeRate feeRate = CFeeRate(0);
bool overrideEstimatedFeerate = false;
UniValue subtractFeeFromOutputs;
@@ -2549,6 +2576,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
{"changePosition", UniValueType(UniValue::VNUM)},
{"includeWatching", UniValueType(UniValue::VBOOL)},
{"lockUnspents", UniValueType(UniValue::VBOOL)},
+ {"reserveChangeKey", UniValueType(UniValue::VBOOL)},
{"feeRate", UniValueType()}, // will be checked below
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
},
@@ -2572,6 +2600,9 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
if (options.exists("lockUnspents"))
lockUnspents = options["lockUnspents"].get_bool();
+ if (options.exists("reserveChangeKey"))
+ reserveChangeKey = options["reserveChangeKey"].get_bool();
+
if (options.exists("feeRate"))
{
feeRate = CFeeRate(AmountFromValue(options["feeRate"]));
@@ -2608,7 +2639,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
CAmount nFeeOut;
string strFailReason;
- if(!pwalletMain->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, setSubtractFeeFromOutputs, changeAddress))
+ if(!pwalletMain->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, setSubtractFeeFromOutputs, reserveChangeKey, changeAddress))
throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
UniValue result(UniValue::VOBJ);
@@ -2619,6 +2650,261 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
return result;
}
+UniValue bumpfee(const JSONRPCRequest& request)
+{
+ if (!EnsureWalletIsAvailable(request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
+ throw runtime_error(
+ "bumpfee \"txid\" ( options ) \n"
+ "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
+ "An opt-in RBF transaction with the given txid must be in the wallet.\n"
+ "The command will pay the additional fee by decreasing (or perhaps removing) its change output.\n"
+ "If the change output is not big enough to cover the increased fee, the command will currently fail\n"
+ "instead of adding new inputs to compensate. (A future implementation could improve this.)\n"
+ "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
+ "By default, the new fee will be calculated automatically using estimatefee.\n"
+ "The user can specify a confirmation target for estimatefee.\n"
+ "Alternatively, the user can specify totalFee, or use RPC setpaytxfee to set a higher fee rate.\n"
+ "At a minimum, the new fee rate must be high enough to pay a new relay fee (relay fee amount returned\n"
+ "by getnetworkinfo RPC) and to enter the node's mempool.\n"
+ "\nArguments:\n"
+ "1. txid (string, required) The txid to be bumped\n"
+ "2. options (object, optional)\n"
+ " {\n"
+ " \"confTarget\" (numeric, optional) Confirmation target (in blocks)\n"
+ " \"totalFee\" (numeric, optional) Total fee (NOT feerate) to pay, in satoshis.\n"
+ " In rare cases, the actual fee paid might be slightly higher than the specified\n"
+ " totalFee if the tx change output has to be removed because it is too close to\n"
+ " the dust threshold.\n"
+ " \"replaceable\" (boolean, optional, default true) Whether the new transaction should still be\n"
+ " marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
+ " be left unchanged from the original. If false, any input sequence numbers in the\n"
+ " original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
+ " so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
+ " still be replacable in practice, for example if it has unconfirmed ancestors which\n"
+ " are replaceable).\n"
+ " }\n"
+ "\nResult:\n"
+ "{\n"
+ " \"txid\": \"value\", (string) The id of the new transaction\n"
+ " \"oldfee\": n, (numeric) Fee of the replaced transaction\n"
+ " \"fee\": n, (numeric) Fee of the new transaction\n"
+ "}\n"
+ "\nExamples:\n"
+ "\nBump the fee, get the new transaction\'s txid\n" +
+ HelpExampleCli("bumpfee", "<txid>"));
+ }
+
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VOBJ));
+ uint256 hash;
+ hash.SetHex(request.params[0].get_str());
+
+ // retrieve the original tx from the wallet
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+ EnsureWalletIsUnlocked();
+ if (!pwalletMain->mapWallet.count(hash)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
+ }
+ CWalletTx& wtx = pwalletMain->mapWallet[hash];
+
+ if (pwalletMain->HasWalletSpend(hash)) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the wallet");
+ }
+
+ {
+ LOCK(mempool.cs);
+ auto it = mempool.mapTx.find(hash);
+ if (it != mempool.mapTx.end() && it->GetCountWithDescendants() > 1) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Transaction has descendants in the mempool");
+ }
+ }
+
+ if (wtx.GetDepthInMainChain() != 0) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction has been mined, or is conflicted with a mined transaction");
+ }
+
+ if (!SignalsOptInRBF(wtx)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction is not BIP 125 replaceable");
+ }
+
+ if (wtx.mapValue.count("replaced_by_txid")) {
+ throw JSONRPCError(RPC_INVALID_REQUEST, strprintf("Cannot bump transaction %s which was already bumped by transaction %s", hash.ToString(), wtx.mapValue.at("replaced_by_txid")));
+ }
+
+ // check that original tx consists entirely of our inputs
+ // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
+ if (!pwalletMain->IsAllFromMe(wtx, ISMINE_SPENDABLE)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction contains inputs that don't belong to this wallet");
+ }
+
+ // figure out which output was change
+ // if there was no change output or multiple change outputs, fail
+ int nOutput = -1;
+ for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {
+ if (pwalletMain->IsChange(wtx.tx->vout[i])) {
+ if (nOutput != -1) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Transaction has multiple change outputs");
+ }
+ nOutput = i;
+ }
+ }
+ if (nOutput == -1) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Transaction does not have a change output");
+ }
+
+ // optional parameters
+ bool specifiedConfirmTarget = false;
+ int newConfirmTarget = nTxConfirmTarget;
+ CAmount totalFee = 0;
+ bool replaceable = true;
+ if (request.params.size() > 1) {
+ UniValue options = request.params[1];
+ RPCTypeCheckObj(options,
+ {
+ {"confTarget", UniValueType(UniValue::VNUM)},
+ {"totalFee", UniValueType(UniValue::VNUM)},
+ {"replaceable", UniValueType(UniValue::VBOOL)},
+ },
+ true, true);
+
+ if (options.exists("confTarget") && options.exists("totalFee")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget and totalFee options should not both be set. Please provide either a confirmation target for fee estimation or an explicit total fee for the transaction.");
+ } else if (options.exists("confTarget")) {
+ specifiedConfirmTarget = true;
+ newConfirmTarget = options["confTarget"].get_int();
+ if (newConfirmTarget <= 0) { // upper-bound will be checked by estimatefee/smartfee
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid confTarget (cannot be <= 0)");
+ }
+ } else if (options.exists("totalFee")) {
+ totalFee = options["totalFee"].get_int64();
+ if (totalFee <= 0) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid totalFee (cannot be <= 0)");
+ } else if (totalFee > maxTxFee) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid totalFee (cannot be higher than maxTxFee)");
+ }
+ }
+
+ if (options.exists("replaceable")) {
+ replaceable = options["replaceable"].get_bool();
+ }
+ }
+
+ // signature sizes can vary by a byte, so add 1 for each input when calculating the new fee
+ int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
+ const int64_t maxNewTxSize = txSize + wtx.tx->vin.size();
+
+ // calculate the old fee and fee-rate
+ CAmount nOldFee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
+ CFeeRate nOldFeeRate(nOldFee, txSize);
+ CAmount nNewFee;
+ CFeeRate nNewFeeRate;
+
+ if (totalFee > 0) {
+ CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + minRelayTxFee.GetFee(maxNewTxSize);
+ if (totalFee < minTotalFee) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid totalFee, must be at least %s (oldFee %s + relayFee %s)", FormatMoney(minTotalFee), nOldFeeRate.GetFee(maxNewTxSize), minRelayTxFee.GetFee(maxNewTxSize)));
+ }
+ nNewFee = totalFee;
+ nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
+ } else {
+ // use the user-defined payTxFee if possible, otherwise use smartfee / fallbackfee
+ if (!specifiedConfirmTarget && payTxFee.GetFeePerK() != 0) {
+ nNewFeeRate = payTxFee;
+ } else {
+ nNewFeeRate = mempool.estimateSmartFee(newConfirmTarget);
+ }
+ if (nNewFeeRate.GetFeePerK() == 0) {
+ nNewFeeRate = CWallet::fallbackFee;
+ }
+
+ // new fee rate must be at least old rate + minimum relay rate
+ if (nNewFeeRate.GetFeePerK() < nOldFeeRate.GetFeePerK() + ::minRelayTxFee.GetFeePerK()) {
+ nNewFeeRate = CFeeRate(nOldFeeRate.GetFeePerK() + ::minRelayTxFee.GetFeePerK());
+ }
+
+ nNewFee = nNewFeeRate.GetFee(maxNewTxSize);
+ }
+
+ // check that fee rate is higher than mempool's minimum fee
+ // (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
+ // This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
+ // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
+ // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
+ CFeeRate minMempoolFeeRate = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
+ if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
+ throw JSONRPCError(RPC_MISC_ERROR, strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
+ }
+
+ // Now modify the output to increase the fee.
+ // If the output is not large enough to pay the fee, fail.
+ CAmount nDelta = nNewFee - nOldFee;
+ assert(nDelta > 0);
+ CMutableTransaction tx(*(wtx.tx));
+ CTxOut* poutput = &(tx.vout[nOutput]);
+ if (poutput->nValue < nDelta) {
+ throw JSONRPCError(RPC_MISC_ERROR, "Change output is too small to bump the fee");
+ }
+
+ // If the output would become dust, discard it (converting the dust to fee)
+ poutput->nValue -= nDelta;
+ if (poutput->nValue <= poutput->GetDustThreshold(::minRelayTxFee)) {
+ LogPrint("rpc", "Bumping fee and discarding dust output\n");
+ nNewFee += poutput->nValue;
+ tx.vout.erase(tx.vout.begin() + nOutput);
+ }
+
+ // Mark new tx not replaceable, if requested.
+ if (!replaceable) {
+ for (auto& input : tx.vin) {
+ if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe;
+ }
+ }
+
+ // sign the new tx
+ CTransaction txNewConst(tx);
+ int nIn = 0;
+ for (auto& input : tx.vin) {
+ std::map<uint256, CWalletTx>::const_iterator mi = pwalletMain->mapWallet.find(input.prevout.hash);
+ assert(mi != pwalletMain->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
+ const CScript& scriptPubKey = mi->second.tx->vout[input.prevout.n].scriptPubKey;
+ const CAmount& amount = mi->second.tx->vout[input.prevout.n].nValue;
+ SignatureData sigdata;
+ if (!ProduceSignature(TransactionSignatureCreator(pwalletMain, &txNewConst, nIn, amount, SIGHASH_ALL), scriptPubKey, sigdata)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
+ }
+ UpdateTransaction(tx, nIn, sigdata);
+ nIn++;
+ }
+
+ // commit/broadcast the tx
+ CReserveKey reservekey(pwalletMain);
+ CWalletTx wtxBumped(pwalletMain, MakeTransactionRef(std::move(tx)));
+ wtxBumped.mapValue["replaces_txid"] = hash.ToString();
+ CValidationState state;
+ if (!pwalletMain->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state) || !state.IsValid()) {
+ throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()));
+ }
+
+ // mark the original tx as bumped
+ if (!pwalletMain->MarkReplaced(wtx.GetHash(), wtxBumped.GetHash())) {
+ // TODO: see if JSON-RPC has a standard way of returning a response
+ // along with an exception. It would be good to return information about
+ // wtxBumped to the caller even if marking the original transaction
+ // replaced does not succeed for some reason.
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error: Created new bumpfee transaction but could not mark the original transaction as replaced.");
+ }
+
+ UniValue result(UniValue::VOBJ);
+ result.push_back(Pair("txid", wtxBumped.GetHash().GetHex()));
+ result.push_back(Pair("oldfee", ValueFromAmount(nOldFee)));
+ result.push_back(Pair("fee", ValueFromAmount(nNewFee)));
+
+ return result;
+}
+
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue importprivkey(const JSONRPCRequest& request);
extern UniValue importaddress(const JSONRPCRequest& request);
@@ -2638,6 +2924,7 @@ static const CRPCCommand commands[] =
{ "wallet", "addmultisigaddress", &addmultisigaddress, true, {"nrequired","keys","account"} },
{ "wallet", "addwitnessaddress", &addwitnessaddress, true, {"address"} },
{ "wallet", "backupwallet", &backupwallet, true, {"destination"} },
+ { "wallet", "bumpfee", &bumpfee, true, {"txid", "options"} },
{ "wallet", "dumpprivkey", &dumpprivkey, true, {"address"} },
{ "wallet", "dumpwallet", &dumpwallet, true, {"filename"} },
{ "wallet", "encryptwallet", &encryptwallet, true, {"passphrase"} },
@@ -2666,7 +2953,7 @@ static const CRPCCommand commands[] =
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, {"minconf","include_empty","include_watchonly"} },
{ "wallet", "listsinceblock", &listsinceblock, false, {"blockhash","target_confirmations","include_watchonly"} },
{ "wallet", "listtransactions", &listtransactions, false, {"account","count","skip","include_watchonly"} },
- { "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses"} },
+ { "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses","include_unsafe"} },
{ "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
{ "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
{ "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 0b18be8764..b4715622cf 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -411,6 +411,13 @@ set<uint256> CWallet::GetConflicts(const uint256& txid) const
return result;
}
+bool CWallet::HasWalletSpend(const uint256& txid) const
+{
+ AssertLockHeld(cs_wallet);
+ auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0));
+ return (iter != mapTxSpends.end() && iter->first.hash == txid);
+}
+
void CWallet::Flush(bool shutdown)
{
bitdb.Flush(shutdown);
@@ -826,6 +833,35 @@ void CWallet::MarkDirty()
}
}
+bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
+{
+ LOCK(cs_wallet);
+
+ auto mi = mapWallet.find(originalHash);
+
+ // There is a bug if MarkReplaced is not called on an existing wallet transaction.
+ assert(mi != mapWallet.end());
+
+ CWalletTx& wtx = (*mi).second;
+
+ // Ensure for now that we're not overwriting data
+ assert(wtx.mapValue.count("replaced_by_txid") == 0);
+
+ wtx.mapValue["replaced_by_txid"] = newHash.ToString();
+
+ CWalletDB walletdb(strWalletFile, "r+");
+
+ bool success = true;
+ if (!walletdb.WriteTx(wtx)) {
+ LogPrintf("%s: Updating walletdb tx %s failed", __func__, wtx.GetHash().ToString());
+ success = false;
+ }
+
+ NotifyTransactionChanged(this, originalHash, CT_UPDATED);
+
+ return success;
+}
+
bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose)
{
LOCK(cs_wallet);
@@ -967,9 +1003,17 @@ bool CWallet::LoadToWallet(const CWalletTx& wtxIn)
}
/**
- * Add a transaction to the wallet, or update it.
- * pblock is optional, but should be provided if the transaction is known to be in a block.
+ * Add a transaction to the wallet, or update it. pIndex and posInBlock should
+ * be set when the transaction was known to be included in a block. When
+ * posInBlock = SYNC_TRANSACTION_NOT_IN_BLOCK (-1) , then wallet state is not
+ * updated in AddToWallet, but notifications happen and cached balances are
+ * marked dirty.
* If fUpdate is true, existing transactions will be updated.
+ * TODO: One exception to this is that the abandoned state is cleared under the
+ * assumption that any further notification of a transaction that was considered
+ * abandoned is an indication that it is not safe to be considered abandoned.
+ * Abandoned state should probably be more carefuly tracked via different
+ * posInBlock signals or by checking mempool presence when necessary.
*/
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
{
@@ -1154,6 +1198,8 @@ isminetype CWallet::IsMine(const CTxIn &txin) const
return ISMINE_NO;
}
+// Note that this function doesn't distinguish between a 0-valued input,
+// and a not-"is mine" (according to the filter) input.
CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
{
{
@@ -1236,6 +1282,27 @@ CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) co
return nDebit;
}
+bool CWallet::IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const
+{
+ LOCK(cs_wallet);
+
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ auto mi = mapWallet.find(txin.prevout.hash);
+ if (mi == mapWallet.end())
+ return false; // any unknown inputs can't be from us
+
+ const CWalletTx& prev = (*mi).second;
+
+ if (txin.prevout.n >= prev.tx->vout.size())
+ return false; // invalid input!
+
+ if (!(IsMine(prev.tx->vout[txin.prevout.n]) & filter))
+ return false;
+ }
+ return true;
+}
+
CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const
{
CAmount nCredit = 0;
@@ -1958,6 +2025,37 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (nDepth == 0 && !pcoin->InMempool())
continue;
+ // We should not consider coins from transactions that are replacing
+ // other transactions.
+ //
+ // Example: There is a transaction A which is replaced by bumpfee
+ // transaction B. In this case, we want to prevent creation of
+ // a transaction B' which spends an output of B.
+ //
+ // Reason: If transaction A were initially confirmed, transactions B
+ // and B' would no longer be valid, so the user would have to create
+ // a new transaction C to replace B'. However, in the case of a
+ // one-block reorg, transactions B' and C might BOTH be accepted,
+ // when the user only wanted one of them. Specifically, there could
+ // be a 1-block reorg away from the chain where transactions A and C
+ // were accepted to another chain where B, B', and C were all
+ // accepted.
+ if (nDepth == 0 && fOnlyConfirmed && pcoin->mapValue.count("replaces_txid")) {
+ continue;
+ }
+
+ // Similarly, we should not consider coins from transactions that
+ // have been replaced. In the example above, we would want to prevent
+ // creation of a transaction A' spending an output of A, because if
+ // transaction B were initially confirmed, conflicting with A and
+ // A', we wouldn't want to the user to create a transaction D
+ // intending to replace A', but potentially resulting in a scenario
+ // where A, A', and D could all be accepted (instead of just B and
+ // D, or just A and A' like the user would want).
+ if (nDepth == 0 && fOnlyConfirmed && pcoin->mapValue.count("replaced_by_txid")) {
+ continue;
+ }
+
for (unsigned int i = 0; i < pcoin->tx->vout.size(); i++) {
isminetype mine = IsMine(pcoin->tx->vout[i]);
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
@@ -2192,7 +2290,7 @@ bool CWallet::SelectCoins(const vector<COutput>& vAvailableCoins, const CAmount&
return res;
}
-bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, const CTxDestination& destChange)
+bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, bool keepReserveKey, const CTxDestination& destChange)
{
vector<CRecipient> vecSend;
@@ -2241,6 +2339,10 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool ov
}
}
+ // optionally keep the change output key
+ if (keepReserveKey)
+ reservekey.KeepKey();
+
return true;
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 92ad098486..a7fc05b62d 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -780,7 +780,7 @@ public:
* Insert additional inputs into the transaction by
* calling CreateTransaction();
*/
- bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, const CTxDestination& destChange = CNoDestination());
+ bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, bool keepReserveKey = true, const CTxDestination& destChange = CNoDestination());
/**
* Create a new transaction paying the recipients with a set of coins
@@ -825,6 +825,10 @@ public:
std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
isminetype IsMine(const CTxIn& txin) const;
+ /**
+ * Returns amount of debit if the input matches the
+ * filter, otherwise returns 0
+ */
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
isminetype IsMine(const CTxOut& txout) const;
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
@@ -834,6 +838,8 @@ public:
/** should probably be renamed to IsRelevantToMe */
bool IsFromMe(const CTransaction& tx) const;
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;
+ /** Returns whether all of the inputs match the filter */
+ bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
CAmount GetChange(const CTransaction& tx) const;
void SetBestChain(const CBlockLocator& loc);
@@ -885,6 +891,9 @@ public:
//! Get wallet transactions that conflict with given transaction (spend same outputs)
std::set<uint256> GetConflicts(const uint256& txid) const;
+ //! Check if a given transaction has any of its outputs spent by another transaction in the wallet
+ bool HasWalletSpend(const uint256& txid) const;
+
//! Flush wallet (bitdb flush)
void Flush(bool shutdown=false);
@@ -921,6 +930,9 @@ public:
/* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
bool AbandonTransaction(const uint256& hashTx);
+ /** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
+ bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
+
/* Returns the wallets help message */
static std::string GetWalletHelpString(bool showDebug);