aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.clang-tidy4
-rw-r--r--src/Makefile.am38
-rw-r--r--src/Makefile.bench.include10
-rw-r--r--src/Makefile.test.include21
-rw-r--r--src/Makefile.test_fuzz.include1
-rw-r--r--src/addrman.cpp151
-rw-r--r--src/addrman.h26
-rw-r--r--src/addrman_impl.h42
-rw-r--r--src/bench/addrman.cpp2
-rw-r--r--src/bench/checkblock.cpp1
-rw-r--r--src/bench/coin_selection.cpp6
-rw-r--r--src/bench/descriptors.cpp30
-rw-r--r--src/bench/wallet_loading.cpp7
-rw-r--r--src/bitcoin-chainstate.cpp35
-rw-r--r--src/bitcoin-cli.cpp4
-rw-r--r--src/bitcoin-tx.cpp2
-rw-r--r--src/bitcoin-util.cpp2
-rw-r--r--src/bitcoin-wallet.cpp2
-rw-r--r--src/bitcoind.cpp2
-rw-r--r--src/blockfilter.cpp2
-rw-r--r--src/chain.cpp15
-rw-r--r--src/chain.h26
-rw-r--r--src/chainparams.cpp2
-rw-r--r--src/coins.cpp6
-rw-r--r--src/compat/compat.h (renamed from src/compat.h)46
-rw-r--r--src/crc32c/CMakeLists.txt7
-rw-r--r--src/crypto/muhash.cpp4
-rw-r--r--src/cuckoocache.h23
-rw-r--r--src/dbwrapper.cpp19
-rw-r--r--src/dbwrapper.h16
-rw-r--r--src/external_signer.cpp2
-rw-r--r--src/fs.h2
-rw-r--r--src/hash.cpp4
-rw-r--r--src/hash.h36
-rw-r--r--src/httpserver.cpp2
-rw-r--r--src/i2p.cpp2
-rw-r--r--src/i2p.h2
-rw-r--r--src/index/base.cpp68
-rw-r--r--src/index/base.h28
-rw-r--r--src/index/blockfilterindex.cpp50
-rw-r--r--src/index/blockfilterindex.h12
-rw-r--r--src/index/coinstatsindex.cpp69
-rw-r--r--src/index/coinstatsindex.h10
-rw-r--r--src/index/txindex.cpp17
-rw-r--r--src/index/txindex.h4
-rw-r--r--src/init.cpp233
-rw-r--r--src/init/common.cpp2
-rw-r--r--src/interfaces/chain.h34
-rw-r--r--src/interfaces/wallet.h44
-rw-r--r--src/kernel/chain.cpp26
-rw-r--r--src/kernel/chain.h19
-rw-r--r--src/kernel/checks.cpp11
-rw-r--r--src/kernel/checks.h10
-rw-r--r--src/kernel/coinstats.cpp24
-rw-r--r--src/kernel/coinstats.h6
-rw-r--r--src/kernel/mempool_options.h19
-rw-r--r--src/kernel/mempool_persist.cpp189
-rw-r--r--src/kernel/mempool_persist.h28
-rw-r--r--src/kernel/validation_cache_sizes.h20
-rw-r--r--src/key.cpp1
-rw-r--r--src/key.h4
-rw-r--r--src/leveldb/util/env_posix.cc2
-rw-r--r--src/mapport.cpp2
-rw-r--r--src/mempool_args.cpp39
-rw-r--r--src/net.cpp77
-rw-r--r--src/net.h54
-rw-r--r--src/net_processing.cpp282
-rw-r--r--src/net_processing.h1
-rw-r--r--src/netaddress.h2
-rw-r--r--src/netbase.cpp2
-rw-r--r--src/netbase.h2
-rw-r--r--src/node/blockstorage.cpp12
-rw-r--r--src/node/blockstorage.h2
-rw-r--r--src/node/chainstate.cpp114
-rw-r--r--src/node/chainstate.h85
-rw-r--r--src/node/interfaces.cpp106
-rw-r--r--src/node/mempool_args.cpp99
-rw-r--r--src/node/mempool_args.h (renamed from src/mempool_args.h)13
-rw-r--r--src/node/mempool_persist_args.cpp23
-rw-r--r--src/node/mempool_persist_args.h25
-rw-r--r--src/node/psbt.cpp2
-rw-r--r--src/node/validation_cache_args.cpp34
-rw-r--r--src/node/validation_cache_args.h17
-rw-r--r--src/outputtype.cpp2
-rw-r--r--src/policy/fees.cpp16
-rw-r--r--src/policy/fees.h6
-rw-r--r--src/policy/policy.cpp13
-rw-r--r--src/policy/policy.h8
-rw-r--r--src/policy/settings.cpp5
-rw-r--r--src/policy/settings.h29
-rw-r--r--src/primitives/transaction.cpp7
-rw-r--r--src/primitives/transaction.h14
-rw-r--r--src/protocol.h11
-rw-r--r--src/psbt.h12
-rw-r--r--src/pubkey.cpp7
-rw-r--r--src/pubkey.h4
-rw-r--r--src/qt/addresstablemodel.cpp2
-rw-r--r--src/qt/bitcoin.cpp2
-rw-r--r--src/qt/bitcoingui.cpp14
-rw-r--r--src/qt/bitcoinstrings.cpp42
-rw-r--r--src/qt/guiutil.cpp2
-rw-r--r--src/qt/locale/bitcoin_en.ts548
-rw-r--r--src/qt/locale/bitcoin_en.xlf3494
-rw-r--r--src/qt/main.cpp2
-rw-r--r--src/qt/optionsdialog.cpp1
-rw-r--r--src/qt/overviewpage.cpp23
-rw-r--r--src/qt/overviewpage.h1
-rw-r--r--src/qt/rpcconsole.cpp2
-rw-r--r--src/qt/sendcoinsdialog.cpp12
-rw-r--r--src/qt/sendcoinsdialog.h2
-rw-r--r--src/qt/test/test_main.cpp2
-rw-r--r--src/qt/test/wallettests.cpp28
-rw-r--r--src/qt/walletcontroller.cpp27
-rw-r--r--src/qt/walletframe.cpp8
-rw-r--r--src/qt/walletmodel.cpp29
-rw-r--r--src/qt/walletmodel.h8
-rw-r--r--src/random.cpp2
-rw-r--r--src/random.h17
-rw-r--r--src/randomenv.cpp2
-rw-r--r--src/rest.cpp41
-rw-r--r--src/rpc/blockchain.cpp30
-rw-r--r--src/rpc/blockchain.h2
-rw-r--r--src/rpc/client.cpp2
-rw-r--r--src/rpc/fees.cpp5
-rw-r--r--src/rpc/mempool.cpp23
-rw-r--r--src/rpc/mining.cpp4
-rw-r--r--src/rpc/net.cpp37
-rw-r--r--src/rpc/node.cpp6
-rw-r--r--src/rpc/output_script.cpp5
-rw-r--r--src/rpc/rawtransaction.cpp40
-rw-r--r--src/rpc/rawtransaction_util.cpp7
-rw-r--r--src/rpc/rawtransaction_util.h3
-rw-r--r--src/rpc/request.cpp6
-rw-r--r--src/script/descriptor.cpp46
-rw-r--r--src/script/interpreter.cpp32
-rw-r--r--src/script/interpreter.h6
-rw-r--r--src/script/script.h2
-rw-r--r--src/script/sigcache.cpp18
-rw-r--r--src/script/sigcache.h11
-rw-r--r--src/script/sign.cpp26
-rw-r--r--src/script/sign.h6
-rw-r--r--src/script/standard.cpp11
-rw-r--r--src/script/standard.h11
-rw-r--r--src/serialize.h23
-rw-r--r--src/streams.h69
-rw-r--r--src/test/addrman_tests.cpp26
-rw-r--r--src/test/bip32_tests.cpp18
-rw-r--r--src/test/blockfilter_index_tests.cpp11
-rw-r--r--src/test/coinstatsindex_tests.cpp16
-rw-r--r--src/test/denialofservice_tests.cpp44
-rw-r--r--src/test/descriptor_tests.cpp7
-rw-r--r--src/test/flatfile_tests.cpp12
-rw-r--r--src/test/fuzz/addrman.cpp18
-rw-r--r--src/test/fuzz/autofile.cpp4
-rw-r--r--src/test/fuzz/chain.cpp3
-rw-r--r--src/test/fuzz/integer.cpp3
-rw-r--r--src/test/fuzz/key.cpp6
-rw-r--r--src/test/fuzz/load_external_block_file.cpp11
-rw-r--r--src/test/fuzz/mempool_utils.h19
-rw-r--r--src/test/fuzz/net.cpp1
-rw-r--r--src/test/fuzz/parse_univalue.cpp2
-rw-r--r--src/test/fuzz/policy_estimator.cpp2
-rw-r--r--src/test/fuzz/policy_estimator_io.cpp2
-rw-r--r--src/test/fuzz/rbf.cpp2
-rw-r--r--src/test/fuzz/script.cpp3
-rw-r--r--src/test/fuzz/script_sigcache.cpp11
-rw-r--r--src/test/fuzz/transaction.cpp5
-rw-r--r--src/test/fuzz/tx_pool.cpp31
-rw-r--r--src/test/fuzz/txorphan.cpp22
-rw-r--r--src/test/fuzz/util.cpp6
-rw-r--r--src/test/fuzz/util.h17
-rw-r--r--src/test/fuzz/utxo_snapshot.cpp4
-rw-r--r--src/test/fuzz/validation_load_mempool.cpp17
-rw-r--r--src/test/miner_tests.cpp16
-rw-r--r--src/test/miniscript_tests.cpp2
-rw-r--r--src/test/multisig_tests.cpp22
-rw-r--r--src/test/net_tests.cpp25
-rw-r--r--src/test/netbase_tests.cpp18
-rw-r--r--src/test/random_tests.cpp10
-rw-r--r--src/test/rbf_tests.cpp230
-rw-r--r--src/test/result_tests.cpp96
-rw-r--r--src/test/rpc_tests.cpp4
-rw-r--r--src/test/script_p2sh_tests.cpp14
-rw-r--r--src/test/script_tests.cpp26
-rw-r--r--src/test/skiplist_tests.cpp6
-rw-r--r--src/test/sock_tests.cpp2
-rw-r--r--src/test/system_tests.cpp5
-rw-r--r--src/test/transaction_tests.cpp22
-rw-r--r--src/test/txindex_tests.cpp5
-rw-r--r--src/test/txvalidationcache_tests.cpp5
-rw-r--r--src/test/util/chainstate.h6
-rw-r--r--src/test/util/net.cpp5
-rw-r--r--src/test/util/net.h3
-rw-r--r--src/test/util/setup_common.cpp53
-rw-r--r--src/test/util/wallet.cpp6
-rw-r--r--src/test/util_tests.cpp16
-rw-r--r--src/test/validation_chainstate_tests.cpp11
-rw-r--r--src/test/validation_chainstatemanager_tests.cpp10
-rw-r--r--src/test/validation_flush_tests.cpp11
-rw-r--r--src/threadinterrupt.cpp12
-rw-r--r--src/threadinterrupt.h5
-rw-r--r--src/timedata.h7
-rw-r--r--src/torcontrol.cpp2
-rw-r--r--src/txdb.cpp2
-rw-r--r--src/txdb.h1
-rw-r--r--src/txmempool.cpp22
-rw-r--r--src/txmempool.h32
-rw-r--r--src/txorphanage.cpp4
-rw-r--r--src/txorphanage.h2
-rw-r--r--src/univalue/include/univalue.h103
-rw-r--r--src/univalue/lib/univalue.cpp70
-rw-r--r--src/univalue/lib/univalue_get.cpp19
-rw-r--r--src/univalue/sources.mk9
-rw-r--r--src/univalue/test/.gitignore1
-rw-r--r--src/univalue/test/no_nul.cpp8
-rw-r--r--src/univalue/test/object.cpp119
-rw-r--r--src/univalue/test/unitester.cpp8
-rw-r--r--src/util/asmap.cpp2
-rw-r--r--src/util/message.cpp2
-rw-r--r--src/util/result.h87
-rw-r--r--src/util/sock.cpp2
-rw-r--r--src/util/sock.h2
-rw-r--r--src/util/string.cpp9
-rw-r--r--src/util/string.h2
-rw-r--r--src/util/system.cpp18
-rw-r--r--src/util/system.h4
-rw-r--r--src/util/time.cpp2
-rw-r--r--src/util/time.h4
-rw-r--r--src/validation.cpp251
-rw-r--r--src/validation.h55
-rw-r--r--src/wallet/bdb.cpp1
-rw-r--r--src/wallet/coinselection.h2
-rw-r--r--src/wallet/dump.cpp4
-rw-r--r--src/wallet/external_signer_scriptpubkeyman.cpp3
-rw-r--r--src/wallet/feebumper.cpp6
-rw-r--r--src/wallet/fees.cpp2
-rw-r--r--src/wallet/interfaces.cpp39
-rw-r--r--src/wallet/receive.cpp74
-rw-r--r--src/wallet/receive.h6
-rw-r--r--src/wallet/rpc/addresses.cpp38
-rw-r--r--src/wallet/rpc/backup.cpp60
-rw-r--r--src/wallet/rpc/coins.cpp18
-rw-r--r--src/wallet/rpc/encrypt.cpp14
-rw-r--r--src/wallet/rpc/signmessage.cpp2
-rw-r--r--src/wallet/rpc/spend.cpp52
-rw-r--r--src/wallet/rpc/transactions.cpp18
-rw-r--r--src/wallet/rpc/wallet.cpp126
-rw-r--r--src/wallet/scriptpubkeyman.cpp72
-rw-r--r--src/wallet/scriptpubkeyman.h14
-rw-r--r--src/wallet/spend.cpp232
-rw-r--r--src/wallet/spend.h71
-rw-r--r--src/wallet/test/availablecoins_tests.cpp105
-rw-r--r--src/wallet/test/coinselector_tests.cpp268
-rw-r--r--src/wallet/test/fuzz/notifications.cpp23
-rw-r--r--src/wallet/test/spend_tests.cpp2
-rw-r--r--src/wallet/test/wallet_tests.cpp129
-rw-r--r--src/wallet/wallet.cpp141
-rw-r--r--src/wallet/wallet.h24
258 files changed, 6266 insertions, 4499 deletions
diff --git a/src/.clang-tidy b/src/.clang-tidy
index e9807d4cb7..b9371b147b 100644
--- a/src/.clang-tidy
+++ b/src/.clang-tidy
@@ -1,13 +1,17 @@
Checks: '
-*,
bugprone-argument-comment,
+misc-unused-using-decls,
modernize-use-default-member-init,
modernize-use-nullptr,
readability-redundant-declaration,
+readability-redundant-string-init,
'
WarningsAsErrors: '
bugprone-argument-comment,
+misc-unused-using-decls,
modernize-use-default-member-init,
modernize-use-nullptr,
readability-redundant-declaration,
+readability-redundant-string-init,
'
diff --git a/src/Makefile.am b/src/Makefile.am
index d293775fc3..18c6c25b96 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -133,13 +133,12 @@ BITCOIN_CORE_H = \
clientversion.h \
coins.h \
common/bloom.h \
- compat.h \
compat/assumptions.h \
compat/byteswap.h \
+ compat/compat.h \
compat/cpuid.h \
compat/endian.h \
compressor.h \
- node/connection_types.h \
consensus/consensus.h \
consensus/tx_check.h \
consensus/tx_verify.h \
@@ -149,7 +148,6 @@ BITCOIN_CORE_H = \
dbwrapper.h \
deploymentinfo.h \
deploymentstatus.h \
- node/eviction.h \
external_signer.h \
flatfile.h \
fs.h \
@@ -171,18 +169,20 @@ BITCOIN_CORE_H = \
interfaces/ipc.h \
interfaces/node.h \
interfaces/wallet.h \
+ kernel/chain.h \
kernel/chainstatemanager_opts.h \
kernel/checks.h \
kernel/coinstats.h \
kernel/context.h \
kernel/mempool_limits.h \
kernel/mempool_options.h \
+ kernel/mempool_persist.h \
+ kernel/validation_cache_sizes.h \
key.h \
key_io.h \
logging.h \
logging/timer.h \
mapport.h \
- mempool_args.h \
memusage.h \
merkleblock.h \
net.h \
@@ -197,13 +197,18 @@ BITCOIN_CORE_H = \
node/caches.h \
node/chainstate.h \
node/coin.h \
+ node/connection_types.h \
node/context.h \
+ node/eviction.h \
+ node/interface_ui.h \
+ node/mempool_args.h \
+ node/mempool_persist_args.h \
node/miner.h \
node/minisketchwrapper.h \
node/psbt.h \
node/transaction.h \
- node/interface_ui.h \
node/utxo_snapshot.h \
+ node/validation_cache_args.h \
noui.h \
outputtype.h \
policy/feerate.h \
@@ -363,14 +368,15 @@ libbitcoin_node_a_SOURCES = \
index/coinstatsindex.cpp \
index/txindex.cpp \
init.cpp \
+ kernel/chain.cpp \
kernel/checks.cpp \
kernel/coinstats.cpp \
kernel/context.cpp \
+ kernel/mempool_persist.cpp \
mapport.cpp \
- mempool_args.cpp \
net.cpp \
- netgroup.cpp \
net_processing.cpp \
+ netgroup.cpp \
node/blockstorage.cpp \
node/caches.cpp \
node/chainstate.cpp \
@@ -378,12 +384,15 @@ libbitcoin_node_a_SOURCES = \
node/connection_types.cpp \
node/context.cpp \
node/eviction.cpp \
+ node/interface_ui.cpp \
node/interfaces.cpp \
+ node/mempool_args.cpp \
+ node/mempool_persist_args.cpp \
node/miner.cpp \
node/minisketchwrapper.cpp \
node/psbt.cpp \
node/transaction.cpp \
- node/interface_ui.cpp \
+ node/validation_cache_args.cpp \
noui.cpp \
policy/fees.cpp \
policy/fees_args.cpp \
@@ -396,8 +405,8 @@ libbitcoin_node_a_SOURCES = \
rpc/fees.cpp \
rpc/mempool.cpp \
rpc/mining.cpp \
- rpc/node.cpp \
rpc/net.cpp \
+ rpc/node.cpp \
rpc/output_script.cpp \
rpc/rawtransaction.cpp \
rpc/server.cpp \
@@ -878,9 +887,11 @@ libbitcoinkernel_la_SOURCES = \
flatfile.cpp \
fs.cpp \
hash.cpp \
+ kernel/chain.cpp \
kernel/checks.cpp \
kernel/coinstats.cpp \
kernel/context.cpp \
+ kernel/mempool_persist.cpp \
key.cpp \
logging.cpp \
node/blockstorage.cpp \
@@ -1054,6 +1065,15 @@ nodist_libbitcoin_ipc_a_SOURCES = $(libbitcoin_ipc_mpgen_output)
CLEANFILES += $(libbitcoin_ipc_mpgen_output)
endif
+%.raw.h: %.raw
+ @$(MKDIR_P) $(@D)
+ @{ \
+ echo "static unsigned const char $(*F)_raw[] = {" && \
+ $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
+ echo "};"; \
+ } > "$@.new" && mv -f "$@.new" "$@"
+ @echo "Generated $@"
+
include Makefile.minisketch.include
include Makefile.crc32c.include
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 532f668668..a23d872250 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -27,6 +27,7 @@ bench_bench_bitcoin_SOURCES = \
bench/crypto_hash.cpp \
bench/data.cpp \
bench/data.h \
+ bench/descriptors.cpp \
bench/duplicate_inputs.cpp \
bench/examples.cpp \
bench/gcs_filter.cpp \
@@ -93,12 +94,3 @@ bench: $(BENCH_BINARY) FORCE
bitcoin_bench_clean : FORCE
rm -f $(CLEAN_BITCOIN_BENCH) $(bench_bench_bitcoin_OBJECTS) $(BENCH_BINARY)
-
-%.raw.h: %.raw
- @$(MKDIR_P) $(@D)
- @{ \
- echo "static unsigned const char $(*F)_raw[] = {" && \
- $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
- echo "};"; \
- } > "$@.new" && mv -f "$@.new" "$@"
- @echo "Generated $@"
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index b806b62d5b..75a404c50a 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -117,7 +117,9 @@ BITCOIN_TESTS =\
test/prevector_tests.cpp \
test/raii_event_tests.cpp \
test/random_tests.cpp \
+ test/rbf_tests.cpp \
test/rest_tests.cpp \
+ test/result_tests.cpp \
test/reverselock_tests.cpp \
test/rpc_tests.cpp \
test/sanity_tests.cpp \
@@ -167,6 +169,7 @@ BITCOIN_TESTS += \
wallet/test/wallet_crypto_tests.cpp \
wallet/test/wallet_transaction_tests.cpp \
wallet/test/coinselector_tests.cpp \
+ wallet/test/availablecoins_tests.cpp \
wallet/test/init_tests.cpp \
wallet/test/ismine_tests.cpp \
wallet/test/scriptpubkeyman_tests.cpp
@@ -336,7 +339,7 @@ nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
$(BITCOIN_TESTS): $(GENERATED_TEST_FILES)
-CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno test/fuzz/*.gcda test/fuzz/*.gcno test/util/*.gcda test/util/*.gcno $(GENERATED_TEST_FILES) $(BITCOIN_TESTS:=.log)
+CLEAN_BITCOIN_TEST = test/*.gcda test/*.gcno test/fuzz/*.gcda test/fuzz/*.gcno test/util/*.gcda test/util/*.gcno $(GENERATED_TEST_FILES) $(addsuffix .log,$(basename $(BITCOIN_TESTS)))
CLEANFILES += $(CLEAN_BITCOIN_TEST)
@@ -373,7 +376,7 @@ endif
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check
if ENABLE_TESTS
-UNIVALUE_TESTS = univalue/test/object univalue/test/unitester univalue/test/no_nul
+UNIVALUE_TESTS = univalue/test/object univalue/test/unitester
noinst_PROGRAMS += $(UNIVALUE_TESTS)
TESTS += $(UNIVALUE_TESTS)
@@ -382,11 +385,6 @@ univalue_test_unitester_LDADD = $(LIBUNIVALUE)
univalue_test_unitester_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) -DJSON_TEST_SRC=\"$(srcdir)/$(UNIVALUE_TEST_DATA_DIR_INT)\"
univalue_test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
-univalue_test_no_nul_SOURCES = $(UNIVALUE_TEST_NO_NUL_INT)
-univalue_test_no_nul_LDADD = $(LIBUNIVALUE)
-univalue_test_no_nul_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT)
-univalue_test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
-
univalue_test_object_SOURCES = $(UNIVALUE_TEST_OBJECT_INT)
univalue_test_object_LDADD = $(LIBUNIVALUE)
univalue_test_object_CPPFLAGS = -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT)
@@ -417,12 +415,3 @@ endif
echo "};};"; \
} > "$@.new" && mv -f "$@.new" "$@"
@echo "Generated $@"
-
-%.raw.h: %.raw
- @$(MKDIR_P) $(@D)
- @{ \
- echo "static unsigned const char $(*F)_raw[] = {" && \
- $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \
- echo "};"; \
- } > "$@.new" && mv -f "$@.new" "$@"
- @echo "Generated $@"
diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include
index 8922dda3ad..b43816636f 100644
--- a/src/Makefile.test_fuzz.include
+++ b/src/Makefile.test_fuzz.include
@@ -10,6 +10,7 @@ EXTRA_LIBRARIES += \
TEST_FUZZ_H = \
test/fuzz/fuzz.h \
test/fuzz/FuzzedDataProvider.h \
+ test/fuzz/mempool_utils.h \
test/fuzz/util.h
libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 204bb544c5..f16ff2230b 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -14,10 +14,10 @@
#include <random.h>
#include <serialize.h>
#include <streams.h>
-#include <timedata.h>
#include <tinyformat.h>
#include <uint256.h>
#include <util/check.h>
+#include <util/time.h>
#include <cmath>
#include <optional>
@@ -29,19 +29,19 @@ static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP{64};
/** Maximum number of times an address can occur in the new table */
static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS{8};
/** How old addresses can maximally be */
-static constexpr int64_t ADDRMAN_HORIZON_DAYS{30};
+static constexpr auto ADDRMAN_HORIZON{30 * 24h};
/** After how many failed attempts we give up on a new node */
static constexpr int32_t ADDRMAN_RETRIES{3};
/** How many successive failures are allowed ... */
static constexpr int32_t ADDRMAN_MAX_FAILURES{10};
-/** ... in at least this many days */
-static constexpr int64_t ADDRMAN_MIN_FAIL_DAYS{7};
+/** ... in at least this duration */
+static constexpr auto ADDRMAN_MIN_FAIL{7 * 24h};
/** How recent a successful connection should be before we allow an address to be evicted from tried */
-static constexpr int64_t ADDRMAN_REPLACEMENT_HOURS{4};
+static constexpr auto ADDRMAN_REPLACEMENT{4h};
/** The maximum number of tried addr collisions to store */
static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10};
-/** The maximum time we'll spend trying to resolve a tried table collision, in seconds */
-static constexpr int64_t ADDRMAN_TEST_WINDOW{40*60}; // 40 minutes
+/** The maximum time we'll spend trying to resolve a tried table collision */
+static constexpr auto ADDRMAN_TEST_WINDOW{40min};
int AddrInfo::GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const
{
@@ -64,36 +64,39 @@ int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int nBucket) con
return hash1 % ADDRMAN_BUCKET_SIZE;
}
-bool AddrInfo::IsTerrible(int64_t nNow) const
+bool AddrInfo::IsTerrible(NodeSeconds now) const
{
- if (nNow - nLastTry <= 60) { // never remove things tried in the last minute
+ if (now - m_last_try <= 1min) { // never remove things tried in the last minute
return false;
}
- if (nTime > nNow + 10 * 60) // came in a flying DeLorean
+ if (nTime > now + 10min) { // came in a flying DeLorean
return true;
+ }
- if (nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) { // not seen in recent history
+ if (now - nTime > ADDRMAN_HORIZON) { // not seen in recent history
return true;
}
- if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success
+ if (TicksSinceEpoch<std::chrono::seconds>(m_last_success) == 0 && nAttempts >= ADDRMAN_RETRIES) { // tried N times and never a success
return true;
+ }
- if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week
+ if (now - m_last_success > ADDRMAN_MIN_FAIL && nAttempts >= ADDRMAN_MAX_FAILURES) { // N successive failures in the last week
return true;
+ }
return false;
}
-double AddrInfo::GetChance(int64_t nNow) const
+double AddrInfo::GetChance(NodeSeconds now) const
{
double fChance = 1.0;
- int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
// deprioritize very recent attempts away
- if (nSinceLastTry < 60 * 10)
+ if (now - m_last_try < 10min) {
fChance *= 0.01;
+ }
// deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
fChance *= pow(0.66, std::min(nAttempts, 8));
@@ -540,7 +543,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
info.fInTried = true;
}
-bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
+bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty)
{
AssertLockHeld(cs);
@@ -552,15 +555,15 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
// Do not set a penalty for a source's self-announcement
if (addr == source) {
- nTimePenalty = 0;
+ time_penalty = 0s;
}
if (pinfo) {
// periodically update nTime
- bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
- int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
- if (pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty) {
- pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
+ const bool currently_online{NodeClock::now() - addr.nTime < 24h};
+ const auto update_interval{currently_online ? 1h : 24h};
+ if (pinfo->nTime < addr.nTime - update_interval - time_penalty) {
+ pinfo->nTime = std::max(NodeSeconds{0s}, addr.nTime - time_penalty);
}
// add services
@@ -587,7 +590,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
return false;
} else {
pinfo = Create(addr, source, &nId);
- pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
+ pinfo->nTime = std::max(NodeSeconds{0s}, pinfo->nTime - time_penalty);
nNew++;
}
@@ -617,13 +620,13 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
return fInsert;
}
-bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
+bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, NodeSeconds time)
{
AssertLockHeld(cs);
int nId;
- nLastGood = nTime;
+ m_last_good = time;
AddrInfo* pinfo = Find(addr, &nId);
@@ -633,8 +636,8 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
AddrInfo& info = *pinfo;
// update info
- info.nLastSuccess = nTime;
- info.nLastTry = nTime;
+ info.m_last_success = time;
+ info.m_last_try = time;
info.nAttempts = 0;
// nTime is not updated here, to avoid leaking information about
// currently-connected peers.
@@ -671,11 +674,11 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
}
}
-bool AddrManImpl::Add_(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty)
+bool AddrManImpl::Add_(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{
int added{0};
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) {
- added += AddSingle(*it, source, nTimePenalty) ? 1 : 0;
+ added += AddSingle(*it, source, time_penalty) ? 1 : 0;
}
if (added > 0) {
LogPrint(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToString(), nTried, nNew);
@@ -683,7 +686,7 @@ bool AddrManImpl::Add_(const std::vector<CAddress> &vAddr, const CNetAddr& sourc
return added > 0;
}
-void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
+void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, NodeSeconds time)
{
AssertLockHeld(cs);
@@ -696,14 +699,14 @@ void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, int64_t nTi
AddrInfo& info = *pinfo;
// update info
- info.nLastTry = nTime;
- if (fCountFailure && info.nLastCountAttempt < nLastGood) {
- info.nLastCountAttempt = nTime;
+ info.m_last_try = time;
+ if (fCountFailure && info.m_last_count_attempt < m_last_good) {
+ info.m_last_count_attempt = time;
info.nAttempts++;
}
}
-std::pair<CAddress, int64_t> AddrManImpl::Select_(bool newOnly) const
+std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool newOnly) const
{
AssertLockHeld(cs);
@@ -736,7 +739,7 @@ std::pair<CAddress, int64_t> AddrManImpl::Select_(bool newOnly) const
// With probability GetChance() * fChanceFactor, return the entry.
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
LogPrint(BCLog::ADDRMAN, "Selected %s from tried\n", info.ToString());
- return {info, info.nLastTry};
+ return {info, info.m_last_try};
}
// Otherwise start over with a (likely) different bucket, and increased chance factor.
fChanceFactor *= 1.2;
@@ -764,7 +767,7 @@ std::pair<CAddress, int64_t> AddrManImpl::Select_(bool newOnly) const
// With probability GetChance() * fChanceFactor, return the entry.
if (insecure_rand.randbits(30) < fChanceFactor * info.GetChance() * (1 << 30)) {
LogPrint(BCLog::ADDRMAN, "Selected %s from new\n", info.ToString());
- return {info, info.nLastTry};
+ return {info, info.m_last_try};
}
// Otherwise start over with a (likely) different bucket, and increased chance factor.
fChanceFactor *= 1.2;
@@ -785,7 +788,7 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct
}
// gather a list of random nodes, skipping those of low quality
- const int64_t now{GetAdjustedTime()};
+ const auto now{Now<NodeSeconds>()};
std::vector<CAddress> addresses;
for (unsigned int n = 0; n < vRandom.size(); n++) {
if (addresses.size() >= nNodes)
@@ -810,7 +813,7 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct
return addresses;
}
-void AddrManImpl::Connected_(const CService& addr, int64_t nTime)
+void AddrManImpl::Connected_(const CService& addr, NodeSeconds time)
{
AssertLockHeld(cs);
@@ -823,9 +826,10 @@ void AddrManImpl::Connected_(const CService& addr, int64_t nTime)
AddrInfo& info = *pinfo;
// update info
- int64_t nUpdateInterval = 20 * 60;
- if (nTime - info.nTime > nUpdateInterval)
- info.nTime = nTime;
+ const auto update_interval{20min};
+ if (time - info.nTime > update_interval) {
+ info.nTime = time;
+ }
}
void AddrManImpl::SetServices_(const CService& addr, ServiceFlags nServices)
@@ -870,22 +874,22 @@ void AddrManImpl::ResolveCollisions_()
int id_old = vvTried[tried_bucket][tried_bucket_pos];
AddrInfo& info_old = mapInfo[id_old];
- const auto current_time{GetAdjustedTime()};
+ const auto current_time{Now<NodeSeconds>()};
// Has successfully connected in last X hours
- if (current_time - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) {
+ if (current_time - info_old.m_last_success < ADDRMAN_REPLACEMENT) {
erase_collision = true;
- } else if (current_time - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours
+ } else if (current_time - info_old.m_last_try < ADDRMAN_REPLACEMENT) { // attempted to connect and failed in last X hours
// Give address at least 60 seconds to successfully connect
- if (current_time - info_old.nLastTry > 60) {
+ if (current_time - info_old.m_last_try > 60s) {
LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToString(), info_new.ToString());
// Replaces an existing address already in the tried table with the new address
Good_(info_new, false, current_time);
erase_collision = true;
}
- } else if (current_time - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) {
+ } else if (current_time - info_new.m_last_success > ADDRMAN_TEST_WINDOW) {
// If the collision hasn't resolved in some reasonable amount of time,
// just evict the old entry -- we must not be able to
// connect to it for some reason.
@@ -894,7 +898,7 @@ void AddrManImpl::ResolveCollisions_()
erase_collision = true;
}
} else { // Collision is not actually a collision anymore
- Good_(info_new, false, GetAdjustedTime());
+ Good_(info_new, false, Now<NodeSeconds>());
erase_collision = true;
}
}
@@ -907,7 +911,7 @@ void AddrManImpl::ResolveCollisions_()
}
}
-std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
+std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision_()
{
AssertLockHeld(cs);
@@ -932,7 +936,7 @@ std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
- return {info_old, info_old.nLastTry};
+ return {info_old, info_old.m_last_try};
}
std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& addr)
@@ -990,8 +994,9 @@ int AddrManImpl::CheckAddrman() const
int n = entry.first;
const AddrInfo& info = entry.second;
if (info.fInTried) {
- if (!info.nLastSuccess)
+ if (!TicksSinceEpoch<std::chrono::seconds>(info.m_last_success)) {
return -1;
+ }
if (info.nRefCount)
return -2;
setTried.insert(n);
@@ -1008,10 +1013,12 @@ int AddrManImpl::CheckAddrman() const
}
if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
return -14;
- if (info.nLastTry < 0)
+ if (info.m_last_try < NodeSeconds{0s}) {
return -6;
- if (info.nLastSuccess < 0)
+ }
+ if (info.m_last_success < NodeSeconds{0s}) {
return -8;
+ }
}
if (setTried.size() != (size_t)nTried)
@@ -1067,29 +1074,29 @@ size_t AddrManImpl::size() const
return vRandom.size();
}
-bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
+bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{
LOCK(cs);
Check();
- auto ret = Add_(vAddr, source, nTimePenalty);
+ auto ret = Add_(vAddr, source, time_penalty);
Check();
return ret;
}
-bool AddrManImpl::Good(const CService& addr, int64_t nTime)
+bool AddrManImpl::Good(const CService& addr, NodeSeconds time)
{
LOCK(cs);
Check();
- auto ret = Good_(addr, /*test_before_evict=*/true, nTime);
+ auto ret = Good_(addr, /*test_before_evict=*/true, time);
Check();
return ret;
}
-void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
+void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
{
LOCK(cs);
Check();
- Attempt_(addr, fCountFailure, nTime);
+ Attempt_(addr, fCountFailure, time);
Check();
}
@@ -1101,7 +1108,7 @@ void AddrManImpl::ResolveCollisions()
Check();
}
-std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision()
+std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision()
{
LOCK(cs);
Check();
@@ -1110,7 +1117,7 @@ std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision()
return ret;
}
-std::pair<CAddress, int64_t> AddrManImpl::Select(bool newOnly) const
+std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool newOnly) const
{
LOCK(cs);
Check();
@@ -1128,11 +1135,11 @@ std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct,
return addresses;
}
-void AddrManImpl::Connected(const CService& addr, int64_t nTime)
+void AddrManImpl::Connected(const CService& addr, NodeSeconds time)
{
LOCK(cs);
Check();
- Connected_(addr, nTime);
+ Connected_(addr, time);
Check();
}
@@ -1184,19 +1191,19 @@ size_t AddrMan::size() const
return m_impl->size();
}
-bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
+bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{
- return m_impl->Add(vAddr, source, nTimePenalty);
+ return m_impl->Add(vAddr, source, time_penalty);
}
-bool AddrMan::Good(const CService& addr, int64_t nTime)
+bool AddrMan::Good(const CService& addr, NodeSeconds time)
{
- return m_impl->Good(addr, nTime);
+ return m_impl->Good(addr, time);
}
-void AddrMan::Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
+void AddrMan::Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
{
- m_impl->Attempt(addr, fCountFailure, nTime);
+ m_impl->Attempt(addr, fCountFailure, time);
}
void AddrMan::ResolveCollisions()
@@ -1204,12 +1211,12 @@ void AddrMan::ResolveCollisions()
m_impl->ResolveCollisions();
}
-std::pair<CAddress, int64_t> AddrMan::SelectTriedCollision()
+std::pair<CAddress, NodeSeconds> AddrMan::SelectTriedCollision()
{
return m_impl->SelectTriedCollision();
}
-std::pair<CAddress, int64_t> AddrMan::Select(bool newOnly) const
+std::pair<CAddress, NodeSeconds> AddrMan::Select(bool newOnly) const
{
return m_impl->Select(newOnly);
}
@@ -1219,9 +1226,9 @@ std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std
return m_impl->GetAddr(max_addresses, max_pct, network);
}
-void AddrMan::Connected(const CService& addr, int64_t nTime)
+void AddrMan::Connected(const CService& addr, NodeSeconds time)
{
- m_impl->Connected(addr, nTime);
+ m_impl->Connected(addr, time);
}
void AddrMan::SetServices(const CService& addr, ServiceFlags nServices)
diff --git a/src/addrman.h b/src/addrman.h
index a0063e8a9c..5099c8c7a3 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -10,7 +10,7 @@
#include <netgroup.h>
#include <protocol.h>
#include <streams.h>
-#include <timedata.h>
+#include <util/time.h>
#include <cstdint>
#include <memory>
@@ -107,23 +107,23 @@ public:
*
* @param[in] vAddr Address records to attempt to add.
* @param[in] source The address of the node that sent us these addr records.
- * @param[in] nTimePenalty A "time penalty" to apply to the address record's nTime. If a peer
+ * @param[in] time_penalty A "time penalty" to apply to the address record's nTime. If a peer
* sends us an address record with nTime=n, then we'll add it to our
- * addrman with nTime=(n - nTimePenalty).
+ * addrman with nTime=(n - time_penalty).
* @return true if at least one address is successfully added. */
- bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty = 0);
+ bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty = 0s);
/**
* Mark an address record as accessible and attempt to move it to addrman's tried table.
*
* @param[in] addr Address record to attempt to move to tried table.
- * @param[in] nTime The time that we were last connected to this peer.
+ * @param[in] time The time that we were last connected to this peer.
* @return true if the address is successfully moved from the new table to the tried table.
*/
- bool Good(const CService& addr, int64_t nTime = GetAdjustedTime());
+ bool Good(const CService& addr, NodeSeconds time = Now<NodeSeconds>());
//! Mark an entry as connection attempted to.
- void Attempt(const CService& addr, bool fCountFailure, int64_t nTime = GetAdjustedTime());
+ void Attempt(const CService& addr, bool fCountFailure, NodeSeconds time = Now<NodeSeconds>());
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
void ResolveCollisions();
@@ -133,18 +133,18 @@ public:
* attempting to evict.
*
* @return CAddress The record for the selected tried peer.
- * int64_t The last time we attempted to connect to that peer.
+ * seconds The last time we attempted to connect to that peer.
*/
- std::pair<CAddress, int64_t> SelectTriedCollision();
+ std::pair<CAddress, NodeSeconds> SelectTriedCollision();
/**
* Choose an address to connect to.
*
* @param[in] newOnly Whether to only select addresses from the new table.
* @return CAddress The record for the selected peer.
- * int64_t The last time we attempted to connect to that peer.
+ * seconds The last time we attempted to connect to that peer.
*/
- std::pair<CAddress, int64_t> Select(bool newOnly = false) const;
+ std::pair<CAddress, NodeSeconds> Select(bool newOnly = false) const;
/**
* Return all or many randomly selected addresses, optionally by network.
@@ -166,9 +166,9 @@ public:
* not leak information about currently connected peers.
*
* @param[in] addr The address of the peer we were connected to
- * @param[in] nTime The time that we were last connected to this peer
+ * @param[in] time The time that we were last connected to this peer
*/
- void Connected(const CService& addr, int64_t nTime = GetAdjustedTime());
+ void Connected(const CService& addr, NodeSeconds time = Now<NodeSeconds>());
//! Update an entry's service bits.
void SetServices(const CService& addr, ServiceFlags nServices);
diff --git a/src/addrman_impl.h b/src/addrman_impl.h
index 9d98cdde54..376e79f49f 100644
--- a/src/addrman_impl.h
+++ b/src/addrman_impl.h
@@ -11,7 +11,9 @@
#include <protocol.h>
#include <serialize.h>
#include <sync.h>
+#include <timedata.h>
#include <uint256.h>
+#include <util/time.h>
#include <cstdint>
#include <optional>
@@ -38,16 +40,16 @@ class AddrInfo : public CAddress
{
public:
//! last try whatsoever by us (memory only)
- int64_t nLastTry{0};
+ NodeSeconds m_last_try{0s};
//! last counted attempt (memory only)
- int64_t nLastCountAttempt{0};
+ NodeSeconds m_last_count_attempt{0s};
//! where knowledge about this address first came from
CNetAddr source;
//! last successful connection by us
- int64_t nLastSuccess{0};
+ NodeSeconds m_last_success{0s};
//! connection attempts since last successful attempt
int nAttempts{0};
@@ -64,7 +66,7 @@ public:
SERIALIZE_METHODS(AddrInfo, obj)
{
READWRITEAS(CAddress, obj);
- READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts);
+ READWRITE(obj.source, Using<ChronoFormatter<int64_t>>(obj.m_last_success), obj.nAttempts);
}
AddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
@@ -91,10 +93,10 @@ public:
int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const;
//! Determine whether the statistics about this entry are bad enough so that it can just be deleted
- bool IsTerrible(int64_t nNow = GetAdjustedTime()) const;
+ bool IsTerrible(NodeSeconds now = Now<NodeSeconds>()) const;
//! Calculate the relative chance this entry should be given when selecting nodes to connect to
- double GetChance(int64_t nNow = GetAdjustedTime()) const;
+ double GetChance(NodeSeconds now = Now<NodeSeconds>()) const;
};
class AddrManImpl
@@ -112,26 +114,26 @@ public:
size_t size() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
- bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty)
+ bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
- bool Good(const CService& addr, int64_t nTime)
+ bool Good(const CService& addr, NodeSeconds time)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
- void Attempt(const CService& addr, bool fCountFailure, int64_t nTime)
+ void Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
void ResolveCollisions() EXCLUSIVE_LOCKS_REQUIRED(!cs);
- std::pair<CAddress, int64_t> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs);
+ std::pair<CAddress, NodeSeconds> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs);
- std::pair<CAddress, int64_t> Select(bool newOnly) const
+ std::pair<CAddress, NodeSeconds> Select(bool newOnly) const
EXCLUSIVE_LOCKS_REQUIRED(!cs);
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
EXCLUSIVE_LOCKS_REQUIRED(!cs);
- void Connected(const CService& addr, int64_t nTime)
+ void Connected(const CService& addr, NodeSeconds time)
EXCLUSIVE_LOCKS_REQUIRED(!cs);
void SetServices(const CService& addr, ServiceFlags nServices)
@@ -202,7 +204,7 @@ private:
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
//! last time Good was called (memory only). Initially set to 1 so that "never" is strictly worse.
- int64_t nLastGood GUARDED_BY(cs){1};
+ NodeSeconds m_last_good GUARDED_BY(cs){1s};
//! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
std::set<int> m_tried_collisions;
@@ -233,25 +235,25 @@ private:
/** Attempt to add a single address to addrman's new table.
* @see AddrMan::Add() for parameters. */
- bool AddSingle(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ bool AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
- bool Good_(const CService& addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ bool Good_(const CService& addr, bool test_before_evict, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
- bool Add_(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ bool Add_(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
- void Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ void Attempt_(const CService& addr, bool fCountFailure, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
- std::pair<CAddress, int64_t> Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs);
+ std::pair<CAddress, NodeSeconds> Select_(bool newOnly) const EXCLUSIVE_LOCKS_REQUIRED(cs);
std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
- void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
+ void Connected_(const CService& addr, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
void SetServices_(const CService& addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
- std::pair<CAddress, int64_t> SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
+ std::pair<CAddress, NodeSeconds> SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
std::optional<AddressPosition> FindAddressEntry_(const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(cs);
diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp
index 76300f4db8..f14d1f89b6 100644
--- a/src/bench/addrman.cpp
+++ b/src/bench/addrman.cpp
@@ -43,7 +43,7 @@ static void CreateAddresses()
CAddress ret(CService(addr, port), NODE_NETWORK);
- ret.nTime = GetAdjustedTime();
+ ret.nTime = Now<NodeSeconds>();
return ret;
};
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index 52e5cb743f..53aa470042 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -8,6 +8,7 @@
#include <chainparams.h>
#include <consensus/validation.h>
#include <streams.h>
+#include <util/system.h>
#include <validation.h>
// These are the two major time-sinks which happen after we have fully received
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
index eaefb9b63a..a80ec3703c 100644
--- a/src/bench/coin_selection.cpp
+++ b/src/bench/coin_selection.cpp
@@ -56,10 +56,10 @@ static void CoinSelection(benchmark::Bench& bench)
addCoin(3 * COIN, wallet, wtxs);
// Create coins
- std::vector<COutput> coins;
+ wallet::CoinsResult available_coins;
for (const auto& wtx : wtxs) {
const auto txout = wtx->tx->vout.at(0);
- coins.emplace_back(COutPoint(wtx->GetHash(), 0), txout, /*depth=*/6 * 24, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/true, /*solvable=*/true, /*safe=*/true, wtx->GetTxTime(), /*from_me=*/true, /*fees=*/ 0);
+ available_coins.bech32.emplace_back(COutPoint(wtx->GetHash(), 0), txout, /*depth=*/6 * 24, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/true, /*solvable=*/true, /*safe=*/true, wtx->GetTxTime(), /*from_me=*/true, /*fees=*/ 0);
}
const CoinEligibilityFilter filter_standard(1, 6, 0);
@@ -76,7 +76,7 @@ static void CoinSelection(benchmark::Bench& bench)
/*avoid_partial=*/ false,
};
bench.run([&] {
- auto result = AttemptSelection(wallet, 1003 * COIN, filter_standard, coins, coin_selection_params);
+ auto result = AttemptSelection(wallet, 1003 * COIN, filter_standard, available_coins, coin_selection_params, /*allow_mixed_output_types=*/true);
assert(result);
assert(result->GetSelectedValue() == 1003 * COIN);
assert(result->GetInputSet().size() == 2);
diff --git a/src/bench/descriptors.cpp b/src/bench/descriptors.cpp
new file mode 100644
index 0000000000..5c868a8573
--- /dev/null
+++ b/src/bench/descriptors.cpp
@@ -0,0 +1,30 @@
+// Copyright (c) 2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <bench/bench.h>
+#include <key.h>
+#include <script/descriptor.h>
+#include <script/standard.h>
+
+#include <string>
+#include <utility>
+
+static void ExpandDescriptor(benchmark::Bench& bench)
+{
+ const auto desc_str = "sh(wsh(multi(16,03669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600,0362a74e399c39ed5593852a30147f2959b56bb827dfa3e60e464b02ccf87dc5e8,0261345b53de74a4d721ef877c255429961b7e43714171ac06168d7e08c542a8b8,02da72e8b46901a65d4374fe6315538d8f368557dda3a1dcf9ea903f3afe7314c8,0318c82dd0b53fd3a932d16e0ba9e278fcc937c582d5781be626ff16e201f72286,0297ccef1ef99f9d73dec9ad37476ddb232f1238aff877af19e72ba04493361009,02e502cfd5c3f972fe9a3e2a18827820638f96b6f347e54d63deb839011fd5765d,03e687710f0e3ebe81c1037074da939d409c0025f17eb86adb9427d28f0f7ae0e9,02c04d3a5274952acdbc76987f3184b346a483d43be40874624b29e3692c1df5af,02ed06e0f418b5b43a7ec01d1d7d27290fa15f75771cb69b642a51471c29c84acd,036d46073cbb9ffee90473f3da429abc8de7f8751199da44485682a989a4bebb24,02f5d1ff7c9029a80a4e36b9a5497027ef7f3e73384a4a94fbfe7c4e9164eec8bc,02e41deffd1b7cce11cde209a781adcffdabd1b91c0ba0375857a2bfd9302419f3,02d76625f7956a7fc505ab02556c23ee72d832f1bac391bcd2d3abce5710a13d06,0399eb0a5487515802dc14544cf10b3666623762fbed2ec38a3975716e2c29c232)))";
+ const std::pair<int64_t, int64_t> range = {0, 1000};
+ FlatSigningProvider provider;
+ std::string error;
+ auto desc = Parse(desc_str, provider, error);
+
+ bench.run([&] {
+ for (int i = range.first; i <= range.second; ++i) {
+ std::vector<CScript> scripts;
+ bool success = desc->Expand(i, provider, scripts, provider);
+ assert(success);
+ }
+ });
+}
+
+BENCHMARK(ExpandDescriptor);
diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp
index d258d7a29e..27e4dd015d 100644
--- a/src/bench/wallet_loading.cpp
+++ b/src/bench/wallet_loading.cpp
@@ -19,8 +19,6 @@
using wallet::CWallet;
using wallet::DatabaseFormat;
using wallet::DatabaseOptions;
-using wallet::ISMINE_SPENDABLE;
-using wallet::MakeWalletDatabase;
using wallet::TxStateInactive;
using wallet::WALLET_FLAG_DESCRIPTORS;
using wallet::WalletContext;
@@ -47,11 +45,8 @@ static void BenchUnloadWallet(std::shared_ptr<CWallet>&& wallet)
static void AddTx(CWallet& wallet)
{
- const auto& dest = wallet.GetNewDestination(OutputType::BECH32, "");
- assert(dest.HasRes());
-
CMutableTransaction mtx;
- mtx.vout.push_back({COIN, GetScriptForDestination(dest.GetObj())});
+ mtx.vout.push_back({COIN, GetScriptForDestination(*Assert(wallet.GetNewDestination(OutputType::BECH32, "")))});
mtx.vin.push_back(CTxIn());
wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInactive{});
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index d53e917aba..fc3f91d492 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -13,11 +13,13 @@
#include <kernel/checks.h>
#include <kernel/context.h>
+#include <kernel/validation_cache_sizes.h>
#include <chainparams.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <node/blockstorage.h>
+#include <node/caches.h>
#include <node/chainstate.h>
#include <scheduler.h>
#include <script/sigcache.h>
@@ -61,8 +63,9 @@ int main(int argc, char* argv[])
// Necessary for CheckInputScripts (eventually called by ProcessNewBlock),
// which will try the script cache first and fall back to actually
// performing the check with the signature cache.
- InitSignatureCache();
- InitScriptExecutionCache();
+ kernel::ValidationCacheSizes validation_cache_sizes{};
+ Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes));
+ Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes));
// SETUP: Scheduling and Background Signals
@@ -83,27 +86,19 @@ int main(int argc, char* argv[])
};
ChainstateManager chainman{chainman_opts};
- auto rv = node::LoadChainstate(false,
- std::ref(chainman),
- nullptr,
- false,
- false,
- 2 << 20,
- 2 << 22,
- (450 << 20) - (2 << 20) - (2 << 22),
- false,
- false,
- []() { return false; });
- if (rv.has_value()) {
+ node::CacheSizes cache_sizes;
+ cache_sizes.block_tree_db = 2 << 20;
+ cache_sizes.coins_db = 2 << 22;
+ cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22);
+ node::ChainstateLoadOptions options;
+ options.check_interrupt = [] { return false; };
+ auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
+ if (status != node::ChainstateLoadStatus::SUCCESS) {
std::cerr << "Failed to load Chain state from your datadir." << std::endl;
goto epilogue;
} else {
- auto maybe_verify_error = node::VerifyLoadedChainstate(std::ref(chainman),
- false,
- false,
- DEFAULT_CHECKBLOCKS,
- DEFAULT_CHECKLEVEL);
- if (maybe_verify_error.has_value()) {
+ std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options);
+ if (status != node::ChainstateLoadStatus::SUCCESS) {
std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl;
goto epilogue;
}
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 0db2b75384..6ce4e05e4d 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -9,7 +9,7 @@
#include <chainparamsbase.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <compat/stdin.h>
#include <policy/feerate.h>
#include <rpc/client.h>
@@ -807,7 +807,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
if (failedToGetAuthCookie) {
throw std::runtime_error(strprintf(
"Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set. See -rpcpassword and -stdinrpcpass. Configuration file: (%s)",
- fs::PathToString(GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)))));
+ fs::PathToString(GetConfigFile(gArgs.GetPathArg("-conf", BITCOIN_CONF_FILENAME)))));
} else {
throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
}
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index e0d5c6e5dc..b006353cb0 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -8,7 +8,7 @@
#include <clientversion.h>
#include <coins.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <core_io.h>
diff --git a/src/bitcoin-util.cpp b/src/bitcoin-util.cpp
index 1739804edb..fb184c0486 100644
--- a/src/bitcoin-util.cpp
+++ b/src/bitcoin-util.cpp
@@ -11,7 +11,7 @@
#include <chainparams.h>
#include <chainparamsbase.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <core_io.h>
#include <streams.h>
#include <util/system.h>
diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp
index 7bec3292a1..a7d49452b0 100644
--- a/src/bitcoin-wallet.cpp
+++ b/src/bitcoin-wallet.cpp
@@ -9,7 +9,7 @@
#include <chainparams.h>
#include <chainparamsbase.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <interfaces/init.h>
#include <key.h>
#include <logging.h>
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index be894e192e..85ba88f6ab 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -9,7 +9,7 @@
#include <chainparams.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <init.h>
#include <interfaces/chain.h>
#include <interfaces/init.h>
diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp
index 1ad6872143..0ff79bb3ca 100644
--- a/src/blockfilter.cpp
+++ b/src/blockfilter.cpp
@@ -148,7 +148,7 @@ bool GCSFilter::MatchAny(const ElementSet& elements) const
const std::string& BlockFilterTypeName(BlockFilterType filter_type)
{
- static std::string unknown_retval = "";
+ static std::string unknown_retval;
auto it = g_filter_types.find(filter_type);
return it != g_filter_types.end() ? it->second : unknown_retval;
}
diff --git a/src/chain.cpp b/src/chain.cpp
index b8158f7b0b..446bb216c2 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chain.h>
+#include <tinyformat.h>
#include <util/time.h>
std::string CBlockFileInfo::ToString() const
@@ -11,11 +12,15 @@ std::string CBlockFileInfo::ToString() const
return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, FormatISO8601Date(nTimeFirst), FormatISO8601Date(nTimeLast));
}
-void CChain::SetTip(CBlockIndex *pindex) {
- if (pindex == nullptr) {
- vChain.clear();
- return;
- }
+std::string CBlockIndex::ToString() const
+{
+ return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
+ pprev, nHeight, hashMerkleRoot.ToString(), GetBlockHash().ToString());
+}
+
+void CChain::SetTip(CBlockIndex& block)
+{
+ CBlockIndex* pindex = &block;
vChain.resize(pindex->nHeight + 1);
while (pindex && vChain[pindex->nHeight] != pindex) {
vChain[pindex->nHeight] = pindex;
diff --git a/src/chain.h b/src/chain.h
index ecc2ae732f..1c5cd3f1f6 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -11,7 +11,6 @@
#include <flatfile.h>
#include <primitives/block.h>
#include <sync.h>
-#include <tinyformat.h>
#include <uint256.h>
#include <vector>
@@ -263,6 +262,7 @@ public:
uint256 GetBlockHash() const
{
+ assert(phashBlock != nullptr);
return *phashBlock;
}
@@ -301,13 +301,7 @@ public:
return pbegin[(pend - pbegin) / 2];
}
- std::string ToString() const
- {
- return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
- pprev, nHeight,
- hashMerkleRoot.ToString(),
- GetBlockHash().ToString());
- }
+ std::string ToString() const;
//! Check whether this block index entry is valid up to the passed validity level.
bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const
@@ -402,7 +396,7 @@ public:
READWRITE(obj.nNonce);
}
- uint256 GetBlockHash() const
+ uint256 ConstructBlockHash() const
{
CBlockHeader block;
block.nVersion = nVersion;
@@ -414,16 +408,8 @@ public:
return block.GetHash();
}
-
- std::string ToString() const
- {
- std::string str = "CDiskBlockIndex(";
- str += CBlockIndex::ToString();
- str += strprintf("\n hashBlock=%s, hashPrev=%s)",
- GetBlockHash().ToString(),
- hashPrev.ToString());
- return str;
- }
+ uint256 GetBlockHash() = delete;
+ std::string ToString() = delete;
};
/** An in-memory indexed chain of blocks. */
@@ -479,7 +465,7 @@ public:
}
/** Set/initialize a chain with a given tip. */
- void SetTip(CBlockIndex* pindex);
+ void SetTip(CBlockIndex& block);
/** Return a CBlockLocator that refers to a block in this chain (by default the tip). */
CBlockLocator GetLocator(const CBlockIndex* pindex = nullptr) const;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 7a7c72ea25..dd7b93234d 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -352,7 +352,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
// message start is defined as the first 4 bytes of the sha256d of the block script
- CHashWriter h(SER_DISK, 0);
+ HashWriter h{};
h << consensus.signet_challenge;
uint256 hash = h.GetHash();
memcpy(pchMessageStart, hash.begin(), 4);
diff --git a/src/coins.cpp b/src/coins.cpp
index 1abdcb54d2..1753d33b71 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -99,9 +99,9 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
TRACE5(utxocache, add,
outpoint.hash.data(),
(uint32_t)outpoint.n,
- (uint32_t)coin.nHeight,
- (int64_t)coin.out.nValue,
- (bool)coin.IsCoinBase());
+ (uint32_t)it->second.coin.nHeight,
+ (int64_t)it->second.coin.out.nValue,
+ (bool)it->second.coin.IsCoinBase());
}
void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coin) {
diff --git a/src/compat.h b/src/compat/compat.h
index 0a44b98b4e..a8e5552c0a 100644
--- a/src/compat.h
+++ b/src/compat/compat.h
@@ -3,21 +3,24 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_COMPAT_H
-#define BITCOIN_COMPAT_H
+#ifndef BITCOIN_COMPAT_COMPAT_H
+#define BITCOIN_COMPAT_COMPAT_H
#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif
+// Windows defines FD_SETSIZE to 64 (see _fd_types.h in mingw-w64),
+// which is too small for our usage, but allows us to redefine it safely.
+// We redefine it to be 1024, to match glibc, see typesizes.h.
#ifdef WIN32
#ifdef FD_SETSIZE
-#undef FD_SETSIZE // prevent redefinition compiler warning
+#undef FD_SETSIZE
#endif
-#define FD_SETSIZE 1024 // max number of fds in fd_set
+#define FD_SETSIZE 1024
#include <winsock2.h>
#include <ws2tcpip.h>
-#include <stdint.h>
+#include <cstdint>
#else
#include <fcntl.h>
#include <sys/mman.h>
@@ -34,49 +37,54 @@
#include <unistd.h>
#endif
+// We map Linux / BSD error functions and codes, to the equivalent
+// Windows definitions, and use the WSA* names throughout our code.
+// Note that glibc defines EWOULDBLOCK as EAGAIN (see errno.h).
#ifndef WIN32
typedef unsigned int SOCKET;
-#include <errno.h>
+#include <cerrno>
#define WSAGetLastError() errno
#define WSAEINVAL EINVAL
-#define WSAEALREADY EALREADY
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAEAGAIN EAGAIN
#define WSAEMSGSIZE EMSGSIZE
#define WSAEINTR EINTR
#define WSAEINPROGRESS EINPROGRESS
#define WSAEADDRINUSE EADDRINUSE
-#define WSAENOTSOCK EBADF
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR -1
#else
-#ifndef WSAEAGAIN
+// WSAEAGAIN doesn't exist on Windows
#ifdef EAGAIN
#define WSAEAGAIN EAGAIN
#else
#define WSAEAGAIN WSAEWOULDBLOCK
#endif
#endif
-#endif
+// Windows doesn't define S_IRUSR or S_IWUSR. We define both
+// here, with the same values as glibc (see stat.h).
#ifdef WIN32
#ifndef S_IRUSR
#define S_IRUSR 0400
#define S_IWUSR 0200
#endif
-#else
+#endif
+
+// Windows defines MAX_PATH as it's maximum path length.
+// We define MAX_PATH for use on non-Windows systems.
+#ifndef WIN32
#define MAX_PATH 1024
#endif
+
+// ssize_t is POSIX, and not present when using MSVC.
#ifdef _MSC_VER
-#if !defined(ssize_t)
-#ifdef _WIN64
-typedef int64_t ssize_t;
-#else
-typedef int32_t ssize_t;
-#endif
-#endif
+#include <BaseTsd.h>
+typedef SSIZE_T ssize_t;
#endif
+// The type of the option value passed to getsockopt & setsockopt
+// differs between Windows and non-Windows.
#ifndef WIN32
typedef void* sockopt_arg_type;
#else
@@ -119,4 +127,4 @@ bool static inline IsSelectableSocket(const SOCKET& s) {
#define MSG_DONTWAIT 0
#endif
-#endif // BITCOIN_COMPAT_H
+#endif // BITCOIN_COMPAT_COMPAT_H
diff --git a/src/crc32c/CMakeLists.txt b/src/crc32c/CMakeLists.txt
index 71692d5796..2f52db104c 100644
--- a/src/crc32c/CMakeLists.txt
+++ b/src/crc32c/CMakeLists.txt
@@ -296,9 +296,10 @@ target_include_directories(crc32c
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
-target_compile_definitions(crc32c
-PRIVATE
- CRC32C_HAVE_CONFIG_H=1
+set_property(
+ TARGET crc32c_arm64 crc32c_sse42 crc32c
+ APPEND
+ PROPERTY COMPILE_DEFINITIONS CRC32C_HAVE_CONFIG_H
)
set_target_properties(crc32c
diff --git a/src/crypto/muhash.cpp b/src/crypto/muhash.cpp
index 57ed357645..7d14b7938e 100644
--- a/src/crypto/muhash.cpp
+++ b/src/crypto/muhash.cpp
@@ -298,7 +298,7 @@ void Num3072::ToBytes(unsigned char (&out)[BYTE_SIZE]) {
Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
unsigned char tmp[Num3072::BYTE_SIZE];
- uint256 hashed_in = (CHashWriter(SER_DISK, 0) << in).GetSHA256();
+ uint256 hashed_in{(HashWriter{} << in).GetSHA256()};
ChaCha20(hashed_in.data(), hashed_in.size()).Keystream(tmp, Num3072::BYTE_SIZE);
Num3072 out{tmp};
@@ -318,7 +318,7 @@ void MuHash3072::Finalize(uint256& out) noexcept
unsigned char data[Num3072::BYTE_SIZE];
m_numerator.ToBytes(data);
- out = (CHashWriter(SER_DISK, 0) << data).GetSHA256();
+ out = (HashWriter{} << data).GetSHA256();
}
MuHash3072& MuHash3072::operator*=(const MuHash3072& mul) noexcept
diff --git a/src/cuckoocache.h b/src/cuckoocache.h
index d0dc61c7e6..61f553806e 100644
--- a/src/cuckoocache.h
+++ b/src/cuckoocache.h
@@ -12,7 +12,9 @@
#include <atomic>
#include <cmath>
#include <cstring>
+#include <limits>
#include <memory>
+#include <optional>
#include <utility>
#include <vector>
@@ -326,7 +328,7 @@ public:
}
/** setup initializes the container to store no more than new_size
- * elements.
+ * elements and no less than 2 elements.
*
* setup should only be called once.
*
@@ -336,8 +338,8 @@ public:
uint32_t setup(uint32_t new_size)
{
// depth_limit must be at least one otherwise errors can occur.
- depth_limit = static_cast<uint8_t>(std::log2(static_cast<float>(std::max((uint32_t)2, new_size))));
size = std::max<uint32_t>(2, new_size);
+ depth_limit = static_cast<uint8_t>(std::log2(static_cast<float>(size)));
table.resize(size);
collection_flags.setup(size);
epoch_flags.resize(size);
@@ -357,12 +359,21 @@ public:
*
* @param bytes the approximate number of bytes to use for this data
* structure
- * @returns the maximum number of elements storable (see setup()
- * documentation for more detail)
+ * @returns A pair of the maximum number of elements storable (see setup()
+ * documentation for more detail) and the approxmiate total size of these
+ * elements in bytes or std::nullopt if the size requested is too large.
*/
- uint32_t setup_bytes(size_t bytes)
+ std::optional<std::pair<uint32_t, size_t>> setup_bytes(size_t bytes)
{
- return setup(bytes/sizeof(Element));
+ size_t requested_num_elems = bytes / sizeof(Element);
+ if (std::numeric_limits<uint32_t>::max() < requested_num_elems) {
+ return std::nullopt;
+ }
+
+ auto num_elems = setup(bytes/sizeof(Element));
+
+ size_t approx_size_bytes = num_elems * sizeof(Element);
+ return std::make_pair(num_elems, approx_size_bytes);
}
/** insert loops at most depth_limit times trying to insert a hash
diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp
index d4a8e4f35a..4dbc839941 100644
--- a/src/dbwrapper.cpp
+++ b/src/dbwrapper.cpp
@@ -4,15 +4,28 @@
#include <dbwrapper.h>
-#include <memory>
+#include <fs.h>
+#include <logging.h>
#include <random.h>
+#include <tinyformat.h>
+#include <util/strencodings.h>
+#include <util/system.h>
+#include <algorithm>
+#include <cassert>
+#include <cstdarg>
+#include <cstdint>
+#include <cstdio>
#include <leveldb/cache.h>
+#include <leveldb/db.h>
#include <leveldb/env.h>
#include <leveldb/filter_policy.h>
#include <leveldb/helpers/memenv/memenv.h>
-#include <stdint.h>
-#include <algorithm>
+#include <leveldb/iterator.h>
+#include <leveldb/options.h>
+#include <leveldb/status.h>
+#include <memory>
+#include <optional>
class CBitcoinLevelDBLogger : public leveldb::Logger {
public:
diff --git a/src/dbwrapper.h b/src/dbwrapper.h
index cef8426d61..665eaa0e98 100644
--- a/src/dbwrapper.h
+++ b/src/dbwrapper.h
@@ -7,14 +7,26 @@
#include <clientversion.h>
#include <fs.h>
+#include <logging.h>
#include <serialize.h>
#include <span.h>
#include <streams.h>
-#include <util/strencodings.h>
-#include <util/system.h>
+#include <cstddef>
+#include <cstdint>
+#include <exception>
#include <leveldb/db.h>
+#include <leveldb/iterator.h>
+#include <leveldb/options.h>
+#include <leveldb/slice.h>
+#include <leveldb/status.h>
#include <leveldb/write_batch.h>
+#include <stdexcept>
+#include <string>
+#include <vector>
+namespace leveldb {
+class Env;
+}
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
diff --git a/src/external_signer.cpp b/src/external_signer.cpp
index d125fe479b..6bab0a856c 100644
--- a/src/external_signer.cpp
+++ b/src/external_signer.cpp
@@ -49,7 +49,7 @@ bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalS
if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true;
}
if (duplicate) break;
- std::string name = "";
+ std::string name;
const UniValue& model_field = find_value(signer, "model");
if (model_field.isStr() && model_field.getValStr() != "") {
name += model_field.getValStr();
diff --git a/src/fs.h b/src/fs.h
index cc55793b95..e8b34319bb 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -9,6 +9,7 @@
#include <cstdio>
#include <filesystem>
+#include <functional>
#include <iomanip>
#include <ios>
#include <ostream>
@@ -199,6 +200,7 @@ bool create_directories(const std::filesystem::path& p, std::error_code& ec) = d
/** Bridge operations to C stdio */
namespace fsbridge {
+ using FopenFn = std::function<FILE*(const fs::path&, const char*)>;
FILE *fopen(const fs::path& p, const char *mode);
/**
diff --git a/src/hash.cpp b/src/hash.cpp
index f58b29e3ba..111b707964 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -86,9 +86,9 @@ uint256 SHA256Uint256(const uint256& input)
return result;
}
-CHashWriter TaggedHash(const std::string& tag)
+HashWriter TaggedHash(const std::string& tag)
{
- CHashWriter writer(SER_GETHASH, 0);
+ HashWriter writer{};
uint256 taghash;
CSHA256().Write((const unsigned char*)tag.data(), tag.size()).Finalize(taghash.begin());
writer << taghash << taghash;
diff --git a/src/hash.h b/src/hash.h
index 0ccef2105f..b1ff3acc7d 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -96,20 +96,12 @@ inline uint160 Hash160(const T1& in1)
}
/** A writer stream (for serialization) that computes a 256-bit hash. */
-class CHashWriter
+class HashWriter
{
private:
CSHA256 ctx;
- const int nType;
- const int nVersion;
public:
-
- CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}
-
- int GetType() const { return nType; }
- int GetVersion() const { return nVersion; }
-
void write(Span<const std::byte> src)
{
ctx.Write(UCharCast(src.data()), src.size());
@@ -144,6 +136,26 @@ public:
return ReadLE64(result.begin());
}
+ template <typename T>
+ HashWriter& operator<<(const T& obj)
+ {
+ ::Serialize(*this, obj);
+ return *this;
+ }
+};
+
+class CHashWriter : public HashWriter
+{
+private:
+ const int nType;
+ const int nVersion;
+
+public:
+ CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {}
+
+ int GetType() const { return nType; }
+ int GetVersion() const { return nVersion; }
+
template<typename T>
CHashWriter& operator<<(const T& obj) {
// Serialize to this stream
@@ -203,12 +215,12 @@ unsigned int MurmurHash3(unsigned int nHashSeed, Span<const unsigned char> vData
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
-/** Return a CHashWriter primed for tagged hashes (as specified in BIP 340).
+/** Return a HashWriter primed for tagged hashes (as specified in BIP 340).
*
* The returned object will have SHA256(tag) written to it twice (= 64 bytes).
* A tagged hash can be computed by feeding the message into this object, and
- * then calling CHashWriter::GetSHA256().
+ * then calling HashWriter::GetSHA256().
*/
-CHashWriter TaggedHash(const std::string& tag);
+HashWriter TaggedHash(const std::string& tag);
#endif // BITCOIN_HASH_H
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
index b8f69b038c..8e00a6278f 100644
--- a/src/httpserver.cpp
+++ b/src/httpserver.cpp
@@ -9,7 +9,7 @@
#include <httpserver.h>
#include <chainparamsbase.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <netbase.h>
#include <node/interface_ui.h>
#include <rpc/protocol.h> // For HTTP status codes
diff --git a/src/i2p.cpp b/src/i2p.cpp
index 8611984555..c45bcc15d2 100644
--- a/src/i2p.cpp
+++ b/src/i2p.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <compat/endian.h>
#include <crypto/sha256.h>
#include <fs.h>
diff --git a/src/i2p.h b/src/i2p.h
index 433fcc3a08..eb0a10103d 100644
--- a/src/i2p.h
+++ b/src/i2p.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_I2P_H
#define BITCOIN_I2P_H
-#include <compat.h>
+#include <compat/compat.h>
#include <fs.h>
#include <netaddress.h>
#include <sync.h>
diff --git a/src/index/base.cpp b/src/index/base.cpp
index 323547900d..1ebe89ef7c 100644
--- a/src/index/base.cpp
+++ b/src/index/base.cpp
@@ -4,11 +4,15 @@
#include <chainparams.h>
#include <index/base.h>
+#include <interfaces/chain.h>
+#include <kernel/chain.h>
#include <node/blockstorage.h>
+#include <node/context.h>
#include <node/interface_ui.h>
#include <shutdown.h>
#include <tinyformat.h>
#include <util/syscall_sandbox.h>
+#include <util/system.h>
#include <util/thread.h>
#include <util/translation.h>
#include <validation.h> // For g_chainman
@@ -31,6 +35,15 @@ static void FatalError(const char* fmt, const Args&... args)
StartShutdown();
}
+CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash)
+{
+ CBlockLocator locator;
+ bool found = chain.findBlock(block_hash, interfaces::FoundBlock().locator(locator));
+ assert(found);
+ assert(!locator.IsNull());
+ return locator;
+}
+
BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate) :
CDBWrapper(path, n_cache_size, f_memory, f_wipe, f_obfuscate)
{}
@@ -49,6 +62,9 @@ void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator
batch.Write(DB_BEST_BLOCK, locator);
}
+BaseIndex::BaseIndex(std::unique_ptr<interfaces::Chain> chain)
+ : m_chain{std::move(chain)} {}
+
BaseIndex::~BaseIndex()
{
Interrupt();
@@ -69,6 +85,10 @@ bool BaseIndex::Init()
} else {
SetBestBlockIndex(m_chainstate->FindForkInGlobalIndex(locator));
}
+
+ // Note: this will latch to true immediately if the user starts up with an empty
+ // datadir and an index enabled. If this is the case, indexation will happen solely
+ // via `BlockConnected` signals until, possibly, the next restart.
m_synced = m_best_block_index.load() == active_chain.Tip();
if (!m_synced) {
bool prune_violation = false;
@@ -175,12 +195,15 @@ void BaseIndex::ThreadSync()
}
CBlock block;
+ interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex);
if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
FatalError("%s: Failed to read block %s from disk",
__func__, pindex->GetBlockHash().ToString());
return;
+ } else {
+ block_info.data = &block;
}
- if (!WriteBlock(block, pindex)) {
+ if (!CustomAppend(block_info)) {
FatalError("%s: Failed to write block %s to index database",
__func__, pindex->GetBlockHash().ToString());
return;
@@ -197,22 +220,20 @@ void BaseIndex::ThreadSync()
bool BaseIndex::Commit()
{
- CDBBatch batch(GetDB());
- if (!CommitInternal(batch) || !GetDB().WriteBatch(batch)) {
- return error("%s: Failed to commit latest %s state", __func__, GetName());
- }
- return true;
-}
-
-bool BaseIndex::CommitInternal(CDBBatch& batch)
-{
- LOCK(cs_main);
// Don't commit anything if we haven't indexed any block yet
// (this could happen if init is interrupted).
- if (m_best_block_index == nullptr) {
- return false;
+ bool ok = m_best_block_index != nullptr;
+ if (ok) {
+ CDBBatch batch(GetDB());
+ ok = CustomCommit(batch);
+ if (ok) {
+ GetDB().WriteBestBlock(batch, GetLocator(*m_chain, m_best_block_index.load()->GetBlockHash()));
+ ok = GetDB().WriteBatch(batch);
+ }
+ }
+ if (!ok) {
+ return error("%s: Failed to commit latest %s state", __func__, GetName());
}
- GetDB().WriteBestBlock(batch, m_chainstate->m_chain.GetLocator(m_best_block_index));
return true;
}
@@ -221,6 +242,10 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
assert(current_tip == m_best_block_index);
assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
+ if (!CustomRewind({current_tip->GetBlockHash(), current_tip->nHeight}, {new_tip->GetBlockHash(), new_tip->nHeight})) {
+ return false;
+ }
+
// In the case of a reorg, ensure persisted block locator is not stale.
// Pruning has a minimum of 288 blocks-to-keep and getting the index
// out of sync may be possible but a users fault.
@@ -268,8 +293,8 @@ void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const
return;
}
}
-
- if (WriteBlock(*block, pindex)) {
+ interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex, block.get());
+ if (CustomAppend(block_info)) {
SetBestBlockIndex(pindex);
} else {
FatalError("%s: Failed to write block %s to index",
@@ -346,13 +371,18 @@ void BaseIndex::Interrupt()
m_interrupt();
}
-bool BaseIndex::Start(CChainState& active_chainstate)
+bool BaseIndex::Start()
{
- m_chainstate = &active_chainstate;
+ // m_chainstate member gives indexing code access to node internals. It is
+ // removed in followup https://github.com/bitcoin/bitcoin/pull/24230
+ m_chainstate = &m_chain->context()->chainman->ActiveChainstate();
// Need to register this ValidationInterface before running Init(), so that
// callbacks are not missed if Init sets m_synced to true.
RegisterValidationInterface(this);
- if (!Init()) {
+ if (!Init()) return false;
+
+ const CBlockIndex* index = m_best_block_index.load();
+ if (!CustomInit(index ? std::make_optional(interfaces::BlockKey{index->GetBlockHash(), index->nHeight}) : std::nullopt)) {
return false;
}
diff --git a/src/index/base.h b/src/index/base.h
index a8f6a18c8d..5a484377e7 100644
--- a/src/index/base.h
+++ b/src/index/base.h
@@ -6,12 +6,16 @@
#define BITCOIN_INDEX_BASE_H
#include <dbwrapper.h>
+#include <interfaces/chain.h>
#include <threadinterrupt.h>
#include <validationinterface.h>
class CBlock;
class CBlockIndex;
class CChainState;
+namespace interfaces {
+class Chain;
+} // namespace interfaces
struct IndexSummary {
std::string name;
@@ -51,6 +55,10 @@ private:
/// Whether the index is in sync with the main chain. The flag is flipped
/// from false to true once, after which point this starts processing
/// ValidationInterface notifications to stay in sync.
+ ///
+ /// Note that this will latch to true *immediately* upon startup if
+ /// `m_chainstate->m_chain` is empty, which will be the case upon startup
+ /// with an empty datadir if, e.g., `-txindex=1` is specified.
std::atomic<bool> m_synced{false};
/// The last block in the chain that the index is in sync with.
@@ -59,6 +67,9 @@ private:
std::thread m_thread_sync;
CThreadInterrupt m_interrupt;
+ /// Read best block locator and check that data needed to sync has not been pruned.
+ bool Init();
+
/// Sync the index with the block index starting from the current best block.
/// Intended to be run in its own thread, m_thread_sync, and can be
/// interrupted with m_interrupt. Once the index gets in sync, the m_synced
@@ -76,30 +87,32 @@ private:
/// getting corrupted.
bool Commit();
+ /// Loop over disconnected blocks and call CustomRewind.
+ bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip);
+
virtual bool AllowPrune() const = 0;
protected:
+ std::unique_ptr<interfaces::Chain> m_chain;
CChainState* m_chainstate{nullptr};
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override;
void ChainStateFlushed(const CBlockLocator& locator) override;
- const CBlockIndex* CurrentIndex() { return m_best_block_index.load(); };
-
/// Initialize internal state from the database and block index.
- [[nodiscard]] virtual bool Init();
+ [[nodiscard]] virtual bool CustomInit(const std::optional<interfaces::BlockKey>& block) { return true; }
/// Write update index entries for a newly connected block.
- virtual bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) { return true; }
+ [[nodiscard]] virtual bool CustomAppend(const interfaces::BlockInfo& block) { return true; }
/// Virtual method called internally by Commit that can be overridden to atomically
/// commit more index state.
- virtual bool CommitInternal(CDBBatch& batch);
+ virtual bool CustomCommit(CDBBatch& batch) { return true; }
/// Rewind index to an earlier chain tip during a chain reorg. The tip must
/// be an ancestor of the current best block.
- virtual bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip);
+ [[nodiscard]] virtual bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) { return true; }
virtual DB& GetDB() const = 0;
@@ -110,6 +123,7 @@ protected:
void SetBestBlockIndex(const CBlockIndex* block);
public:
+ BaseIndex(std::unique_ptr<interfaces::Chain> chain);
/// Destructor interrupts sync thread if running and blocks until it exits.
virtual ~BaseIndex();
@@ -124,7 +138,7 @@ public:
/// Start initializes the sync state and registers the instance as a
/// ValidationInterface so that it stays in sync with blockchain updates.
- [[nodiscard]] bool Start(CChainState& active_chainstate);
+ [[nodiscard]] bool Start();
/// Stops the instance from staying in sync with blockchain updates.
void Stop();
diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp
index e7fad8eb64..f4837f3456 100644
--- a/src/index/blockfilterindex.cpp
+++ b/src/index/blockfilterindex.cpp
@@ -9,6 +9,7 @@
#include <index/blockfilterindex.h>
#include <node/blockstorage.h>
#include <util/system.h>
+#include <validation.h>
using node::UndoReadFromDisk;
@@ -94,9 +95,9 @@ struct DBHashKey {
static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes;
-BlockFilterIndex::BlockFilterIndex(BlockFilterType filter_type,
+BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory, bool f_wipe)
- : m_filter_type(filter_type)
+ : BaseIndex(std::move(chain)), m_filter_type(filter_type)
{
const std::string& filter_name = BlockFilterTypeName(filter_type);
if (filter_name.empty()) throw std::invalid_argument("unknown filter_type");
@@ -109,7 +110,7 @@ BlockFilterIndex::BlockFilterIndex(BlockFilterType filter_type,
m_filter_fileseq = std::make_unique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE);
}
-bool BlockFilterIndex::Init()
+bool BlockFilterIndex::CustomInit(const std::optional<interfaces::BlockKey>& block)
{
if (!m_db->Read(DB_FILTER_POS, m_next_filter_pos)) {
// Check that the cause of the read failure is that the key does not exist. Any other errors
@@ -124,15 +125,15 @@ bool BlockFilterIndex::Init()
m_next_filter_pos.nFile = 0;
m_next_filter_pos.nPos = 0;
}
- return BaseIndex::Init();
+ return true;
}
-bool BlockFilterIndex::CommitInternal(CDBBatch& batch)
+bool BlockFilterIndex::CustomCommit(CDBBatch& batch)
{
const FlatFilePos& pos = m_next_filter_pos;
// Flush current filter file to disk.
- CAutoFile file(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION);
+ AutoFile file{m_filter_fileseq->Open(pos)};
if (file.IsNull()) {
return error("%s: Failed to open filter file %d", __func__, pos.nFile);
}
@@ -141,12 +142,12 @@ bool BlockFilterIndex::CommitInternal(CDBBatch& batch)
}
batch.Write(DB_FILTER_POS, pos);
- return BaseIndex::CommitInternal(batch);
+ return true;
}
bool BlockFilterIndex::ReadFilterFromDisk(const FlatFilePos& pos, const uint256& hash, BlockFilter& filter) const
{
- CAutoFile filein(m_filter_fileseq->Open(pos, true), SER_DISK, CLIENT_VERSION);
+ AutoFile filein{m_filter_fileseq->Open(pos, true)};
if (filein.IsNull()) {
return false;
}
@@ -178,7 +179,7 @@ size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter&
// If writing the filter would overflow the file, flush and move to the next one.
if (pos.nPos + data_size > MAX_FLTR_FILE_SIZE) {
- CAutoFile last_file(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION);
+ AutoFile last_file{m_filter_fileseq->Open(pos)};
if (last_file.IsNull()) {
LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile);
return 0;
@@ -204,7 +205,7 @@ size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter&
return 0;
}
- CAutoFile fileout(m_filter_fileseq->Open(pos), SER_DISK, CLIENT_VERSION);
+ AutoFile fileout{m_filter_fileseq->Open(pos)};
if (fileout.IsNull()) {
LogPrintf("%s: Failed to open filter file %d\n", __func__, pos.nFile);
return 0;
@@ -214,22 +215,25 @@ size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter&
return data_size;
}
-bool BlockFilterIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
+bool BlockFilterIndex::CustomAppend(const interfaces::BlockInfo& block)
{
CBlockUndo block_undo;
uint256 prev_header;
- if (pindex->nHeight > 0) {
+ if (block.height > 0) {
+ // pindex variable gives indexing code access to node internals. It
+ // will be removed in upcoming commit
+ const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
if (!UndoReadFromDisk(block_undo, pindex)) {
return false;
}
std::pair<uint256, DBVal> read_out;
- if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
+ if (!m_db->Read(DBHeightKey(block.height - 1), read_out)) {
return false;
}
- uint256 expected_block_hash = pindex->pprev->GetBlockHash();
+ uint256 expected_block_hash = *Assert(block.prev_hash);
if (read_out.first != expected_block_hash) {
return error("%s: previous block header belongs to unexpected block %s; expected %s",
__func__, read_out.first.ToString(), expected_block_hash.ToString());
@@ -238,18 +242,18 @@ bool BlockFilterIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex
prev_header = read_out.second.header;
}
- BlockFilter filter(m_filter_type, block, block_undo);
+ BlockFilter filter(m_filter_type, *Assert(block.data), block_undo);
size_t bytes_written = WriteFilterToDisk(m_next_filter_pos, filter);
if (bytes_written == 0) return false;
std::pair<uint256, DBVal> value;
- value.first = pindex->GetBlockHash();
+ value.first = block.hash;
value.second.hash = filter.GetHash();
value.second.header = filter.ComputeHeader(prev_header);
value.second.pos = m_next_filter_pos;
- if (!m_db->Write(DBHeightKey(pindex->nHeight), value)) {
+ if (!m_db->Write(DBHeightKey(block.height), value)) {
return false;
}
@@ -283,17 +287,15 @@ static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
return true;
}
-bool BlockFilterIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
+bool BlockFilterIndex::CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip)
{
- assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
-
CDBBatch batch(*m_db);
std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
// During a reorg, we need to copy all filters for blocks that are getting disconnected from the
// height index to the hash index so we can still find them when the height index entries are
// overwritten.
- if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip->nHeight, current_tip->nHeight)) {
+ if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip.height, current_tip.height)) {
return false;
}
@@ -303,7 +305,7 @@ bool BlockFilterIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex*
batch.Write(DB_FILTER_POS, m_next_filter_pos);
if (!m_db->WriteBatch(batch)) return false;
- return BaseIndex::Rewind(current_tip, new_tip);
+ return true;
}
static bool LookupOne(const CDBWrapper& db, const CBlockIndex* block_index, DBVal& result)
@@ -467,12 +469,12 @@ void ForEachBlockFilterIndex(std::function<void (BlockFilterIndex&)> fn)
for (auto& entry : g_filter_indexes) fn(entry.second);
}
-bool InitBlockFilterIndex(BlockFilterType filter_type,
+bool InitBlockFilterIndex(std::function<std::unique_ptr<interfaces::Chain>()> make_chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory, bool f_wipe)
{
auto result = g_filter_indexes.emplace(std::piecewise_construct,
std::forward_as_tuple(filter_type),
- std::forward_as_tuple(filter_type,
+ std::forward_as_tuple(make_chain(), filter_type,
n_cache_size, f_memory, f_wipe));
return result.second;
}
diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h
index fef8b573e8..968eccb6b3 100644
--- a/src/index/blockfilterindex.h
+++ b/src/index/blockfilterindex.h
@@ -41,13 +41,13 @@ private:
bool AllowPrune() const override { return true; }
protected:
- bool Init() override;
+ bool CustomInit(const std::optional<interfaces::BlockKey>& block) override;
- bool CommitInternal(CDBBatch& batch) override;
+ bool CustomCommit(CDBBatch& batch) override;
- bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
+ bool CustomAppend(const interfaces::BlockInfo& block) override;
- bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip) override;
+ bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) override;
BaseIndex::DB& GetDB() const override { return *m_db; }
@@ -55,7 +55,7 @@ protected:
public:
/** Constructs the index, which becomes available to be queried. */
- explicit BlockFilterIndex(BlockFilterType filter_type,
+ explicit BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
BlockFilterType GetFilterType() const { return m_filter_type; }
@@ -88,7 +88,7 @@ void ForEachBlockFilterIndex(std::function<void (BlockFilterIndex&)> fn);
* Initialize a block filter index for the given type if one does not already exist. Returns true if
* a new index is created and false if one has already been initialized.
*/
-bool InitBlockFilterIndex(BlockFilterType filter_type,
+bool InitBlockFilterIndex(std::function<std::unique_ptr<interfaces::Chain>()> make_chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
/**
diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp
index 687e330fe0..b9029e946a 100644
--- a/src/index/coinstatsindex.cpp
+++ b/src/index/coinstatsindex.cpp
@@ -10,6 +10,7 @@
#include <serialize.h>
#include <txdb.h>
#include <undo.h>
+#include <util/system.h>
#include <validation.h>
using kernel::CCoinsStats;
@@ -102,7 +103,8 @@ struct DBHashKey {
std::unique_ptr<CoinStatsIndex> g_coin_stats_index;
-CoinStatsIndex::CoinStatsIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
+CoinStatsIndex::CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe)
+ : BaseIndex(std::move(chain))
{
fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"};
fs::create_directories(path);
@@ -110,24 +112,27 @@ CoinStatsIndex::CoinStatsIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
m_db = std::make_unique<CoinStatsIndex::DB>(path / "db", n_cache_size, f_memory, f_wipe);
}
-bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
+bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
{
CBlockUndo block_undo;
- const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
+ const CAmount block_subsidy{GetBlockSubsidy(block.height, Params().GetConsensus())};
m_total_subsidy += block_subsidy;
// Ignore genesis block
- if (pindex->nHeight > 0) {
+ if (block.height > 0) {
+ // pindex variable gives indexing code access to node internals. It
+ // will be removed in upcoming commit
+ const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
if (!UndoReadFromDisk(block_undo, pindex)) {
return false;
}
std::pair<uint256, DBVal> read_out;
- if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
+ if (!m_db->Read(DBHeightKey(block.height - 1), read_out)) {
return false;
}
- uint256 expected_block_hash{pindex->pprev->GetBlockHash()};
+ uint256 expected_block_hash{*Assert(block.prev_hash)};
if (read_out.first != expected_block_hash) {
LogPrintf("WARNING: previous block header belongs to unexpected block %s; expected %s\n",
read_out.first.ToString(), expected_block_hash.ToString());
@@ -139,12 +144,13 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
}
// TODO: Deduplicate BIP30 related code
- bool is_bip30_block{(pindex->nHeight == 91722 && pindex->GetBlockHash() == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) ||
- (pindex->nHeight == 91812 && pindex->GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"))};
+ bool is_bip30_block{(block.height == 91722 && block.hash == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) ||
+ (block.height == 91812 && block.hash == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"))};
// Add the new utxos created from the block
- for (size_t i = 0; i < block.vtx.size(); ++i) {
- const auto& tx{block.vtx.at(i)};
+ assert(block.data);
+ for (size_t i = 0; i < block.data->vtx.size(); ++i) {
+ const auto& tx{block.data->vtx.at(i)};
// Skip duplicate txid coinbase transactions (BIP30).
if (is_bip30_block && tx->IsCoinBase()) {
@@ -155,7 +161,7 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
for (uint32_t j = 0; j < tx->vout.size(); ++j) {
const CTxOut& out{tx->vout[j]};
- Coin coin{out, pindex->nHeight, tx->IsCoinBase()};
+ Coin coin{out, block.height, tx->IsCoinBase()};
COutPoint outpoint{tx->GetHash(), j};
// Skip unspendable coins
@@ -211,7 +217,7 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
std::pair<uint256, DBVal> value;
- value.first = pindex->GetBlockHash();
+ value.first = block.hash;
value.second.transaction_output_count = m_transaction_output_count;
value.second.bogo_size = m_bogo_size;
value.second.total_amount = m_total_amount;
@@ -231,7 +237,7 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
// Intentionally do not update DB_MUHASH here so it stays in sync with
// DB_BEST_BLOCK, and the index is not corrupted if there is an unclean shutdown.
- return m_db->Write(DBHeightKey(pindex->nHeight), value);
+ return m_db->Write(DBHeightKey(block.height), value);
}
static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
@@ -260,17 +266,15 @@ static bool CopyHeightIndexToHashIndex(CDBIterator& db_it, CDBBatch& batch,
return true;
}
-bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
+bool CoinStatsIndex::CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip)
{
- assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
-
CDBBatch batch(*m_db);
std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
// During a reorg, we need to copy all hash digests for blocks that are
// getting disconnected from the height index to the hash index so we can
// still find them when the height index entries are overwritten.
- if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip->nHeight, current_tip->nHeight)) {
+ if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip.height, current_tip.height)) {
return false;
}
@@ -278,7 +282,8 @@ bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* n
{
LOCK(cs_main);
- const CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip->GetBlockHash())};
+ const CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip.hash)};
+ const CBlockIndex* new_tip_index{m_chainstate->m_blockman.LookupBlockIndex(new_tip.hash)};
const auto& consensus_params{Params().GetConsensus()};
do {
@@ -292,29 +297,29 @@ bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* n
ReverseBlock(block, iter_tip);
iter_tip = iter_tip->GetAncestor(iter_tip->nHeight - 1);
- } while (new_tip != iter_tip);
+ } while (new_tip_index != iter_tip);
}
- return BaseIndex::Rewind(current_tip, new_tip);
+ return true;
}
-static bool LookUpOne(const CDBWrapper& db, const CBlockIndex* block_index, DBVal& result)
+static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockKey& block, DBVal& result)
{
// First check if the result is stored under the height index and the value
// there matches the block hash. This should be the case if the block is on
// the active chain.
std::pair<uint256, DBVal> read_out;
- if (!db.Read(DBHeightKey(block_index->nHeight), read_out)) {
+ if (!db.Read(DBHeightKey(block.height), read_out)) {
return false;
}
- if (read_out.first == block_index->GetBlockHash()) {
+ if (read_out.first == block.hash) {
result = std::move(read_out.second);
return true;
}
// If value at the height index corresponds to an different block, the
// result will be stored in the hash index.
- return db.Read(DBHashKey(block_index->GetBlockHash()), result);
+ return db.Read(DBHashKey(block.hash), result);
}
std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex* block_index) const
@@ -323,7 +328,7 @@ std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex* block_
stats.index_used = true;
DBVal entry;
- if (!LookUpOne(*m_db, block_index, entry)) {
+ if (!LookUpOne(*m_db, {block_index->GetBlockHash(), block_index->nHeight}, entry)) {
return std::nullopt;
}
@@ -344,7 +349,7 @@ std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex* block_
return stats;
}
-bool CoinStatsIndex::Init()
+bool CoinStatsIndex::CustomInit(const std::optional<interfaces::BlockKey>& block)
{
if (!m_db->Read(DB_MUHASH, m_muhash)) {
// Check that the cause of the read failure is that the key does not
@@ -356,13 +361,9 @@ bool CoinStatsIndex::Init()
}
}
- if (!BaseIndex::Init()) return false;
-
- const CBlockIndex* pindex{CurrentIndex()};
-
- if (pindex) {
+ if (block) {
DBVal entry;
- if (!LookUpOne(*m_db, pindex, entry)) {
+ if (!LookUpOne(*m_db, *block, entry)) {
return error("%s: Cannot read current %s state; index may be corrupted",
__func__, GetName());
}
@@ -391,12 +392,12 @@ bool CoinStatsIndex::Init()
return true;
}
-bool CoinStatsIndex::CommitInternal(CDBBatch& batch)
+bool CoinStatsIndex::CustomCommit(CDBBatch& batch)
{
// DB_MUHASH should always be committed in a batch together with DB_BEST_BLOCK
// to prevent an inconsistent state of the DB.
batch.Write(DB_MUHASH, m_muhash);
- return BaseIndex::CommitInternal(batch);
+ return true;
}
// Reverse a single block as part of a reorg
diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h
index cae052d913..c4af223388 100644
--- a/src/index/coinstatsindex.h
+++ b/src/index/coinstatsindex.h
@@ -39,13 +39,13 @@ private:
bool AllowPrune() const override { return true; }
protected:
- bool Init() override;
+ bool CustomInit(const std::optional<interfaces::BlockKey>& block) override;
- bool CommitInternal(CDBBatch& batch) override;
+ bool CustomCommit(CDBBatch& batch) override;
- bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
+ bool CustomAppend(const interfaces::BlockInfo& block) override;
- bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip) override;
+ bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) override;
BaseIndex::DB& GetDB() const override { return *m_db; }
@@ -53,7 +53,7 @@ protected:
public:
// Constructs the index, which becomes available to be queried.
- explicit CoinStatsIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
+ explicit CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
// Look up stats for a specific block using CBlockIndex
std::optional<kernel::CCoinsStats> LookUpStats(const CBlockIndex* block_index) const;
diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp
index 97c11c4383..b719aface8 100644
--- a/src/index/txindex.cpp
+++ b/src/index/txindex.cpp
@@ -48,23 +48,22 @@ bool TxIndex::DB::WriteTxs(const std::vector<std::pair<uint256, CDiskTxPos>>& v_
return WriteBatch(batch);
}
-TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
- : m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
+TxIndex::TxIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe)
+ : BaseIndex(std::move(chain)), m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
{}
TxIndex::~TxIndex() = default;
-bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
+bool TxIndex::CustomAppend(const interfaces::BlockInfo& block)
{
// Exclude genesis block transaction because outputs are not spendable.
- if (pindex->nHeight == 0) return true;
+ if (block.height == 0) return true;
- CDiskTxPos pos{
- WITH_LOCK(::cs_main, return pindex->GetBlockPos()),
- GetSizeOfCompactSize(block.vtx.size())};
+ assert(block.data);
+ CDiskTxPos pos({block.file_number, block.data_pos}, GetSizeOfCompactSize(block.data->vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos>> vPos;
- vPos.reserve(block.vtx.size());
- for (const auto& tx : block.vtx) {
+ vPos.reserve(block.data->vtx.size());
+ for (const auto& tx : block.data->vtx) {
vPos.emplace_back(tx->GetHash(), pos);
pos.nTxOffset += ::GetSerializeSize(*tx, CLIENT_VERSION);
}
diff --git a/src/index/txindex.h b/src/index/txindex.h
index ec339abaa1..be240c4582 100644
--- a/src/index/txindex.h
+++ b/src/index/txindex.h
@@ -23,7 +23,7 @@ private:
bool AllowPrune() const override { return false; }
protected:
- bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
+ bool CustomAppend(const interfaces::BlockInfo& block) override;
BaseIndex::DB& GetDB() const override;
@@ -31,7 +31,7 @@ protected:
public:
/// Constructs the index, which becomes available to be queried.
- explicit TxIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
+ explicit TxIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
// Destructor is declared because this class contains a unique_ptr to an incomplete type.
virtual ~TxIndex() override;
diff --git a/src/init.cpp b/src/init.cpp
index 267070a4c9..4606b77e9f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -10,6 +10,8 @@
#include <init.h>
#include <kernel/checks.h>
+#include <kernel/mempool_persist.h>
+#include <kernel/validation_cache_sizes.h>
#include <addrman.h>
#include <banman.h>
@@ -30,7 +32,6 @@
#include <interfaces/init.h>
#include <interfaces/node.h>
#include <mapport.h>
-#include <mempool_args.h>
#include <net.h>
#include <net_permissions.h>
#include <net_processing.h>
@@ -41,7 +42,10 @@
#include <node/chainstate.h>
#include <node/context.h>
#include <node/interface_ui.h>
+#include <node/mempool_args.h>
+#include <node/mempool_persist_args.h>
#include <node/miner.h>
+#include <node/validation_cache_args.h>
#include <policy/feerate.h>
#include <policy/fees.h>
#include <policy/fees_args.h>
@@ -102,14 +106,18 @@
#include <zmq/zmqrpc.h>
#endif
+using kernel::DumpMempool;
+using kernel::ValidationCacheSizes;
+
+using node::ApplyArgsManOptions;
using node::CacheSizes;
using node::CalculateCacheSizes;
-using node::ChainstateLoadVerifyError;
-using node::ChainstateLoadingError;
-using node::CleanupBlockRevFiles;
+using node::DEFAULT_PERSIST_MEMPOOL;
using node::DEFAULT_PRINTPRIORITY;
using node::DEFAULT_STOPAFTERBLOCKIMPORT;
using node::LoadChainstate;
+using node::MempoolPath;
+using node::ShouldPersistMempool;
using node::NodeContext;
using node::ThreadImport;
using node::VerifyLoadedChainstate;
@@ -245,8 +253,8 @@ void Shutdown(NodeContext& node)
node.addrman.reset();
node.netgroupman.reset();
- if (node.mempool && node.mempool->IsLoaded() && node.args->GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
- DumpMempool(*node.mempool);
+ if (node.mempool && node.mempool->GetLoadTried() && ShouldPersistMempool(*node.args)) {
+ DumpMempool(*node.mempool, MempoolPath(*node.args));
}
// Drop transactions we were still watching, and record fee estimations.
@@ -544,7 +552,7 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-addrmantest", "Allows to test address relay on localhost", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-mocktime=<n>", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
- argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
+ argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_BYTES >> 20), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in " + CURRENCY_UNIT + "/kvB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
@@ -931,16 +939,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex());
}
- // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
- // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
- if (args.IsArgSet("-incrementalrelayfee")) {
- if (std::optional<CAmount> inc_relay_fee = ParseMoney(args.GetArg("-incrementalrelayfee", ""))) {
- ::incrementalRelayFee = CFeeRate{inc_relay_fee.value()};
- } else {
- return InitError(AmountErrMsg("incrementalrelayfee", args.GetArg("-incrementalrelayfee", "")));
- }
- }
-
// block pruning; get the amount of disk space (in MiB) to allot for block & undo files
int64_t nPruneArg = args.GetIntArg("-prune", 0);
if (nPruneArg < 0) {
@@ -969,19 +967,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
return InitError(Untranslated("peertimeout must be a positive integer."));
}
- if (args.IsArgSet("-minrelaytxfee")) {
- if (std::optional<CAmount> min_relay_fee = ParseMoney(args.GetArg("-minrelaytxfee", ""))) {
- // High fee check is done afterward in CWallet::Create()
- ::minRelayTxFee = CFeeRate{min_relay_fee.value()};
- } else {
- return InitError(AmountErrMsg("minrelaytxfee", args.GetArg("-minrelaytxfee", "")));
- }
- } else if (incrementalRelayFee > ::minRelayTxFee) {
- // Allow only setting incrementalRelayFee to control both
- ::minRelayTxFee = incrementalRelayFee;
- LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n",::minRelayTxFee.ToString());
- }
-
// Sanity check argument for min fee for including tx in block
// TODO: Harmonize which arguments need sanity checking and where that happens
if (args.IsArgSet("-blockmintxfee")) {
@@ -990,28 +975,10 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
}
}
- // Feerate used to define dust. Shouldn't be changed lightly as old
- // implementations may inadvertently create non-standard transactions
- if (args.IsArgSet("-dustrelayfee")) {
- if (std::optional<CAmount> parsed = ParseMoney(args.GetArg("-dustrelayfee", ""))) {
- dustRelayFee = CFeeRate{parsed.value()};
- } else {
- return InitError(AmountErrMsg("dustrelayfee", args.GetArg("-dustrelayfee", "")));
- }
- }
-
- fRequireStandard = !args.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
- if (!chainparams.IsTestChain() && !fRequireStandard) {
- return InitError(strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.NetworkIDString()));
- }
nBytesPerSigOp = args.GetIntArg("-bytespersigop", nBytesPerSigOp);
if (!g_wallet_init_interface.ParameterInteraction()) return false;
- fIsBareMultisigStd = args.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
- fAcceptDatacarrier = args.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER);
- nMaxDatacarrierBytes = args.GetIntArg("-datacarriersize", nMaxDatacarrierBytes);
-
// Option to startup with mocktime set (used for regression testing):
SetMockTime(args.GetIntArg("-mocktime", 0)); // SetMockTime(0) is a no-op
@@ -1092,21 +1059,8 @@ static bool LockDataDirectory(bool probeOnly)
bool AppInitSanityChecks(const kernel::Context& kernel)
{
// ********************************************************* Step 4: sanity checks
- auto maybe_error = kernel::SanityChecks(kernel);
-
- if (maybe_error.has_value()) {
- switch (maybe_error.value()) {
- case kernel::SanityCheckError::ERROR_ECC:
- InitError(Untranslated("Elliptic curve cryptography sanity check failure. Aborting."));
- break;
- case kernel::SanityCheckError::ERROR_RANDOM:
- InitError(Untranslated("OS cryptographic RNG sanity check failure. Aborting."));
- break;
- case kernel::SanityCheckError::ERROR_CHRONO:
- InitError(Untranslated("Clock epoch mismatch. Aborting."));
- break;
- } // no default case, so the compiler can warn about missing cases
-
+ if (auto error = kernel::SanityChecks(kernel)) {
+ InitError(*error);
return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME));
}
@@ -1165,8 +1119,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
args.GetArg("-datadir", ""), fs::PathToString(fs::current_path()));
}
- InitSignatureCache();
- InitScriptExecutionCache();
+ ValidationCacheSizes validation_cache_sizes{};
+ ApplyArgsManOptions(args, validation_cache_sizes);
+ if (!InitSignatureCache(validation_cache_sizes.signature_cache_bytes)
+ || !InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes))
+ {
+ return InitError(strprintf(_("Unable to allocate memory for -maxsigcachesize: '%s' MiB"), args.GetIntArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_BYTES >> 20)));
+ }
int script_threads = args.GetIntArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
if (script_threads <= 0) {
@@ -1427,7 +1386,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
.estimator = node.fee_estimator.get(),
.check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0,
};
- ApplyArgsManOptions(args, mempool_opts);
+ if (const auto err{ApplyArgsManOptions(args, chainparams, mempool_opts)}) {
+ return InitError(*err);
+ }
mempool_opts.check_ratio = std::clamp<int>(mempool_opts.check_ratio, 0, 1'000'000);
int64_t descendant_limit_bytes = mempool_opts.limits.descendant_size_vbytes * 40;
@@ -1446,112 +1407,54 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
node.chainman = std::make_unique<ChainstateManager>(chainman_opts);
ChainstateManager& chainman = *node.chainman;
- const bool fReset = fReindex;
- bilingual_str strLoadError;
+ node::ChainstateLoadOptions options;
+ options.mempool = Assert(node.mempool.get());
+ options.reindex = node::fReindex;
+ options.reindex_chainstate = fReindexChainState;
+ options.prune = node::fPruneMode;
+ options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
+ options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
+ options.check_interrupt = ShutdownRequested;
+ options.coins_error_cb = [] {
+ uiInterface.ThreadSafeMessageBox(
+ _("Error reading from database, shutting down."),
+ "", CClientUIInterface::MSG_ERROR);
+ };
uiInterface.InitMessage(_("Loading block index…").translated);
const int64_t load_block_index_start_time = GetTimeMillis();
- std::optional<ChainstateLoadingError> maybe_load_error;
- try {
- maybe_load_error = LoadChainstate(fReset,
- chainman,
- Assert(node.mempool.get()),
- fPruneMode,
- fReindexChainState,
- cache_sizes.block_tree_db,
- cache_sizes.coins_db,
- cache_sizes.coins,
- /*block_tree_db_in_memory=*/false,
- /*coins_db_in_memory=*/false,
- /*shutdown_requested=*/ShutdownRequested,
- /*coins_error_cb=*/[]() {
- uiInterface.ThreadSafeMessageBox(
- _("Error reading from database, shutting down."),
- "", CClientUIInterface::MSG_ERROR);
- });
- } catch (const std::exception& e) {
- LogPrintf("%s\n", e.what());
- maybe_load_error = ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED;
- }
- if (maybe_load_error.has_value()) {
- switch (maybe_load_error.value()) {
- case ChainstateLoadingError::ERROR_LOADING_BLOCK_DB:
- strLoadError = _("Error loading block database");
- break;
- case ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK:
- // If the loaded chain has a wrong genesis, bail out immediately
- // (we're likely using a testnet datadir, or the other way around).
- return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
- case ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX:
- strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
- break;
- case ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED:
- strLoadError = _("Error initializing block database");
- break;
- case ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED:
- return InitError(_("Unsupported chainstate database format found. "
- "Please restart with -reindex-chainstate. This will "
- "rebuild the chainstate database."));
- case ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED:
- strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.");
- break;
- case ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED:
- strLoadError = _("Error initializing block database");
- break;
- case ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED:
- strLoadError = _("Error opening block database");
- break;
- case ChainstateLoadingError::ERROR_BLOCKS_WITNESS_INSUFFICIENTLY_VALIDATED:
- strLoadError = strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."),
- chainman.GetConsensus().SegwitHeight);
- break;
- case ChainstateLoadingError::SHUTDOWN_PROBED:
- break;
- }
- } else {
- std::optional<ChainstateLoadVerifyError> maybe_verify_error;
+ auto catch_exceptions = [](auto&& f) {
try {
- uiInterface.InitMessage(_("Verifying blocks…").translated);
- auto check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
- if (chainman.m_blockman.m_have_pruned && check_blocks > MIN_BLOCKS_TO_KEEP) {
- LogPrintfCategory(BCLog::PRUNE, "pruned datadir may not have more than %d blocks; only checking available blocks\n",
- MIN_BLOCKS_TO_KEEP);
- }
- maybe_verify_error = VerifyLoadedChainstate(chainman,
- fReset,
- fReindexChainState,
- check_blocks,
- args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL));
+ return f();
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());
- maybe_verify_error = ChainstateLoadVerifyError::ERROR_GENERIC_FAILURE;
+ return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error opening block database"));
}
- if (maybe_verify_error.has_value()) {
- switch (maybe_verify_error.value()) {
- case ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE:
- strLoadError = _("The block database contains a block which appears to be from the future. "
- "This may be due to your computer's date and time being set incorrectly. "
- "Only rebuild the block database if you are sure that your computer's date and time are correct");
- break;
- case ChainstateLoadVerifyError::ERROR_CORRUPTED_BLOCK_DB:
- strLoadError = _("Corrupted block database detected");
- break;
- case ChainstateLoadVerifyError::ERROR_GENERIC_FAILURE:
- strLoadError = _("Error opening block database");
- break;
- }
- } else {
+ };
+ auto [status, error] = catch_exceptions([&]{ return LoadChainstate(chainman, cache_sizes, options); });
+ if (status == node::ChainstateLoadStatus::SUCCESS) {
+ uiInterface.InitMessage(_("Verifying blocks…").translated);
+ if (chainman.m_blockman.m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) {
+ LogPrintfCategory(BCLog::PRUNE, "pruned datadir may not have more than %d blocks; only checking available blocks\n",
+ MIN_BLOCKS_TO_KEEP);
+ }
+ std::tie(status, error) = catch_exceptions([&]{ return VerifyLoadedChainstate(chainman, options);});
+ if (status == node::ChainstateLoadStatus::SUCCESS) {
fLoaded = true;
LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time);
}
}
+ if (status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB) {
+ return InitError(error);
+ }
+
if (!fLoaded && !ShutdownRequested()) {
// first suggest a reindex
- if (!fReset) {
+ if (!options.reindex) {
bool fRet = uiInterface.ThreadSafeQuestion(
- strLoadError + Untranslated(".\n\n") + _("Do you want to rebuild the block database now?"),
- strLoadError.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
+ error + Untranslated(".\n\n") + _("Do you want to rebuild the block database now?"),
+ error.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
if (fRet) {
fReindex = true;
@@ -1561,7 +1464,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
return false;
}
} else {
- return InitError(strLoadError);
+ return InitError(error);
}
}
}
@@ -1587,22 +1490,22 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
return InitError(*error);
}
- g_txindex = std::make_unique<TxIndex>(cache_sizes.tx_index, false, fReindex);
- if (!g_txindex->Start(chainman.ActiveChainstate())) {
+ g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, fReindex);
+ if (!g_txindex->Start()) {
return false;
}
}
for (const auto& filter_type : g_enabled_filter_types) {
- InitBlockFilterIndex(filter_type, cache_sizes.filter_index, false, fReindex);
- if (!GetBlockFilterIndex(filter_type)->Start(chainman.ActiveChainstate())) {
+ InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, fReindex);
+ if (!GetBlockFilterIndex(filter_type)->Start()) {
return false;
}
}
if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
- g_coin_stats_index = std::make_unique<CoinStatsIndex>(/* cache size */ 0, false, fReindex);
- if (!g_coin_stats_index->Start(chainman.ActiveChainstate())) {
+ g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /* cache size */ 0, false, fReindex);
+ if (!g_coin_stats_index->Start()) {
return false;
}
}
@@ -1669,7 +1572,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
chainman.m_load_block = std::thread(&util::TraceThread, "loadblk", [=, &chainman, &args] {
- ThreadImport(chainman, vImportFiles, args);
+ ThreadImport(chainman, vImportFiles, args, ShouldPersistMempool(args) ? MempoolPath(args) : fs::path{});
});
// Wait for genesis block to be processed
diff --git a/src/init/common.cpp b/src/init/common.cpp
index a0cdf44f47..bdd7f16307 100644
--- a/src/init/common.cpp
+++ b/src/init/common.cpp
@@ -99,7 +99,7 @@ bool StartLogging(const ArgsManager& args)
LogPrintf("Using data directory %s\n", fs::PathToString(gArgs.GetDataDirNet()));
// Only log conf file usage message if conf file actually exists.
- fs::path config_file_path = GetConfigFile(args.GetArg("-conf", BITCOIN_CONF_FILENAME));
+ fs::path config_file_path = GetConfigFile(args.GetPathArg("-conf", BITCOIN_CONF_FILENAME));
if (fs::exists(config_file_path)) {
LogPrintf("Config file: %s\n", fs::PathToString(config_file_path));
} else if (args.IsArgSet("-conf")) {
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index df9e55874f..5fc0e540a9 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -18,6 +18,7 @@
class ArgsManager;
class CBlock;
+class CBlockUndo;
class CFeeRate;
class CRPCCommand;
class CScheduler;
@@ -37,6 +38,12 @@ namespace interfaces {
class Handler;
class Wallet;
+//! Hash/height pair to help track and identify blocks.
+struct BlockKey {
+ uint256 hash;
+ int height = -1;
+};
+
//! Helper for findBlock to selectively return pieces of block data. If block is
//! found, data will be returned by setting specified output variables. If block
//! is not found, output variables will keep their previous values.
@@ -50,6 +57,8 @@ public:
FoundBlock& mtpTime(int64_t& mtp_time) { m_mtp_time = &mtp_time; return *this; }
//! Return whether block is in the active (most-work) chain.
FoundBlock& inActiveChain(bool& in_active_chain) { m_in_active_chain = &in_active_chain; return *this; }
+ //! Return locator if block is in the active chain.
+ FoundBlock& locator(CBlockLocator& locator) { m_locator = &locator; return *this; }
//! Return next block in the active chain if current block is in the active chain.
FoundBlock& nextBlock(const FoundBlock& next_block) { m_next_block = &next_block; return *this; }
//! Read block data from disk. If the block exists but doesn't have data
@@ -62,11 +71,25 @@ public:
int64_t* m_max_time = nullptr;
int64_t* m_mtp_time = nullptr;
bool* m_in_active_chain = nullptr;
+ CBlockLocator* m_locator = nullptr;
const FoundBlock* m_next_block = nullptr;
CBlock* m_data = nullptr;
mutable bool found = false;
};
+//! Block data sent with blockConnected, blockDisconnected notifications.
+struct BlockInfo {
+ const uint256& hash;
+ const uint256* prev_hash = nullptr;
+ int height = -1;
+ int file_number = -1;
+ unsigned data_pos = 0;
+ const CBlock* data = nullptr;
+ const CBlockUndo* undo_data = nullptr;
+
+ BlockInfo(const uint256& hash LIFETIMEBOUND) : hash(hash) {}
+};
+
//! Interface giving clients (wallet processes, maybe other analysis tools in
//! the future) ability to access to the chain state, receive notifications,
//! estimate fees, and submit transactions.
@@ -239,8 +262,8 @@ public:
virtual ~Notifications() {}
virtual void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) {}
virtual void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) {}
- virtual void blockConnected(const CBlock& block, int height) {}
- virtual void blockDisconnected(const CBlock& block, int height) {}
+ virtual void blockConnected(const BlockInfo& block) {}
+ virtual void blockDisconnected(const BlockInfo& block) {}
virtual void updatedBlockTip() {}
virtual void chainStateFlushed(const CBlockLocator& locator) {}
};
@@ -287,6 +310,13 @@ public:
//! to be prepared to handle this by ignoring notifications about unknown
//! removed transactions and already added new transactions.
virtual void requestMempoolTransactions(Notifications& notifications) = 0;
+
+ //! Return true if an assumed-valid chain is in use.
+ virtual bool hasAssumedValidChain() = 0;
+
+ //! Get internal node context. Useful for testing, but not
+ //! accessible across processes.
+ virtual node::NodeContext* context() { return nullptr; }
};
//! Interface to let node manage chain clients (wallets, or maybe tools for
diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h
index e29fefae56..1148dc7e4c 100644
--- a/src/interfaces/wallet.h
+++ b/src/interfaces/wallet.h
@@ -88,7 +88,7 @@ public:
virtual std::string getWalletName() = 0;
// Get a new address.
- virtual BResult<CTxDestination> getNewDestination(const OutputType type, const std::string label) = 0;
+ virtual util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string& label) = 0;
//! Get public key.
virtual bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) = 0;
@@ -139,7 +139,7 @@ public:
virtual void listLockedCoins(std::vector<COutPoint>& outputs) = 0;
//! Create transaction.
- virtual BResult<CTransactionRef> createTransaction(const std::vector<wallet::CRecipient>& recipients,
+ virtual util::Result<CTransactionRef> createTransaction(const std::vector<wallet::CRecipient>& recipients,
const wallet::CCoinControl& coin_control,
bool sign,
int& change_pos,
@@ -183,7 +183,7 @@ public:
virtual WalletTx getWalletTx(const uint256& txid) = 0;
//! Get list of all wallet transactions.
- virtual std::vector<WalletTx> getWalletTxs() = 0;
+ virtual std::set<WalletTx> getWalletTxs() = 0;
//! Try to get updated status for a particular transaction, if possible without blocking.
virtual bool tryGetTxStatus(const uint256& txid,
@@ -320,31 +320,31 @@ class WalletLoader : public ChainClient
{
public:
//! Create new wallet.
- virtual std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
+ virtual util::Result<std::unique_ptr<Wallet>> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, std::vector<bilingual_str>& warnings) = 0;
- //! Load existing wallet.
- virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
+ //! Load existing wallet.
+ virtual util::Result<std::unique_ptr<Wallet>> loadWallet(const std::string& name, std::vector<bilingual_str>& warnings) = 0;
- //! Return default wallet directory.
- virtual std::string getWalletDir() = 0;
+ //! Return default wallet directory.
+ virtual std::string getWalletDir() = 0;
- //! Restore backup wallet
- virtual BResult<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) = 0;
+ //! Restore backup wallet
+ virtual util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) = 0;
- //! Return available wallets in wallet directory.
- virtual std::vector<std::string> listWalletDir() = 0;
+ //! Return available wallets in wallet directory.
+ virtual std::vector<std::string> listWalletDir() = 0;
- //! Return interfaces for accessing wallets (if any).
- virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;
+ //! Return interfaces for accessing wallets (if any).
+ virtual std::vector<std::unique_ptr<Wallet>> getWallets() = 0;
- //! Register handler for load wallet messages. This callback is triggered by
- //! createWallet and loadWallet above, and also triggered when wallets are
- //! loaded at startup or by RPC.
- using LoadWalletFn = std::function<void(std::unique_ptr<Wallet> wallet)>;
- virtual std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) = 0;
+ //! Register handler for load wallet messages. This callback is triggered by
+ //! createWallet and loadWallet above, and also triggered when wallets are
+ //! loaded at startup or by RPC.
+ using LoadWalletFn = std::function<void(std::unique_ptr<Wallet> wallet)>;
+ virtual std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) = 0;
- //! Return pointer to internal context, useful for testing.
- virtual wallet::WalletContext* context() { return nullptr; }
+ //! Return pointer to internal context, useful for testing.
+ virtual wallet::WalletContext* context() { return nullptr; }
};
//! Information about one wallet address.
@@ -395,6 +395,8 @@ struct WalletTx
int64_t time;
std::map<std::string, std::string> value_map;
bool is_coinbase;
+
+ bool operator<(const WalletTx& a) const { return tx->GetHash() < a.tx->GetHash(); }
};
//! Updated transaction status.
diff --git a/src/kernel/chain.cpp b/src/kernel/chain.cpp
new file mode 100644
index 0000000000..82e77125d7
--- /dev/null
+++ b/src/kernel/chain.cpp
@@ -0,0 +1,26 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <chain.h>
+#include <interfaces/chain.h>
+#include <sync.h>
+#include <uint256.h>
+
+class CBlock;
+
+namespace kernel {
+interfaces::BlockInfo MakeBlockInfo(const CBlockIndex* index, const CBlock* data)
+{
+ interfaces::BlockInfo info{index ? *index->phashBlock : uint256::ZERO};
+ if (index) {
+ info.prev_hash = index->pprev ? index->pprev->phashBlock : nullptr;
+ info.height = index->nHeight;
+ LOCK(::cs_main);
+ info.file_number = index->nFile;
+ info.data_pos = index->nDataPos;
+ }
+ info.data = data;
+ return info;
+}
+} // namespace kernel
diff --git a/src/kernel/chain.h b/src/kernel/chain.h
new file mode 100644
index 0000000000..f0750f8266
--- /dev/null
+++ b/src/kernel/chain.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_KERNEL_CHAIN_H
+#define BITCOIN_KERNEL_CHAIN_H
+
+class CBlock;
+class CBlockIndex;
+namespace interfaces {
+struct BlockInfo;
+} // namespace interfaces
+
+namespace kernel {
+//! Return data from block index.
+interfaces::BlockInfo MakeBlockInfo(const CBlockIndex* block_index, const CBlock* data = nullptr);
+} // namespace kernel
+
+#endif // BITCOIN_KERNEL_CHAIN_H
diff --git a/src/kernel/checks.cpp b/src/kernel/checks.cpp
index 2a1dd3bfa2..4c303c172c 100644
--- a/src/kernel/checks.cpp
+++ b/src/kernel/checks.cpp
@@ -7,21 +7,24 @@
#include <key.h>
#include <random.h>
#include <util/time.h>
+#include <util/translation.h>
+
+#include <memory>
namespace kernel {
-std::optional<SanityCheckError> SanityChecks(const Context&)
+std::optional<bilingual_str> SanityChecks(const Context&)
{
if (!ECC_InitSanityCheck()) {
- return SanityCheckError::ERROR_ECC;
+ return Untranslated("Elliptic curve cryptography sanity check failure. Aborting.");
}
if (!Random_SanityCheck()) {
- return SanityCheckError::ERROR_RANDOM;
+ return Untranslated("OS cryptographic RNG sanity check failure. Aborting.");
}
if (!ChronoSanityCheck()) {
- return SanityCheckError::ERROR_CHRONO;
+ return Untranslated("Clock epoch mismatch. Aborting.");
}
return std::nullopt;
diff --git a/src/kernel/checks.h b/src/kernel/checks.h
index 80b207f607..3eb14824fb 100644
--- a/src/kernel/checks.h
+++ b/src/kernel/checks.h
@@ -7,20 +7,16 @@
#include <optional>
+struct bilingual_str;
+
namespace kernel {
struct Context;
-enum class SanityCheckError {
- ERROR_ECC,
- ERROR_RANDOM,
- ERROR_CHRONO,
-};
-
/**
* Ensure a usable environment with all necessary library support.
*/
-std::optional<SanityCheckError> SanityChecks(const Context&);
+std::optional<bilingual_str> SanityChecks(const Context&);
}
diff --git a/src/kernel/coinstats.cpp b/src/kernel/coinstats.cpp
index f380871627..06a4b8c974 100644
--- a/src/kernel/coinstats.cpp
+++ b/src/kernel/coinstats.cpp
@@ -4,16 +4,32 @@
#include <kernel/coinstats.h>
+#include <chain.h>
#include <coins.h>
#include <crypto/muhash.h>
#include <hash.h>
+#include <node/blockstorage.h>
+#include <primitives/transaction.h>
+#include <script/script.h>
#include <serialize.h>
+#include <span.h>
+#include <streams.h>
+#include <sync.h>
+#include <tinyformat.h>
#include <uint256.h>
+#include <util/check.h>
#include <util/overflow.h>
#include <util/system.h>
#include <validation.h>
+#include <version.h>
+#include <cassert>
+#include <iosfwd>
+#include <iterator>
#include <map>
+#include <memory>
+#include <string>
+#include <utility>
namespace kernel {
@@ -52,7 +68,7 @@ CDataStream TxOutSer(const COutPoint& outpoint, const Coin& coin) {
//! It is also possible, though very unlikely, that a change in this
//! construction could cause a previously invalid (and potentially malicious)
//! UTXO snapshot to be considered valid.
-static void ApplyHash(CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
+static void ApplyHash(HashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
{
for (auto it = outputs.begin(); it != outputs.end(); ++it) {
if (it == outputs.begin()) {
@@ -143,7 +159,7 @@ std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsV
bool success = [&]() -> bool {
switch (hash_type) {
case(CoinStatsHashType::HASH_SERIALIZED): {
- CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
+ HashWriter ss{};
return ComputeUTXOStats(view, stats, ss, interruption_point);
}
case(CoinStatsHashType::MUHASH): {
@@ -164,7 +180,7 @@ std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsV
}
// The legacy hash serializes the hashBlock
-static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats)
+static void PrepareHash(HashWriter& ss, const CCoinsStats& stats)
{
ss << stats.hashBlock;
}
@@ -172,7 +188,7 @@ static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats)
static void PrepareHash(MuHash3072& muhash, CCoinsStats& stats) {}
static void PrepareHash(std::nullptr_t, CCoinsStats& stats) {}
-static void FinalizeHash(CHashWriter& ss, CCoinsStats& stats)
+static void FinalizeHash(HashWriter& ss, CCoinsStats& stats)
{
stats.hashSerialized = ss.GetHash();
}
diff --git a/src/kernel/coinstats.h b/src/kernel/coinstats.h
index a15957233f..b7c1328e93 100644
--- a/src/kernel/coinstats.h
+++ b/src/kernel/coinstats.h
@@ -5,16 +5,18 @@
#ifndef BITCOIN_KERNEL_COINSTATS_H
#define BITCOIN_KERNEL_COINSTATS_H
-#include <chain.h>
-#include <coins.h>
#include <consensus/amount.h>
#include <streams.h>
#include <uint256.h>
#include <cstdint>
#include <functional>
+#include <optional>
class CCoinsView;
+class Coin;
+class COutPoint;
+class CScript;
namespace node {
class BlockManager;
} // namespace node
diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h
index 07953b443b..dad6f14c39 100644
--- a/src/kernel/mempool_options.h
+++ b/src/kernel/mempool_options.h
@@ -6,8 +6,13 @@
#include <kernel/mempool_limits.h>
+#include <policy/feerate.h>
+#include <policy/policy.h>
+#include <script/standard.h>
+
#include <chrono>
#include <cstdint>
+#include <optional>
class CBlockPolicyEstimator;
@@ -33,6 +38,20 @@ struct MemPoolOptions {
int check_ratio{0};
int64_t max_size_bytes{DEFAULT_MAX_MEMPOOL_SIZE_MB * 1'000'000};
std::chrono::seconds expiry{std::chrono::hours{DEFAULT_MEMPOOL_EXPIRY_HOURS}};
+ CFeeRate incremental_relay_feerate{DEFAULT_INCREMENTAL_RELAY_FEE};
+ /** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
+ CFeeRate min_relay_feerate{DEFAULT_MIN_RELAY_TX_FEE};
+ CFeeRate dust_relay_feerate{DUST_RELAY_TX_FEE};
+ /**
+ * A data carrying output is an unspendable output containing data. The script
+ * type is designated as TxoutType::NULL_DATA.
+ *
+ * Maximum size of TxoutType::NULL_DATA scripts that this node considers standard.
+ * If nullopt, any size is nonstandard.
+ */
+ std::optional<unsigned> max_datacarrier_bytes{DEFAULT_ACCEPT_DATACARRIER ? std::optional{MAX_OP_RETURN_RELAY} : std::nullopt};
+ bool permit_bare_multisig{DEFAULT_PERMIT_BAREMULTISIG};
+ bool require_standard{true};
bool full_rbf{DEFAULT_MEMPOOL_FULL_RBF};
MemPoolLimits limits{};
};
diff --git a/src/kernel/mempool_persist.cpp b/src/kernel/mempool_persist.cpp
new file mode 100644
index 0000000000..1a1cf2bbdc
--- /dev/null
+++ b/src/kernel/mempool_persist.cpp
@@ -0,0 +1,189 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <kernel/mempool_persist.h>
+
+#include <clientversion.h>
+#include <consensus/amount.h>
+#include <fs.h>
+#include <logging.h>
+#include <primitives/transaction.h>
+#include <serialize.h>
+#include <shutdown.h>
+#include <streams.h>
+#include <sync.h>
+#include <txmempool.h>
+#include <uint256.h>
+#include <util/system.h>
+#include <util/time.h>
+#include <validation.h>
+
+#include <chrono>
+#include <cstdint>
+#include <cstdio>
+#include <exception>
+#include <functional>
+#include <map>
+#include <memory>
+#include <set>
+#include <stdexcept>
+#include <utility>
+#include <vector>
+
+using fsbridge::FopenFn;
+
+namespace kernel {
+
+static const uint64_t MEMPOOL_DUMP_VERSION = 1;
+
+bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, CChainState& active_chainstate, FopenFn mockable_fopen_function)
+{
+ if (load_path.empty()) return false;
+
+ FILE* filestr{mockable_fopen_function(load_path, "rb")};
+ CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
+ if (file.IsNull()) {
+ LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
+ return false;
+ }
+
+ int64_t count = 0;
+ int64_t expired = 0;
+ int64_t failed = 0;
+ int64_t already_there = 0;
+ int64_t unbroadcast = 0;
+ auto now = NodeClock::now();
+
+ try {
+ uint64_t version;
+ file >> version;
+ if (version != MEMPOOL_DUMP_VERSION) {
+ return false;
+ }
+ uint64_t num;
+ file >> num;
+ while (num) {
+ --num;
+ CTransactionRef tx;
+ int64_t nTime;
+ int64_t nFeeDelta;
+ file >> tx;
+ file >> nTime;
+ file >> nFeeDelta;
+
+ CAmount amountdelta = nFeeDelta;
+ if (amountdelta) {
+ pool.PrioritiseTransaction(tx->GetHash(), amountdelta);
+ }
+ if (nTime > TicksSinceEpoch<std::chrono::seconds>(now - pool.m_expiry)) {
+ LOCK(cs_main);
+ const auto& accepted = AcceptToMemoryPool(active_chainstate, tx, nTime, /*bypass_limits=*/false, /*test_accept=*/false);
+ if (accepted.m_result_type == MempoolAcceptResult::ResultType::VALID) {
+ ++count;
+ } else {
+ // mempool may contain the transaction already, e.g. from
+ // wallet(s) having loaded it while we were processing
+ // mempool transactions; consider these as valid, instead of
+ // failed, but mark them as 'already there'
+ if (pool.exists(GenTxid::Txid(tx->GetHash()))) {
+ ++already_there;
+ } else {
+ ++failed;
+ }
+ }
+ } else {
+ ++expired;
+ }
+ if (ShutdownRequested())
+ return false;
+ }
+ std::map<uint256, CAmount> mapDeltas;
+ file >> mapDeltas;
+
+ for (const auto& i : mapDeltas) {
+ pool.PrioritiseTransaction(i.first, i.second);
+ }
+
+ std::set<uint256> unbroadcast_txids;
+ file >> unbroadcast_txids;
+ unbroadcast = unbroadcast_txids.size();
+ for (const auto& txid : unbroadcast_txids) {
+ // Ensure transactions were accepted to mempool then add to
+ // unbroadcast set.
+ if (pool.get(txid) != nullptr) pool.AddUnbroadcastTx(txid);
+ }
+ } catch (const std::exception& e) {
+ LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
+ return false;
+ }
+
+ LogPrintf("Imported mempool transactions from disk: %i succeeded, %i failed, %i expired, %i already there, %i waiting for initial broadcast\n", count, failed, expired, already_there, unbroadcast);
+ return true;
+}
+
+bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, FopenFn mockable_fopen_function, bool skip_file_commit)
+{
+ auto start = SteadyClock::now();
+
+ std::map<uint256, CAmount> mapDeltas;
+ std::vector<TxMempoolInfo> vinfo;
+ std::set<uint256> unbroadcast_txids;
+
+ static Mutex dump_mutex;
+ LOCK(dump_mutex);
+
+ {
+ LOCK(pool.cs);
+ for (const auto &i : pool.mapDeltas) {
+ mapDeltas[i.first] = i.second;
+ }
+ vinfo = pool.infoAll();
+ unbroadcast_txids = pool.GetUnbroadcastTxs();
+ }
+
+ auto mid = SteadyClock::now();
+
+ try {
+ FILE* filestr{mockable_fopen_function(dump_path + ".new", "wb")};
+ if (!filestr) {
+ return false;
+ }
+
+ CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
+
+ uint64_t version = MEMPOOL_DUMP_VERSION;
+ file << version;
+
+ file << (uint64_t)vinfo.size();
+ for (const auto& i : vinfo) {
+ file << *(i.tx);
+ file << int64_t{count_seconds(i.m_time)};
+ file << int64_t{i.nFeeDelta};
+ mapDeltas.erase(i.tx->GetHash());
+ }
+
+ file << mapDeltas;
+
+ LogPrintf("Writing %d unbroadcast transactions to disk.\n", unbroadcast_txids.size());
+ file << unbroadcast_txids;
+
+ if (!skip_file_commit && !FileCommit(file.Get()))
+ throw std::runtime_error("FileCommit failed");
+ file.fclose();
+ if (!RenameOver(dump_path + ".new", dump_path)) {
+ throw std::runtime_error("Rename failed");
+ }
+ auto last = SteadyClock::now();
+
+ LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n",
+ Ticks<SecondsDouble>(mid - start),
+ Ticks<SecondsDouble>(last - mid));
+ } catch (const std::exception& e) {
+ LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
+ return false;
+ }
+ return true;
+}
+
+} // namespace kernel
diff --git a/src/kernel/mempool_persist.h b/src/kernel/mempool_persist.h
new file mode 100644
index 0000000000..9a15ec6dca
--- /dev/null
+++ b/src/kernel/mempool_persist.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_KERNEL_MEMPOOL_PERSIST_H
+#define BITCOIN_KERNEL_MEMPOOL_PERSIST_H
+
+#include <fs.h>
+
+class CChainState;
+class CTxMemPool;
+
+namespace kernel {
+
+/** Dump the mempool to disk. */
+bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path,
+ fsbridge::FopenFn mockable_fopen_function = fsbridge::fopen,
+ bool skip_file_commit = false);
+
+/** Load the mempool from disk. */
+bool LoadMempool(CTxMemPool& pool, const fs::path& load_path,
+ CChainState& active_chainstate,
+ fsbridge::FopenFn mockable_fopen_function = fsbridge::fopen);
+
+} // namespace kernel
+
+
+#endif // BITCOIN_KERNEL_MEMPOOL_PERSIST_H
diff --git a/src/kernel/validation_cache_sizes.h b/src/kernel/validation_cache_sizes.h
new file mode 100644
index 0000000000..72e4d1a52c
--- /dev/null
+++ b/src/kernel/validation_cache_sizes.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H
+#define BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H
+
+#include <script/sigcache.h>
+
+#include <cstddef>
+#include <limits>
+
+namespace kernel {
+struct ValidationCacheSizes {
+ size_t signature_cache_bytes{DEFAULT_MAX_SIG_CACHE_BYTES / 2};
+ size_t script_execution_cache_bytes{DEFAULT_MAX_SIG_CACHE_BYTES / 2};
+};
+}
+
+#endif // BITCOIN_KERNEL_VALIDATION_CACHE_SIZES_H
diff --git a/src/key.cpp b/src/key.cpp
index 9b0971a2dd..199808505d 100644
--- a/src/key.cpp
+++ b/src/key.cpp
@@ -333,6 +333,7 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
}
bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
+ if (nDepth == std::numeric_limits<unsigned char>::max()) return false;
out.nDepth = nDepth + 1;
CKeyID id = key.GetPubKey().GetID();
memcpy(out.vchFingerprint, &id, 4);
diff --git a/src/key.h b/src/key.h
index 12d03778a0..e9b78ebd44 100644
--- a/src/key.h
+++ b/src/key.h
@@ -146,7 +146,7 @@ public:
bool SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256* merkle_root, const uint256& aux) const;
//! Derive BIP32 child key.
- bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
+ [[nodiscard]] bool Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
/**
* Verify thoroughly whether a private key and a public key match.
@@ -176,7 +176,7 @@ struct CExtKey {
void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
- bool Derive(CExtKey& out, unsigned int nChild) const;
+ [[nodiscard]] bool Derive(CExtKey& out, unsigned int nChild) const;
CExtPubKey Neuter() const;
void SetSeed(Span<const std::byte> seed);
};
diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc
index 18626b327c..fac41be6ce 100644
--- a/src/leveldb/util/env_posix.cc
+++ b/src/leveldb/util/env_posix.cc
@@ -49,7 +49,7 @@ constexpr const int kDefaultMmapLimit = (sizeof(void*) >= 8) ? 4096 : 0;
int g_mmap_limit = kDefaultMmapLimit;
// Common flags defined for all posix open operations
-#if defined(HAVE_O_CLOEXEC)
+#if HAVE_O_CLOEXEC
constexpr const int kOpenBaseFlags = O_CLOEXEC;
#else
constexpr const int kOpenBaseFlags = 0;
diff --git a/src/mapport.cpp b/src/mapport.cpp
index 235e6f904c..6262e51879 100644
--- a/src/mapport.cpp
+++ b/src/mapport.cpp
@@ -19,7 +19,7 @@
#include <util/thread.h>
#ifdef USE_NATPMP
-#include <compat.h>
+#include <compat/compat.h>
#include <natpmp.h>
#endif // USE_NATPMP
diff --git a/src/mempool_args.cpp b/src/mempool_args.cpp
deleted file mode 100644
index 77caa127e9..0000000000
--- a/src/mempool_args.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2022 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include <mempool_args.h>
-
-#include <kernel/mempool_limits.h>
-#include <kernel/mempool_options.h>
-
-#include <util/system.h>
-
-using kernel::MemPoolLimits;
-using kernel::MemPoolOptions;
-
-namespace {
-void ApplyArgsManOptions(const ArgsManager& argsman, MemPoolLimits& mempool_limits)
-{
- mempool_limits.ancestor_count = argsman.GetIntArg("-limitancestorcount", mempool_limits.ancestor_count);
-
- if (auto vkb = argsman.GetIntArg("-limitancestorsize")) mempool_limits.ancestor_size_vbytes = *vkb * 1'000;
-
- mempool_limits.descendant_count = argsman.GetIntArg("-limitdescendantcount", mempool_limits.descendant_count);
-
- if (auto vkb = argsman.GetIntArg("-limitdescendantsize")) mempool_limits.descendant_size_vbytes = *vkb * 1'000;
-}
-}
-
-void ApplyArgsManOptions(const ArgsManager& argsman, MemPoolOptions& mempool_opts)
-{
- mempool_opts.check_ratio = argsman.GetIntArg("-checkmempool", mempool_opts.check_ratio);
-
- if (auto mb = argsman.GetIntArg("-maxmempool")) mempool_opts.max_size_bytes = *mb * 1'000'000;
-
- if (auto hours = argsman.GetIntArg("-mempoolexpiry")) mempool_opts.expiry = std::chrono::hours{*hours};
-
- mempool_opts.full_rbf = argsman.GetBoolArg("-mempoolfullrbf", mempool_opts.full_rbf);
-
- ApplyArgsManOptions(argsman, mempool_opts.limits);
-}
diff --git a/src/net.cpp b/src/net.cpp
index 90c73d583e..865ce2ea97 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -13,7 +13,7 @@
#include <addrman.h>
#include <banman.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <consensus/consensus.h>
#include <crypto/sha256.h>
#include <node/eviction.h>
@@ -85,8 +85,8 @@ static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000; // "many" vs "few" pe
/** The default timeframe for -maxuploadtarget. 1 day. */
static constexpr std::chrono::seconds MAX_UPLOAD_TIMEFRAME{60 * 60 * 24};
-// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization.
-#define FEELER_SLEEP_WINDOW 1
+// A random time period (0 to 1 seconds) is added to feeler connections to prevent synchronization.
+static constexpr auto FEELER_SLEEP_WINDOW{1s};
/** Used to pass flags to the Bind() function */
enum BindFlags {
@@ -187,7 +187,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
// it'll get a pile of addresses with newer timestamps.
// Seed nodes are given a random 'last seen time' of between one and two
// weeks ago.
- const int64_t nOneWeek = 7*24*60*60;
+ const auto one_week{7 * 24h};
std::vector<CAddress> vSeedsOut;
FastRandomContext rng;
CDataStream s(vSeedsIn, SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
@@ -195,7 +195,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
CService endpoint;
s >> endpoint;
CAddress addr{endpoint, GetDesirableServiceFlags(NODE_NONE)};
- addr.nTime = GetTime() - rng.randrange(nOneWeek) - nOneWeek;
+ addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - one_week, -one_week);
LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToString());
vSeedsOut.push_back(addr);
}
@@ -206,16 +206,13 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
// Otherwise, return the unroutable 0.0.0.0 but filled in with
// the normal parameters, since the IP may be changed to a useful
// one by discovery.
-CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices)
+CService GetLocalAddress(const CNetAddr& addrPeer)
{
- CAddress ret(CService(CNetAddr(),GetListenPort()), nLocalServices);
CService addr;
- if (GetLocal(addr, paddrPeer))
- {
- ret = CAddress(addr, nLocalServices);
+ if (GetLocal(addr, &addrPeer)) {
+ return addr;
}
- ret.nTime = GetAdjustedTime();
- return ret;
+ return CService{CNetAddr(), GetListenPort()};
}
static int GetnScore(const CService& addr)
@@ -233,35 +230,35 @@ bool IsPeerAddrLocalGood(CNode *pnode)
IsReachable(addrLocal.GetNetwork());
}
-std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode)
+std::optional<CService> GetLocalAddrForPeer(CNode& node)
{
- CAddress addrLocal = GetLocalAddress(&pnode->addr, pnode->GetLocalServices());
+ CService addrLocal{GetLocalAddress(node.addr)};
if (gArgs.GetBoolArg("-addrmantest", false)) {
// use IPv4 loopback during addrmantest
- addrLocal = CAddress(CService(LookupNumeric("127.0.0.1", GetListenPort())), pnode->GetLocalServices());
+ addrLocal = CService(LookupNumeric("127.0.0.1", GetListenPort()));
}
// If discovery is enabled, sometimes give our peer the address it
// tells us that it sees us as in case it has a better idea of our
// address than we do.
FastRandomContext rng;
- if (IsPeerAddrLocalGood(pnode) && (!addrLocal.IsRoutable() ||
+ if (IsPeerAddrLocalGood(&node) && (!addrLocal.IsRoutable() ||
rng.randbits((GetnScore(addrLocal) > LOCAL_MANUAL) ? 3 : 1) == 0))
{
- if (pnode->IsInboundConn()) {
+ if (node.IsInboundConn()) {
// For inbound connections, assume both the address and the port
// as seen from the peer.
- addrLocal = CAddress{pnode->GetAddrLocal(), addrLocal.nServices, addrLocal.nTime};
+ addrLocal = CService{node.GetAddrLocal()};
} else {
// For outbound connections, assume just the address as seen from
// the peer and leave the port in `addrLocal` as returned by
// `GetLocalAddress()` above. The peer has no way to observe our
// listening port when we have initiated the connection.
- addrLocal.SetIP(pnode->GetAddrLocal());
+ addrLocal.SetIP(node.GetAddrLocal());
}
}
if (addrLocal.IsRoutable() || gArgs.GetBoolArg("-addrmantest", false))
{
- LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToString(), pnode->GetId());
+ LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToString(), node.GetId());
return addrLocal;
}
// Address is unroutable. Don't advertise.
@@ -454,10 +451,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
}
}
- /// debug print
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "trying connection %s lastseen=%.1fhrs\n",
- pszDest ? pszDest : addrConnect.ToString(),
- pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime) / 3600.0);
+ pszDest ? pszDest : addrConnect.ToString(),
+ Ticks<HoursDouble>(pszDest ? 0h : Now<NodeSeconds>() - addrConnect.nTime));
// Resolve
const uint16_t default_port{pszDest != nullptr ? Params().GetDefaultPort(pszDest) :
@@ -543,7 +539,6 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
addr_bind = GetBindAddress(*sock);
}
CNode* pnode = new CNode(id,
- nLocalServices,
std::move(sock),
addrConnect,
CalculateKeyedNetGroup(addrConnect),
@@ -603,7 +598,6 @@ Network CNode::ConnectedThroughNetwork() const
void CNode::CopyStats(CNodeStats& stats)
{
stats.nodeid = this->GetId();
- X(nServices);
X(addr);
X(addrBind);
stats.m_network = ConnectedThroughNetwork();
@@ -880,7 +874,7 @@ bool CConnman::AttemptToEvictConnection()
.m_min_ping_time = node->m_min_ping_time,
.m_last_block_time = node->m_last_block_time,
.m_last_tx_time = node->m_last_tx_time,
- .fRelevantServices = HasAllDesirableServiceFlags(node->nServices),
+ .fRelevantServices = node->m_has_all_wanted_services,
.m_relay_txs = node->m_relays_txs.load(),
.fBloomFilter = node->m_bloom_filter_loaded.load(),
.nKeyedNetGroup = node->nKeyedNetGroup,
@@ -1014,7 +1008,6 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
CNode* pnode = new CNode(id,
- nodeServices,
std::move(sock),
addr,
CalculateKeyedNetGroup(addr),
@@ -1026,7 +1019,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
pnode->AddRef();
pnode->m_permissionFlags = permissionFlags;
pnode->m_prefer_evict = discouraged;
- m_msgproc->InitializeNode(pnode);
+ m_msgproc->InitializeNode(*pnode, nodeServices);
LogPrint(BCLog::NET, "connection from %s accepted\n", addr.ToString());
@@ -1474,9 +1467,8 @@ void CConnman::ThreadDNSAddressSeed()
unsigned int nMaxIPs = 256; // Limits number of IPs learned from a DNS seed
if (LookupHost(host, vIPs, nMaxIPs, true)) {
for (const CNetAddr& ip : vIPs) {
- int nOneDay = 24*3600;
CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
- addr.nTime = GetTime() - 3*nOneDay - rng.randrange(4*nOneDay); // use a random age between 3 and 7 days old
+ addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
vAdd.push_back(addr);
found++;
}
@@ -1573,6 +1565,7 @@ int CConnman::GetExtraBlockRelayCount() const
void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET_OPEN_CONNECTION);
+ FastRandomContext rng;
// Connect to specific addresses
if (!connect.empty())
{
@@ -1741,7 +1734,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
addrman.ResolveCollisions();
- int64_t nANow = GetAdjustedTime();
+ const auto current_time{NodeClock::now()};
int nTries = 0;
while (!interruptNet)
{
@@ -1764,7 +1757,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
break;
CAddress addr;
- int64_t addr_last_try{0};
+ NodeSeconds addr_last_try{0s};
if (fFeeler) {
// First, try to get a tried table collision address. This returns
@@ -1804,8 +1797,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
continue;
// only consider very recently tried nodes after 30 failed attempts
- if (nANow - addr_last_try < 600 && nTries < 30)
+ if (current_time - addr_last_try < 10min && nTries < 30) {
continue;
+ }
// for non-feelers, require all the services we'll want,
// for feelers, only require they be a full node (only because most
@@ -1826,12 +1820,11 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
}
if (addrConnect.IsValid()) {
-
if (fFeeler) {
// Add small amount of random noise before connection to avoid synchronization.
- int randsleep = GetRand<int>(FEELER_SLEEP_WINDOW * 1000);
- if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep)))
+ if (!interruptNet.sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) {
return;
+ }
LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString());
}
@@ -1964,7 +1957,7 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
if (grantOutbound)
grantOutbound->MoveTo(pnode->grantOutbound);
- m_msgproc->InitializeNode(pnode);
+ m_msgproc->InitializeNode(*pnode, nLocalServices);
{
LOCK(m_nodes_mutex);
m_nodes.push_back(pnode);
@@ -2708,7 +2701,10 @@ ServiceFlags CConnman::GetLocalServices() const
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
-CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, std::shared_ptr<Sock> sock, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion)
+CNode::CNode(NodeId idIn, std::shared_ptr<Sock> sock, const CAddress& addrIn,
+ uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn,
+ const CAddress& addrBindIn, const std::string& addrNameIn,
+ ConnectionType conn_type_in, bool inbound_onion)
: m_sock{sock},
m_connected{GetTime<std::chrono::seconds>()},
addr(addrIn),
@@ -2718,8 +2714,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, std::shared_ptr<Sock> s
nKeyedNetGroup(nKeyedNetGroupIn),
id(idIn),
nLocalHostNonce(nLocalHostNonceIn),
- m_conn_type(conn_type_in),
- nLocalServices(nLocalServicesIn)
+ m_conn_type(conn_type_in)
{
if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
@@ -2828,7 +2823,7 @@ void CaptureMessageToFile(const CAddress& addr,
fs::create_directories(base_path);
fs::path path = base_path / (is_incoming ? "msgs_recv.dat" : "msgs_sent.dat");
- CAutoFile f(fsbridge::fopen(path, "ab"), SER_DISK, CLIENT_VERSION);
+ AutoFile f{fsbridge::fopen(path, "ab")};
ser_writedata64(f, now.count());
f.write(MakeByteSpan(msg_type));
diff --git a/src/net.h b/src/net.h
index 6453ad1dc7..2036e9078c 100644
--- a/src/net.h
+++ b/src/net.h
@@ -8,7 +8,7 @@
#include <chainparams.h>
#include <common/bloom.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <node/connection_types.h>
#include <consensus/amount.h>
#include <crypto/siphash.h>
@@ -144,8 +144,8 @@ enum
};
bool IsPeerAddrLocalGood(CNode *pnode);
-/** Returns a local address that we should advertise to this peer */
-std::optional<CAddress> GetLocalAddrForPeer(CNode *pnode);
+/** Returns a local address that we should advertise to this peer. */
+std::optional<CService> GetLocalAddrForPeer(CNode& node);
/**
* Mark a network as reachable or unreachable (no automatic connects to it)
@@ -163,7 +163,7 @@ void RemoveLocal(const CService& addr);
bool SeenLocal(const CService& addr);
bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = nullptr);
-CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices);
+CService GetLocalAddress(const CNetAddr& addrPeer);
extern bool fDiscover;
@@ -187,7 +187,6 @@ class CNodeStats
{
public:
NodeId nodeid;
- ServiceFlags nServices;
std::chrono::seconds m_last_send;
std::chrono::seconds m_last_recv;
std::chrono::seconds m_last_tx_time;
@@ -346,7 +345,6 @@ public:
std::unique_ptr<TransportSerializer> m_serializer;
NetPermissionFlags m_permissionFlags{NetPermissionFlags::None};
- std::atomic<ServiceFlags> nServices{NODE_NONE};
/**
* Socket used for communication with the node.
@@ -399,8 +397,6 @@ public:
bool HasPermission(NetPermissionFlags permission) const {
return NetPermissions::HasFlag(m_permissionFlags, permission);
}
- bool fClient{false}; // set by version message
- bool m_limited_node{false}; //after BIP159, set by version message
/** fSuccessfullyConnected is set to true on receiving VERACK from the peer. */
std::atomic_bool fSuccessfullyConnected{false};
// Setting fDisconnect to true will cause the node to be disconnected the
@@ -484,6 +480,9 @@ public:
// Peer selected us as (compact blocks) high-bandwidth peer (BIP152)
std::atomic<bool> m_bip152_highbandwidth_from{false};
+ /** Whether this peer provides all services that we want. Used for eviction decisions */
+ std::atomic_bool m_has_all_wanted_services{false};
+
/** Whether we should relay transactions to this peer (their version
* message did not include fRelay=false and this is not a block-relay-only
* connection). This only changes from false to true. It will never change
@@ -514,7 +513,10 @@ public:
* criterium in CConnman::AttemptToEvictConnection. */
std::atomic<std::chrono::microseconds> m_min_ping_time{std::chrono::microseconds::max()};
- CNode(NodeId id, ServiceFlags nLocalServicesIn, std::shared_ptr<Sock> sock, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion);
+ CNode(NodeId id, std::shared_ptr<Sock> sock, const CAddress& addrIn,
+ uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn,
+ const CAddress& addrBindIn, const std::string& addrNameIn,
+ ConnectionType conn_type_in, bool inbound_onion);
CNode(const CNode&) = delete;
CNode& operator=(const CNode&) = delete;
@@ -572,11 +574,6 @@ public:
void CopyStats(CNodeStats& stats) EXCLUSIVE_LOCKS_REQUIRED(!m_subver_mutex, !m_addr_local_mutex, !cs_vSend, !cs_vRecv);
- ServiceFlags GetLocalServices() const
- {
- return nLocalServices;
- }
-
std::string ConnectionTypeAsString() const { return ::ConnectionTypeAsString(m_conn_type); }
/** A ping-pong round trip has completed successfully. Update latest and minimum ping times. */
@@ -591,23 +588,6 @@ private:
const ConnectionType m_conn_type;
std::atomic<int> m_greatest_common_version{INIT_PROTO_VERSION};
- //! Services offered to this peer.
- //!
- //! This is supplied by the parent CConnman during peer connection
- //! (CConnman::ConnectNode()) from its attribute of the same name.
- //!
- //! This is const because there is no protocol defined for renegotiating
- //! services initially offered to a peer. The set of local services we
- //! offer should not change after initialization.
- //!
- //! An interesting example of this is NODE_NETWORK and initial block
- //! download: a node which starts up from scratch doesn't have any blocks
- //! to serve, but still advertises NODE_NETWORK because it will eventually
- //! fulfill this role after IBD completes. P2P code is written in such a
- //! way that it can gracefully handle peers who don't make good on their
- //! service advertisements.
- const ServiceFlags nLocalServices;
-
std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread
// Our address, as reported by the peer
@@ -625,7 +605,7 @@ class NetEventsInterface
{
public:
/** Initialize a peer (setup state, queue any initial messages) */
- virtual void InitializeNode(CNode* pnode) = 0;
+ virtual void InitializeNode(CNode& node, ServiceFlags our_services) = 0;
/** Handle removal of a peer (clear state) */
virtual void FinalizeNode(const CNode& node) = 0;
@@ -1035,16 +1015,14 @@ private:
std::map<uint64_t, CachedAddrResponse> m_addr_response_caches;
/**
- * Services this instance offers.
+ * Services this node offers.
*
- * This data is replicated in each CNode instance we create during peer
- * connection (in ConnectNode()) under a member also called
- * nLocalServices.
+ * This data is replicated in each Peer instance we create.
*
* This data is not marked const, but after being set it should not
- * change. See the note in CNode::nLocalServices documentation.
+ * change.
*
- * \sa CNode::nLocalServices
+ * \sa Peer::our_services
*/
ServiceFlags nLocalServices;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 77fa23b594..ed78ae5a81 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -29,6 +29,7 @@
#include <scheduler.h>
#include <streams.h>
#include <sync.h>
+#include <timedata.h>
#include <tinyformat.h>
#include <txmempool.h>
#include <txorphanage.h>
@@ -207,6 +208,23 @@ struct Peer {
/** Same id as the CNode object for this peer */
const NodeId m_id{0};
+ /** Services we offered to this peer.
+ *
+ * This is supplied by CConnman during peer initialization. It's const
+ * because there is no protocol defined for renegotiating services
+ * initially offered to a peer. The set of local services we offer should
+ * not change after initialization.
+ *
+ * An interesting example of this is NODE_NETWORK and initial block
+ * download: a node which starts up from scratch doesn't have any blocks
+ * to serve, but still advertises NODE_NETWORK because it will eventually
+ * fulfill this role after IBD completes. P2P code is written in such a
+ * way that it can gracefully handle peers who don't make good on their
+ * service advertisements. */
+ const ServiceFlags m_our_services;
+ /** Services this peer offered to us. */
+ std::atomic<ServiceFlags> m_their_services{NODE_NONE};
+
/** Protects misbehavior data members */
Mutex m_misbehavior_mutex;
/** Accumulated misbehavior score for this peer */
@@ -352,6 +370,9 @@ struct Peer {
/** Set of txids to reconsider once their parent transactions have been accepted **/
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
+ /** Whether we've sent this peer a getheaders in response to an inv prior to initial-headers-sync completing */
+ bool m_inv_triggered_getheaders_before_sync{false};
+
/** Protects m_getdata_requests **/
Mutex m_getdata_requests_mutex;
/** Work queue of items requested by this peer **/
@@ -360,8 +381,9 @@ struct Peer {
/** Time of the last getheaders message to this peer */
NodeClock::time_point m_last_getheaders_timestamp{};
- Peer(NodeId id)
+ explicit Peer(NodeId id, ServiceFlags our_services)
: m_id{id}
+ , m_our_services{our_services}
{}
private:
@@ -410,8 +432,6 @@ struct CNodeState {
bool m_requested_hb_cmpctblocks{false};
/** Whether this peer will send us cmpctblocks if we request them. */
bool m_provides_cmpctblocks{false};
- //! Whether this peer can give us witnesses
- bool fHaveWitness{false};
/** State used to enforce CHAIN_SYNC_TIMEOUT and EXTRA_PEER_CHECK_INTERVAL logic.
*
@@ -482,7 +502,7 @@ public:
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex);
/** Implement NetEventsInterface */
- void InitializeNode(CNode* pnode) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
+ void InitializeNode(CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex);
@@ -492,7 +512,8 @@ public:
/** Implement PeerManager */
void StartScheduledTasks(CScheduler& scheduler) override;
void CheckForStaleTipAndEvictPeers() override;
- std::optional<std::string> FetchBlock(NodeId peer_id, const CBlockIndex& block_index) override;
+ std::optional<std::string> FetchBlock(NodeId peer_id, const CBlockIndex& block_index) override
+ EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; }
void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
@@ -578,7 +599,7 @@ private:
*/
bool MaybeSendGetHeaders(CNode& pfrom, const CBlockLocator& locator, Peer& peer);
/** Potentially fetch blocks from this peer upon receipt of a new headers tip */
- void HeadersDirectFetchBlocks(CNode& pfrom, const CBlockIndex* pindexLast);
+ void HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex* pindexLast);
/** Update peer state based on received headers message */
void UpdatePeerStateForReceivedHeaders(CNode& pfrom, const CBlockIndex *pindexLast, bool received_new_header, bool may_have_more_headers);
@@ -657,13 +678,16 @@ private:
/** Get a pointer to a mutable CNodeState. */
CNodeState* State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- uint32_t GetFetchFlags(const CNode& pfrom) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ uint32_t GetFetchFlags(const Peer& peer) const;
std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us};
/** Number of nodes with fSyncStarted. */
int nSyncStarted GUARDED_BY(cs_main) = 0;
+ /** Hash of the last block we received via INV */
+ uint256 m_last_block_inv_triggering_headers_sync{};
+
/**
* Sources of received blocks, saved to be able punish them when processing
* happens afterwards.
@@ -778,7 +802,7 @@ private:
/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has
* at most count entries.
*/
- void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void FindNextBlocksToDownload(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> > mapBlocksInFlight GUARDED_BY(cs_main);
@@ -848,6 +872,7 @@ private:
*
* May disconnect from the peer in the case of a bad request.
*
+ * @param[in] node The node that we received the request from
* @param[in] peer The peer that we received the request from
* @param[in] filter_type The filter type the request is for. Must be basic filters.
* @param[in] start_height The start height for the request
@@ -857,7 +882,7 @@ private:
* @param[out] filter_index The filter index, if the request can be serviced.
* @return True if the request can be serviced.
*/
- bool PrepareBlockFilterRequest(CNode& peer,
+ bool PrepareBlockFilterRequest(CNode& node, Peer& peer,
BlockFilterType filter_type, uint32_t start_height,
const uint256& stop_hash, uint32_t max_height_diff,
const CBlockIndex*& stop_index,
@@ -868,30 +893,33 @@ private:
*
* May disconnect from the peer in the case of a bad request.
*
+ * @param[in] node The node that we received the request from
* @param[in] peer The peer that we received the request from
* @param[in] vRecv The raw message received
*/
- void ProcessGetCFilters(CNode& peer, CDataStream& vRecv);
+ void ProcessGetCFilters(CNode& node, Peer& peer, CDataStream& vRecv);
/**
* Handle a cfheaders request.
*
* May disconnect from the peer in the case of a bad request.
*
+ * @param[in] node The node that we received the request from
* @param[in] peer The peer that we received the request from
* @param[in] vRecv The raw message received
*/
- void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv);
+ void ProcessGetCFHeaders(CNode& node, Peer& peer, CDataStream& vRecv);
/**
* Handle a getcfcheckpt request.
*
* May disconnect from the peer in the case of a bad request.
*
+ * @param[in] node The node that we received the request from
* @param[in] peer The peer that we received the request from
* @param[in] vRecv The raw message received
*/
- void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv);
+ void ProcessGetCFCheckPt(CNode& node, Peer& peer, CDataStream& vRecv);
/** Checks if address relay is permitted with peer. If needed, initializes
* the m_addr_known bloom filter and sets m_addr_relay_enabled to true.
@@ -955,6 +983,26 @@ static void AddKnownTx(Peer& peer, const uint256& hash)
tx_relay->m_tx_inventory_known_filter.insert(hash);
}
+/** Whether this peer can serve us blocks. */
+static bool CanServeBlocks(const Peer& peer)
+{
+ return peer.m_their_services & (NODE_NETWORK|NODE_NETWORK_LIMITED);
+}
+
+/** Whether this peer can only serve limited recent blocks (e.g. because
+ * it prunes old blocks) */
+static bool IsLimitedPeer(const Peer& peer)
+{
+ return (!(peer.m_their_services & NODE_NETWORK) &&
+ (peer.m_their_services & NODE_NETWORK_LIMITED));
+}
+
+/** Whether this peer can serve us witness data */
+static bool CanServeWitnesses(const Peer& peer)
+{
+ return peer.m_their_services & NODE_WITNESS;
+}
+
std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
std::chrono::seconds average_interval)
{
@@ -1148,17 +1196,17 @@ void PeerManagerImpl::UpdateBlockAvailability(NodeId nodeid, const uint256 &hash
}
}
-void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller)
+void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller)
{
if (count == 0)
return;
vBlocks.reserve(vBlocks.size() + count);
- CNodeState *state = State(nodeid);
+ CNodeState *state = State(peer.m_id);
assert(state != nullptr);
// Make sure pindexBestKnownBlock is up to date, we'll need it.
- ProcessBlockAvailability(nodeid);
+ ProcessBlockAvailability(peer.m_id);
if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.ActiveChain().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
// This peer has nothing interesting.
@@ -1206,7 +1254,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
// We consider the chain that this peer is on invalid.
return;
}
- if (!State(nodeid)->fHaveWitness && DeploymentActiveAt(*pindex, m_chainman, Consensus::DEPLOYMENT_SEGWIT)) {
+ if (!CanServeWitnesses(peer) && DeploymentActiveAt(*pindex, m_chainman, Consensus::DEPLOYMENT_SEGWIT)) {
// We wouldn't download this block or its descendants from this peer.
return;
}
@@ -1217,7 +1265,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
// The block is not already downloaded, and not yet in flight.
if (pindex->nHeight > nWindowEnd) {
// We reached the end of the window.
- if (vBlocks.size() == 0 && waitingfor != nodeid) {
+ if (vBlocks.size() == 0 && waitingfor != peer.m_id) {
// We aren't able to fetch anything, but we would be if the download window was one larger.
nodeStaller = waitingfor;
}
@@ -1239,10 +1287,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer)
{
- // Note that pnode->GetLocalServices() is a reflection of the local
- // services we were offering when the CNode object was created for this
- // peer.
- uint64_t my_services{pnode.GetLocalServices()};
+ uint64_t my_services{peer.m_our_services};
const int64_t nTime{count_seconds(GetTime<std::chrono::seconds>())};
uint64_t nonce = pnode.GetLocalNonce();
const int nNodeStartingHeight{m_best_height};
@@ -1299,21 +1344,21 @@ void PeerManagerImpl::UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_s
if (state) state->m_last_block_announcement = time_in_seconds;
}
-void PeerManagerImpl::InitializeNode(CNode *pnode)
+void PeerManagerImpl::InitializeNode(CNode& node, ServiceFlags our_services)
{
- NodeId nodeid = pnode->GetId();
+ NodeId nodeid = node.GetId();
{
LOCK(cs_main);
- m_node_states.emplace_hint(m_node_states.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(pnode->IsInboundConn()));
+ m_node_states.emplace_hint(m_node_states.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(node.IsInboundConn()));
assert(m_txrequest.Count(nodeid) == 0);
}
- PeerRef peer = std::make_shared<Peer>(nodeid);
+ PeerRef peer = std::make_shared<Peer>(nodeid, our_services);
{
LOCK(m_peer_mutex);
m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);
}
- if (!pnode->IsInboundConn()) {
- PushNodeVersion(*pnode, *peer);
+ if (!node.IsInboundConn()) {
+ PushNodeVersion(node, *peer);
}
}
@@ -1431,6 +1476,7 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c
PeerRef peer = GetPeerRef(nodeid);
if (peer == nullptr) return false;
+ stats.their_services = peer->m_their_services;
stats.m_starting_height = peer->m_starting_height;
// It is common for nodes with good ping times to suddenly become lagged,
// due to a new block arriving or other large transfer.
@@ -1585,12 +1631,14 @@ std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl
if (fImporting) return "Importing...";
if (fReindex) return "Reindexing...";
- LOCK(cs_main);
// Ensure this peer exists and hasn't been disconnected
- CNodeState* state = State(peer_id);
- if (state == nullptr) return "Peer does not exist";
+ PeerRef peer = GetPeerRef(peer_id);
+ if (peer == nullptr) return "Peer does not exist";
+
// Ignore pre-segwit peers
- if (!state->fHaveWitness) return "Pre-SegWit peer";
+ if (!CanServeWitnesses(*peer)) return "Pre-SegWit peer";
+
+ LOCK(cs_main);
// Mark block as in-flight unless it already is (for this peer).
// If a block was already in-flight for a different peer, its BLOCKTXN
@@ -1974,7 +2022,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
}
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
if (!pfrom.HasPermission(NetPermissionFlags::NoBan) && (
- (((pfrom.GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom.GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (m_chainman.ActiveChain().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
+ (((peer.m_our_services & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((peer.m_our_services & NODE_NETWORK) != NODE_NETWORK) && (m_chainman.ActiveChain().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
)) {
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold, disconnect peer=%d\n", pfrom.GetId());
//disconnect node and prevent it from stalling (would otherwise wait for the missing block)
@@ -2191,10 +2239,10 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic
}
}
-uint32_t PeerManagerImpl::GetFetchFlags(const CNode& pfrom) const EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+uint32_t PeerManagerImpl::GetFetchFlags(const Peer& peer) const
{
uint32_t nFetchFlags = 0;
- if (State(pfrom.GetId())->fHaveWitness) {
+ if (CanServeWitnesses(peer)) {
nFetchFlags |= MSG_WITNESS_FLAG;
}
return nFetchFlags;
@@ -2289,7 +2337,7 @@ bool PeerManagerImpl::MaybeSendGetHeaders(CNode& pfrom, const CBlockLocator& loc
* We require that the given tip have at least as much work as our tip, and for
* our current tip to be "close to synced" (see CanDirectFetch()).
*/
-void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const CBlockIndex* pindexLast)
+void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const Peer& peer, const CBlockIndex* pindexLast)
{
const CNetMsgMaker msgMaker(pfrom.GetCommonVersion());
@@ -2304,7 +2352,7 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const CBlockIndex*
while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
!IsBlockRequested(pindexWalk->GetBlockHash()) &&
- (!DeploymentActiveAt(*pindexWalk, m_chainman, Consensus::DEPLOYMENT_SEGWIT) || State(pfrom.GetId())->fHaveWitness)) {
+ (!DeploymentActiveAt(*pindexWalk, m_chainman, Consensus::DEPLOYMENT_SEGWIT) || CanServeWitnesses(peer))) {
// We don't have this block, and it's not yet in flight.
vToFetch.push_back(pindexWalk);
}
@@ -2326,7 +2374,7 @@ void PeerManagerImpl::HeadersDirectFetchBlocks(CNode& pfrom, const CBlockIndex*
// Can't download any more from this peer
break;
}
- uint32_t nFetchFlags = GetFetchFlags(pfrom);
+ uint32_t nFetchFlags = GetFetchFlags(peer);
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
BlockRequested(pfrom.GetId(), *pindex);
LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n",
@@ -2471,7 +2519,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
UpdatePeerStateForReceivedHeaders(pfrom, pindexLast, received_new_header, nCount == MAX_HEADERS_RESULTS);
// Consider immediately downloading blocks.
- HeadersDirectFetchBlocks(pfrom, pindexLast);
+ HeadersDirectFetchBlocks(pfrom, peer, pindexLast);
return;
}
@@ -2555,7 +2603,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
}
}
-bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer,
+bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer,
BlockFilterType filter_type, uint32_t start_height,
const uint256& stop_hash, uint32_t max_height_diff,
const CBlockIndex*& stop_index,
@@ -2563,11 +2611,11 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer,
{
const bool supported_filter_type =
(filter_type == BlockFilterType::BASIC &&
- (peer.GetLocalServices() & NODE_COMPACT_FILTERS));
+ (peer.m_our_services & NODE_COMPACT_FILTERS));
if (!supported_filter_type) {
LogPrint(BCLog::NET, "peer %d requested unsupported block filter type: %d\n",
- peer.GetId(), static_cast<uint8_t>(filter_type));
- peer.fDisconnect = true;
+ node.GetId(), static_cast<uint8_t>(filter_type));
+ node.fDisconnect = true;
return false;
}
@@ -2578,8 +2626,8 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer,
// Check that the stop block exists and the peer would be allowed to fetch it.
if (!stop_index || !BlockRequestAllowed(stop_index)) {
LogPrint(BCLog::NET, "peer %d requested invalid block hash: %s\n",
- peer.GetId(), stop_hash.ToString());
- peer.fDisconnect = true;
+ node.GetId(), stop_hash.ToString());
+ node.fDisconnect = true;
return false;
}
}
@@ -2588,14 +2636,14 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer,
if (start_height > stop_height) {
LogPrint(BCLog::NET, "peer %d sent invalid getcfilters/getcfheaders with " /* Continued */
"start height %d and stop height %d\n",
- peer.GetId(), start_height, stop_height);
- peer.fDisconnect = true;
+ node.GetId(), start_height, stop_height);
+ node.fDisconnect = true;
return false;
}
if (stop_height - start_height >= max_height_diff) {
LogPrint(BCLog::NET, "peer %d requested too many cfilters/cfheaders: %d / %d\n",
- peer.GetId(), stop_height - start_height + 1, max_height_diff);
- peer.fDisconnect = true;
+ node.GetId(), stop_height - start_height + 1, max_height_diff);
+ node.fDisconnect = true;
return false;
}
@@ -2608,7 +2656,7 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer,
return true;
}
-void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv)
+void PeerManagerImpl::ProcessGetCFilters(CNode& node,Peer& peer, CDataStream& vRecv)
{
uint8_t filter_type_ser;
uint32_t start_height;
@@ -2620,7 +2668,7 @@ void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv)
const CBlockIndex* stop_index;
BlockFilterIndex* filter_index;
- if (!PrepareBlockFilterRequest(peer, filter_type, start_height, stop_hash,
+ if (!PrepareBlockFilterRequest(node, peer, filter_type, start_height, stop_hash,
MAX_GETCFILTERS_SIZE, stop_index, filter_index)) {
return;
}
@@ -2633,13 +2681,13 @@ void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv)
}
for (const auto& filter : filters) {
- CSerializedNetMsg msg = CNetMsgMaker(peer.GetCommonVersion())
+ CSerializedNetMsg msg = CNetMsgMaker(node.GetCommonVersion())
.Make(NetMsgType::CFILTER, filter);
- m_connman.PushMessage(&peer, std::move(msg));
+ m_connman.PushMessage(&node, std::move(msg));
}
}
-void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv)
+void PeerManagerImpl::ProcessGetCFHeaders(CNode& node, Peer& peer, CDataStream& vRecv)
{
uint8_t filter_type_ser;
uint32_t start_height;
@@ -2651,7 +2699,7 @@ void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv)
const CBlockIndex* stop_index;
BlockFilterIndex* filter_index;
- if (!PrepareBlockFilterRequest(peer, filter_type, start_height, stop_hash,
+ if (!PrepareBlockFilterRequest(node, peer, filter_type, start_height, stop_hash,
MAX_GETCFHEADERS_SIZE, stop_index, filter_index)) {
return;
}
@@ -2674,16 +2722,16 @@ void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv)
return;
}
- CSerializedNetMsg msg = CNetMsgMaker(peer.GetCommonVersion())
+ CSerializedNetMsg msg = CNetMsgMaker(node.GetCommonVersion())
.Make(NetMsgType::CFHEADERS,
filter_type_ser,
stop_index->GetBlockHash(),
prev_header,
filter_hashes);
- m_connman.PushMessage(&peer, std::move(msg));
+ m_connman.PushMessage(&node, std::move(msg));
}
-void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv)
+void PeerManagerImpl::ProcessGetCFCheckPt(CNode& node, Peer& peer, CDataStream& vRecv)
{
uint8_t filter_type_ser;
uint256 stop_hash;
@@ -2694,7 +2742,7 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv)
const CBlockIndex* stop_index;
BlockFilterIndex* filter_index;
- if (!PrepareBlockFilterRequest(peer, filter_type, /*start_height=*/0, stop_hash,
+ if (!PrepareBlockFilterRequest(node, peer, filter_type, /*start_height=*/0, stop_hash,
/*max_height_diff=*/std::numeric_limits<uint32_t>::max(),
stop_index, filter_index)) {
return;
@@ -2715,12 +2763,12 @@ void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv)
}
}
- CSerializedNetMsg msg = CNetMsgMaker(peer.GetCommonVersion())
+ CSerializedNetMsg msg = CNetMsgMaker(node.GetCommonVersion())
.Make(NetMsgType::CFCHECKPT,
filter_type_ser,
stop_index->GetBlockHash(),
headers);
- m_connman.PushMessage(&peer, std::move(msg));
+ m_connman.PushMessage(&node, std::move(msg));
}
void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing)
@@ -2842,7 +2890,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
m_connman.PushMessage(&pfrom, msg_maker.Make(NetMsgType::VERACK));
- pfrom.nServices = nServices;
+ pfrom.m_has_all_wanted_services = HasAllDesirableServiceFlags(nServices);
+ peer->m_their_services = nServices;
pfrom.SetAddrLocal(addrMe);
{
LOCK(pfrom.m_subver_mutex);
@@ -2850,18 +2899,12 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
peer->m_starting_height = starting_height;
- // set nodes not relaying blocks and tx and not serving (parts) of the historical blockchain as "clients"
- pfrom.fClient = (!(nServices & NODE_NETWORK) && !(nServices & NODE_NETWORK_LIMITED));
-
- // set nodes not capable of serving the complete blockchain history as "limited nodes"
- pfrom.m_limited_node = (!(nServices & NODE_NETWORK) && (nServices & NODE_NETWORK_LIMITED));
-
// We only initialize the m_tx_relay data structure if:
// - this isn't an outbound block-relay-only connection; and
// - fRelay=true or we're offering NODE_BLOOM to this peer
// (NODE_BLOOM means that the peer may turn on tx relay later)
if (!pfrom.IsBlockOnlyConn() &&
- (fRelay || (pfrom.GetLocalServices() & NODE_BLOOM))) {
+ (fRelay || (peer->m_our_services & NODE_BLOOM))) {
auto* const tx_relay = peer->SetTxRelay();
{
LOCK(tx_relay->m_bloom_filter_mutex);
@@ -2870,17 +2913,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (fRelay) pfrom.m_relays_txs = true;
}
- if((nServices & NODE_WITNESS))
- {
- LOCK(cs_main);
- State(pfrom.GetId())->fHaveWitness = true;
- }
-
// Potentially mark this peer as a preferred download peer.
{
LOCK(cs_main);
CNodeState* state = State(pfrom.GetId());
- state->fPreferredDownload = (!pfrom.IsInboundConn() || pfrom.HasPermission(NetPermissionFlags::NoBan)) && !pfrom.IsAddrFetchConn() && !pfrom.fClient;
+ state->fPreferredDownload = (!pfrom.IsInboundConn() || pfrom.HasPermission(NetPermissionFlags::NoBan)) && !pfrom.IsAddrFetchConn() && CanServeBlocks(*peer);
m_num_preferred_download_peers += state->fPreferredDownload;
}
@@ -2899,7 +2936,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// indicate to the peer that we will participate in addr relay.
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
{
- CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices());
+ CAddress addr{GetLocalAddress(pfrom.addr), peer->m_our_services, Now<NodeSeconds>()};
FastRandomContext insecure_rand;
if (addr.IsRoutable())
{
@@ -3104,8 +3141,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// Store the new addresses
std::vector<CAddress> vAddrOk;
- int64_t nNow = GetAdjustedTime();
- int64_t nSince = nNow - 10 * 60;
+ const auto current_a_time{Now<NodeSeconds>()};
// Update/increment addr rate limiting bucket.
const auto current_time{GetTime<std::chrono::microseconds>()};
@@ -3141,8 +3177,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (!MayHaveUsefulAddressDB(addr.nServices) && !HasAllDesirableServiceFlags(addr.nServices))
continue;
- if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
- addr.nTime = nNow - 5 * 24 * 60 * 60;
+ if (addr.nTime <= NodeSeconds{100000000s} || addr.nTime > current_a_time + 10min) {
+ addr.nTime = current_a_time - 5 * 24h;
+ }
AddAddressKnown(*peer, addr);
if (m_banman && (m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr))) {
// Do not process banned/discouraged addresses beyond remembering we received them
@@ -3150,7 +3187,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
++num_proc;
bool fReachable = IsReachable(addr);
- if (addr.nTime > nSince && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) {
+ if (addr.nTime > current_a_time - 10min && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) {
// Relay to a limited number of other nodes
RelayAddress(pfrom.GetId(), addr, fReachable);
}
@@ -3163,7 +3200,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
LogPrint(BCLog::NET, "Received addr: %u addresses (%u processed, %u rate-limited) from peer=%d\n",
vAddr.size(), num_proc, num_rate_limit, pfrom.GetId());
- m_addrman.Add(vAddrOk, pfrom.addr, 2 * 60 * 60);
+ m_addrman.Add(vAddrOk, pfrom.addr, 2h);
if (vAddr.size() < 1000) peer->m_getaddr_sent = false;
// AddrFetch: Require multiple addresses to avoid disconnecting on self-announcements
@@ -3209,8 +3246,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
UpdateBlockAvailability(pfrom.GetId(), inv.hash);
if (!fAlreadyHave && !fImporting && !fReindex && !IsBlockRequested(inv.hash)) {
// Headers-first is the primary method of announcement on
- // the network. If a node fell back to sending blocks by inv,
- // it's probably for a re-org. The final block hash
+ // the network. If a node fell back to sending blocks by
+ // inv, it may be for a re-org, or because we haven't
+ // completed initial headers sync. The final block hash
// provided should be the highest, so send a getheaders and
// then fetch the blocks we need to catch up.
best_block = &inv.hash;
@@ -3235,10 +3273,30 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (best_block != nullptr) {
- if (MaybeSendGetHeaders(pfrom, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *peer)) {
- LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n",
- m_chainman.m_best_header->nHeight, best_block->ToString(),
- pfrom.GetId());
+ // If we haven't started initial headers-sync with this peer, then
+ // consider sending a getheaders now. On initial startup, there's a
+ // reliability vs bandwidth tradeoff, where we are only trying to do
+ // initial headers sync with one peer at a time, with a long
+ // timeout (at which point, if the sync hasn't completed, we will
+ // disconnect the peer and then choose another). In the meantime,
+ // as new blocks are found, we are willing to add one new peer per
+ // block to sync with as well, to sync quicker in the case where
+ // our initial peer is unresponsive (but less bandwidth than we'd
+ // use if we turned on sync with all peers).
+ CNodeState& state{*Assert(State(pfrom.GetId()))};
+ if (state.fSyncStarted || (!peer->m_inv_triggered_getheaders_before_sync && *best_block != m_last_block_inv_triggering_headers_sync)) {
+ if (MaybeSendGetHeaders(pfrom, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *peer)) {
+ LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n",
+ m_chainman.m_best_header->nHeight, best_block->ToString(),
+ pfrom.GetId());
+ }
+ if (!state.fSyncStarted) {
+ peer->m_inv_triggered_getheaders_before_sync = true;
+ // Update the last block hash that triggered a new headers
+ // sync, so that we don't turn on headers sync with more
+ // than 1 new peer every new block.
+ m_last_block_inv_triggering_headers_sync = *best_block;
+ }
}
}
@@ -3600,10 +3658,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// DoS prevention: do not allow m_orphanage to grow unbounded (see CVE-2012-3789)
unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, gArgs.GetIntArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS));
- unsigned int nEvicted = m_orphanage.LimitOrphans(nMaxOrphanTx);
- if (nEvicted > 0) {
- LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted);
- }
+ m_orphanage.LimitOrphans(nMaxOrphanTx);
} else {
LogPrint(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s\n",tx.GetHash().ToString());
// We will continue to reject this tx since it has rejected
@@ -3758,7 +3813,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// We requested this block for some reason, but our mempool will probably be useless
// so we just grab the block via normal getdata
std::vector<CInv> vInv(1);
- vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
+ vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(*peer), cmpctblock.header.GetHash());
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
}
return;
@@ -3794,7 +3849,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
} else if (status == READ_STATUS_FAILED) {
// Duplicate txindexes, the block is now in-flight, so just request it
std::vector<CInv> vInv(1);
- vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
+ vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(*peer), cmpctblock.header.GetHash());
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
return;
}
@@ -3837,7 +3892,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// We requested this block, but its far into the future, so our
// mempool will probably be useless - request the block normally
std::vector<CInv> vInv(1);
- vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(pfrom), cmpctblock.header.GetHash());
+ vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(*peer), cmpctblock.header.GetHash());
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, vInv));
return;
} else {
@@ -3921,7 +3976,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
} else if (status == READ_STATUS_FAILED) {
// Might have collided, fall back to getdata now :(
std::vector<CInv> invs;
- invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom), resp.blockhash));
+ invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(*peer), resp.blockhash));
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETDATA, invs));
} else {
// Block is either okay, or possibly we received
@@ -4061,7 +4116,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (msg_type == NetMsgType::MEMPOOL) {
- if (!(pfrom.GetLocalServices() & NODE_BLOOM) && !pfrom.HasPermission(NetPermissionFlags::Mempool))
+ if (!(peer->m_our_services & NODE_BLOOM) && !pfrom.HasPermission(NetPermissionFlags::Mempool))
{
if (!pfrom.HasPermission(NetPermissionFlags::NoBan))
{
@@ -4164,7 +4219,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (msg_type == NetMsgType::FILTERLOAD) {
- if (!(pfrom.GetLocalServices() & NODE_BLOOM)) {
+ if (!(peer->m_our_services & NODE_BLOOM)) {
LogPrint(BCLog::NET, "filterload received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
@@ -4189,7 +4244,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (msg_type == NetMsgType::FILTERADD) {
- if (!(pfrom.GetLocalServices() & NODE_BLOOM)) {
+ if (!(peer->m_our_services & NODE_BLOOM)) {
LogPrint(BCLog::NET, "filteradd received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
@@ -4217,7 +4272,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (msg_type == NetMsgType::FILTERCLEAR) {
- if (!(pfrom.GetLocalServices() & NODE_BLOOM)) {
+ if (!(peer->m_our_services & NODE_BLOOM)) {
LogPrint(BCLog::NET, "filterclear received despite not offering bloom services from peer=%d; disconnecting\n", pfrom.GetId());
pfrom.fDisconnect = true;
return;
@@ -4248,17 +4303,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (msg_type == NetMsgType::GETCFILTERS) {
- ProcessGetCFilters(pfrom, vRecv);
+ ProcessGetCFilters(pfrom, *peer, vRecv);
return;
}
if (msg_type == NetMsgType::GETCFHEADERS) {
- ProcessGetCFHeaders(pfrom, vRecv);
+ ProcessGetCFHeaders(pfrom, *peer, vRecv);
return;
}
if (msg_type == NetMsgType::GETCFCHECKPT) {
- ProcessGetCFCheckPt(pfrom, vRecv);
+ ProcessGetCFCheckPt(pfrom, *peer, vRecv);
return;
}
@@ -4654,9 +4709,10 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
if (peer.m_next_local_addr_send != 0us) {
peer.m_addr_known->reset();
}
- if (std::optional<CAddress> local_addr = GetLocalAddrForPeer(&node)) {
+ if (std::optional<CService> local_service = GetLocalAddrForPeer(node)) {
+ CAddress local_addr{*local_service, peer.m_our_services, Now<NodeSeconds>()};
FastRandomContext insecure_rand;
- PushAddress(peer, *local_addr, insecure_rand);
+ PushAddress(peer, local_addr, insecure_rand);
}
peer.m_next_local_addr_send = GetExponentialRand(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
@@ -4730,8 +4786,8 @@ void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, Peer& peer, std::chrono::mi
}
if (current_time > peer.m_next_send_feefilter) {
CAmount filterToSend = g_filter_rounder.round(currentFilter);
- // We always have a fee filter of at least minRelayTxFee
- filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
+ // We always have a fee filter of at least the min relay fee
+ filterToSend = std::max(filterToSend, m_mempool.m_min_relay_feerate.GetFeePerK());
if (filterToSend != peer.m_fee_filter_sent) {
m_connman.PushMessage(&pto, CNetMsgMaker(pto.GetCommonVersion()).Make(NetMsgType::FEEFILTER, filterToSend));
peer.m_fee_filter_sent = filterToSend;
@@ -4840,7 +4896,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
bool sync_blocks_and_headers_from_peer = false;
if (state.fPreferredDownload) {
sync_blocks_and_headers_from_peer = true;
- } else if (!pto->fClient && !pto->IsAddrFetchConn()) {
+ } else if (CanServeBlocks(*peer) && !pto->IsAddrFetchConn()) {
// Typically this is an inbound peer. If we don't have any outbound
// peers, or if we aren't downloading any blocks from such peers,
// then allow block downloads from this peer, too.
@@ -4855,7 +4911,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
}
}
- if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) {
+ if (!state.fSyncStarted && CanServeBlocks(*peer) && !fImporting && !fReindex) {
// Only actively request headers from a single peer, unless we're close to today.
if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) || m_chainman.m_best_header->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
const CBlockIndex* pindexStart = m_chainman.m_best_header;
@@ -5232,12 +5288,12 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Message: getdata (blocks)
//
std::vector<CInv> vGetData;
- if (!pto->fClient && ((sync_blocks_and_headers_from_peer && !pto->m_limited_node) || !m_chainman.ActiveChainstate().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
+ if (CanServeBlocks(*peer) && ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) || !m_chainman.ActiveChainstate().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
std::vector<const CBlockIndex*> vToDownload;
NodeId staller = -1;
- FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
+ FindNextBlocksToDownload(*peer, MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
for (const CBlockIndex *pindex : vToDownload) {
- uint32_t nFetchFlags = GetFetchFlags(*pto);
+ uint32_t nFetchFlags = GetFetchFlags(*peer);
vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
BlockRequested(pto->GetId(), *pindex);
LogPrint(BCLog::NET, "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
@@ -5264,7 +5320,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (!AlreadyHaveTx(gtxid)) {
LogPrint(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",
gtxid.GetHash().ToString(), pto->GetId());
- vGetData.emplace_back(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*pto)), gtxid.GetHash());
+ vGetData.emplace_back(gtxid.IsWtxid() ? MSG_WTX : (MSG_TX | GetFetchFlags(*peer)), gtxid.GetHash());
if (vGetData.size() >= MAX_GETDATA_SZ) {
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
vGetData.clear();
diff --git a/src/net_processing.h b/src/net_processing.h
index 5fbae98c27..bcda9614d4 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -34,6 +34,7 @@ struct CNodeStateStats {
uint64_t m_addr_processed = 0;
uint64_t m_addr_rate_limited = 0;
bool m_addr_relay_enabled{false};
+ ServiceFlags their_services;
};
class PeerManager : public CValidationInterface, public NetEventsInterface
diff --git a/src/netaddress.h b/src/netaddress.h
index 47ba045334..e52beb783d 100644
--- a/src/netaddress.h
+++ b/src/netaddress.h
@@ -9,7 +9,7 @@
#include <config/bitcoin-config.h>
#endif
-#include <compat.h>
+#include <compat/compat.h>
#include <crypto/siphash.h>
#include <prevector.h>
#include <random.h>
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 030f462ed9..4b8d2f8d0c 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -5,7 +5,7 @@
#include <netbase.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <sync.h>
#include <tinyformat.h>
#include <util/sock.h>
diff --git a/src/netbase.h b/src/netbase.h
index bf7522210d..fadc8b418e 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -9,7 +9,7 @@
#include <config/bitcoin-config.h>
#endif
-#include <compat.h>
+#include <compat/compat.h>
#include <netaddress.h>
#include <serialize.h>
#include <util/sock.h>
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index cadafcaa8d..601d0bdf58 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -21,6 +21,7 @@
#include <util/system.h>
#include <validation.h>
+#include <map>
#include <unordered_map>
namespace node {
@@ -471,7 +472,7 @@ static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const
fileout << blockundo;
// calculate & write checksum
- CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
+ HashWriter hasher{};
hasher << hashBlock;
hasher << blockundo;
fileout << hasher.GetHash();
@@ -823,7 +824,7 @@ struct CImportingNow {
}
};
-void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args)
+void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args, const fs::path& mempool_path)
{
SetSyscallSandboxPolicy(SyscallSandboxPolicy::INITIALIZATION_LOAD_BLOCKS);
ScheduleBatchPriority();
@@ -834,6 +835,9 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
// -reindex
if (fReindex) {
int nFile = 0;
+ // Map of disk positions for blocks with unknown parent (only used for reindex);
+ // parent hash -> child disk position, multiple children can have the same parent.
+ std::multimap<uint256, FlatFilePos> blocks_with_unknown_parent;
while (true) {
FlatFilePos pos(nFile, 0);
if (!fs::exists(GetBlockPosFilename(pos))) {
@@ -844,7 +848,7 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
break; // This error is logged in OpenBlockFile
}
LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile);
- chainman.ActiveChainstate().LoadExternalBlockFile(file, &pos);
+ chainman.ActiveChainstate().LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent);
if (ShutdownRequested()) {
LogPrintf("Shutdown requested. Exit %s\n", __func__);
return;
@@ -893,6 +897,6 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
return;
}
} // End scope of CImportingNow
- chainman.ActiveChainstate().LoadMempool(args);
+ chainman.ActiveChainstate().LoadMempool(mempool_path);
}
} // namespace node
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index e017f3f427..9b76371aae 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -211,7 +211,7 @@ bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, c
bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex);
-void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args);
+void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args, const fs::path& mempool_path);
} // namespace node
#endif // BITCOIN_NODE_BLOCKSTORAGE_H
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index 54ba5b7966..ad9293f172 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -4,66 +4,75 @@
#include <node/chainstate.h>
+#include <chain.h>
+#include <coins.h>
#include <consensus/params.h>
#include <node/blockstorage.h>
+#include <node/caches.h>
+#include <sync.h>
+#include <threadsafety.h>
+#include <tinyformat.h>
+#include <txdb.h>
+#include <uint256.h>
+#include <util/time.h>
+#include <util/translation.h>
#include <validation.h>
+#include <algorithm>
+#include <atomic>
+#include <cassert>
+#include <memory>
+#include <vector>
+
namespace node {
-std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
- ChainstateManager& chainman,
- CTxMemPool* mempool,
- bool fPruneMode,
- bool fReindexChainState,
- int64_t nBlockTreeDBCache,
- int64_t nCoinDBCache,
- int64_t nCoinCacheUsage,
- bool block_tree_db_in_memory,
- bool coins_db_in_memory,
- std::function<bool()> shutdown_requested,
- std::function<void()> coins_error_cb)
+ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes,
+ const ChainstateLoadOptions& options)
{
auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
- return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
+ return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
};
LOCK(cs_main);
- chainman.InitializeChainstate(mempool);
- chainman.m_total_coinstip_cache = nCoinCacheUsage;
- chainman.m_total_coinsdb_cache = nCoinDBCache;
+ chainman.InitializeChainstate(options.mempool);
+ chainman.m_total_coinstip_cache = cache_sizes.coins;
+ chainman.m_total_coinsdb_cache = cache_sizes.coins_db;
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
// new CBlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
pblocktree.reset();
- pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, block_tree_db_in_memory, fReset));
+ pblocktree.reset(new CBlockTreeDB(cache_sizes.block_tree_db, options.block_tree_db_in_memory, options.reindex));
- if (fReset) {
+ if (options.reindex) {
pblocktree->WriteReindexing(true);
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
- if (fPruneMode)
+ if (options.prune) {
CleanupBlockRevFiles();
+ }
}
- if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
+ if (options.check_interrupt && options.check_interrupt()) return {ChainstateLoadStatus::INTERRUPTED, {}};
// LoadBlockIndex will load m_have_pruned if we've ever removed a
// block file from disk.
- // Note that it also sets fReindex based on the disk flag!
- // From here on out fReindex and fReset mean something different!
+ // Note that it also sets fReindex global based on the disk flag!
+ // From here on, fReindex and options.reindex values may be different!
if (!chainman.LoadBlockIndex()) {
- if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
- return ChainstateLoadingError::ERROR_LOADING_BLOCK_DB;
+ if (options.check_interrupt && options.check_interrupt()) return {ChainstateLoadStatus::INTERRUPTED, {}};
+ return {ChainstateLoadStatus::FAILURE, _("Error loading block database")};
}
if (!chainman.BlockIndex().empty() &&
!chainman.m_blockman.LookupBlockIndex(chainman.GetConsensus().hashGenesisBlock)) {
- return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK;
+ // If the loaded chain has a wrong genesis, bail out immediately
+ // (we're likely using a testnet datadir, or the other way around).
+ return {ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB, _("Incorrect or no genesis block found. Wrong datadir for network?")};
}
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
// in the past, but is now trying to run unpruned.
- if (chainman.m_blockman.m_have_pruned && !fPruneMode) {
- return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
+ if (chainman.m_blockman.m_have_pruned && !options.prune) {
+ return {ChainstateLoadStatus::FAILURE, _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain")};
}
// At this point blocktree args are consistent with what's on disk.
@@ -71,7 +80,7 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
// (otherwise we use the one already on disk).
// This is called again in ThreadImport after the reindex completes.
if (!fReindex && !chainman.ActiveChainstate().LoadGenesisBlock()) {
- return ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED;
+ return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")};
}
// At this point we're either in reindex or we've loaded a useful
@@ -79,57 +88,56 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
for (CChainState* chainstate : chainman.GetAll()) {
chainstate->InitCoinsDB(
- /*cache_size_bytes=*/nCoinDBCache,
- /*in_memory=*/coins_db_in_memory,
- /*should_wipe=*/fReset || fReindexChainState);
+ /*cache_size_bytes=*/cache_sizes.coins_db,
+ /*in_memory=*/options.coins_db_in_memory,
+ /*should_wipe=*/options.reindex || options.reindex_chainstate);
- if (coins_error_cb) {
- chainstate->CoinsErrorCatcher().AddReadErrCallback(coins_error_cb);
+ if (options.coins_error_cb) {
+ chainstate->CoinsErrorCatcher().AddReadErrCallback(options.coins_error_cb);
}
// Refuse to load unsupported database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (chainstate->CoinsDB().NeedsUpgrade()) {
- return ChainstateLoadingError::ERROR_CHAINSTATE_UPGRADE_FAILED;
+ return {ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB, _("Unsupported chainstate database format found. "
+ "Please restart with -reindex-chainstate. This will "
+ "rebuild the chainstate database.")};
}
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
if (!chainstate->ReplayBlocks()) {
- return ChainstateLoadingError::ERROR_REPLAYBLOCKS_FAILED;
+ return {ChainstateLoadStatus::FAILURE, _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.")};
}
// The on-disk coinsdb is now in a good state, create the cache
- chainstate->InitCoinsCache(nCoinCacheUsage);
+ chainstate->InitCoinsCache(cache_sizes.coins);
assert(chainstate->CanFlushToDisk());
if (!is_coinsview_empty(chainstate)) {
// LoadChainTip initializes the chain based on CoinsTip()'s best block
if (!chainstate->LoadChainTip()) {
- return ChainstateLoadingError::ERROR_LOADCHAINTIP_FAILED;
+ return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")};
}
assert(chainstate->m_chain.Tip() != nullptr);
}
}
- if (!fReset) {
+ if (!options.reindex) {
auto chainstates{chainman.GetAll()};
if (std::any_of(chainstates.begin(), chainstates.end(),
[](const CChainState* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {
- return ChainstateLoadingError::ERROR_BLOCKS_WITNESS_INSUFFICIENTLY_VALIDATED;
- }
+ return {ChainstateLoadStatus::FAILURE, strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."),
+ chainman.GetConsensus().SegwitHeight)};
+ };
}
- return std::nullopt;
+ return {ChainstateLoadStatus::SUCCESS, {}};
}
-std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManager& chainman,
- bool fReset,
- bool fReindexChainState,
- int check_blocks,
- int check_level)
+ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options)
{
auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
- return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
+ return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
};
LOCK(cs_main);
@@ -138,18 +146,20 @@ std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManage
if (!is_coinsview_empty(chainstate)) {
const CBlockIndex* tip = chainstate->m_chain.Tip();
if (tip && tip->nTime > GetTime() + MAX_FUTURE_BLOCK_TIME) {
- return ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE;
+ return {ChainstateLoadStatus::FAILURE, _("The block database contains a block which appears to be from the future. "
+ "This may be due to your computer's date and time being set incorrectly. "
+ "Only rebuild the block database if you are sure that your computer's date and time are correct")};
}
if (!CVerifyDB().VerifyDB(
*chainstate, chainman.GetConsensus(), chainstate->CoinsDB(),
- check_level,
- check_blocks)) {
- return ChainstateLoadVerifyError::ERROR_CORRUPTED_BLOCK_DB;
+ options.check_level,
+ options.check_blocks)) {
+ return {ChainstateLoadStatus::FAILURE, _("Corrupted block database detected")};
}
}
}
- return std::nullopt;
+ return {ChainstateLoadStatus::SUCCESS, {}};
}
} // namespace node
diff --git a/src/node/chainstate.h b/src/node/chainstate.h
index ff7935e8e0..2289310ece 100644
--- a/src/node/chainstate.h
+++ b/src/node/chainstate.h
@@ -5,30 +5,41 @@
#ifndef BITCOIN_NODE_CHAINSTATE_H
#define BITCOIN_NODE_CHAINSTATE_H
+#include <util/translation.h>
+#include <validation.h>
+
#include <cstdint>
#include <functional>
-#include <optional>
+#include <tuple>
-class ChainstateManager;
class CTxMemPool;
-namespace Consensus {
-struct Params;
-} // namespace Consensus
namespace node {
-enum class ChainstateLoadingError {
- ERROR_LOADING_BLOCK_DB,
- ERROR_BAD_GENESIS_BLOCK,
- ERROR_PRUNED_NEEDS_REINDEX,
- ERROR_LOAD_GENESIS_BLOCK_FAILED,
- ERROR_CHAINSTATE_UPGRADE_FAILED,
- ERROR_REPLAYBLOCKS_FAILED,
- ERROR_LOADCHAINTIP_FAILED,
- ERROR_GENERIC_BLOCKDB_OPEN_FAILED,
- ERROR_BLOCKS_WITNESS_INSUFFICIENTLY_VALIDATED,
- SHUTDOWN_PROBED,
+
+struct CacheSizes;
+
+struct ChainstateLoadOptions {
+ CTxMemPool* mempool{nullptr};
+ bool block_tree_db_in_memory{false};
+ bool coins_db_in_memory{false};
+ bool reindex{false};
+ bool reindex_chainstate{false};
+ bool prune{false};
+ int64_t check_blocks{DEFAULT_CHECKBLOCKS};
+ int64_t check_level{DEFAULT_CHECKLEVEL};
+ std::function<bool()> check_interrupt;
+ std::function<void()> coins_error_cb;
};
+//! Chainstate load status. Simple applications can just check for the success
+//! case, and treat other cases as errors. More complex applications may want to
+//! try reindexing in the generic failure case, and pass an interrupt callback
+//! and exit cleanly in the interrupted case.
+enum class ChainstateLoadStatus { SUCCESS, FAILURE, FAILURE_INCOMPATIBLE_DB, INTERRUPTED };
+
+//! Chainstate load status code and optional error string.
+using ChainstateLoadResult = std::tuple<ChainstateLoadStatus, bilingual_str>;
+
/** This sequence can have 4 types of outcomes:
*
* 1. Success
@@ -40,45 +51,11 @@ enum class ChainstateLoadingError {
* 4. Hard failure
* - a failure that definitively cannot be recovered from with a reindex
*
- * Currently, LoadChainstate returns a std::optional<ChainstateLoadingError>
- * which:
- *
- * - if has_value()
- * - Either "Soft failure", "Hard failure", or "Shutdown requested",
- * differentiable by the specific enumerator.
- *
- * Note that a return value of SHUTDOWN_PROBED means ONLY that "during
- * this sequence, when we explicitly checked shutdown_requested() at
- * arbitrary points, one of those calls returned true". Therefore, a
- * return value other than SHUTDOWN_PROBED does not guarantee that
- * shutdown hasn't been called indirectly.
- * - else
- * - Success!
+ * LoadChainstate returns a (status code, error string) tuple.
*/
-std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
- ChainstateManager& chainman,
- CTxMemPool* mempool,
- bool fPruneMode,
- bool fReindexChainState,
- int64_t nBlockTreeDBCache,
- int64_t nCoinDBCache,
- int64_t nCoinCacheUsage,
- bool block_tree_db_in_memory,
- bool coins_db_in_memory,
- std::function<bool()> shutdown_requested = nullptr,
- std::function<void()> coins_error_cb = nullptr);
-
-enum class ChainstateLoadVerifyError {
- ERROR_BLOCK_FROM_FUTURE,
- ERROR_CORRUPTED_BLOCK_DB,
- ERROR_GENERIC_FAILURE,
-};
-
-std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManager& chainman,
- bool fReset,
- bool fReindexChainState,
- int check_blocks,
- int check_level);
+ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes,
+ const ChainstateLoadOptions& options);
+ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options);
} // namespace node
#endif // BITCOIN_NODE_CHAINSTATE_H
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index 93aa9e526b..2c845d0127 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -19,6 +19,7 @@
#include <netaddress.h>
#include <netbase.h>
#include <node/blockstorage.h>
+#include <kernel/chain.h>
#include <node/coin.h>
#include <node/context.h>
#include <node/transaction.h>
@@ -35,7 +36,6 @@
#include <shutdown.h>
#include <support/allocators/secure.h>
#include <sync.h>
-#include <timedata.h>
#include <txmempool.h>
#include <uint256.h>
#include <univalue.h>
@@ -66,6 +66,8 @@ using interfaces::Node;
using interfaces::WalletLoader;
namespace node {
+// All members of the classes in this namespace are intentionally public, as the
+// classes themselves are private.
namespace {
#ifdef ENABLE_EXTERNAL_SIGNER
class ExternalSignerImpl : public interfaces::ExternalSigner
@@ -73,15 +75,12 @@ class ExternalSignerImpl : public interfaces::ExternalSigner
public:
ExternalSignerImpl(::ExternalSigner signer) : m_signer(std::move(signer)) {}
std::string getName() override { return m_signer.m_name; }
-private:
::ExternalSigner m_signer;
};
#endif
class NodeImpl : public Node
{
-private:
- ChainstateManager& chainman() { return *Assert(m_context->chainman); }
public:
explicit NodeImpl(NodeContext& context) { setContext(&context); }
void initLogging() override { InitLogging(*Assert(m_context->args)); }
@@ -288,12 +287,7 @@ public:
}
double getVerificationProgress() override
{
- const CBlockIndex* tip;
- {
- LOCK(::cs_main);
- tip = chainman().ActiveChain().Tip();
- }
- return GuessVerificationProgress(chainman().GetParams().TxData(), tip);
+ return GuessVerificationProgress(chainman().GetParams().TxData(), WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()));
}
bool isInitialBlockDownload() override {
return chainman().ActiveChainstate().IsInitialBlockDownload();
@@ -307,7 +301,11 @@ public:
}
}
bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
- CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
+ CFeeRate getDustRelayFee() override
+ {
+ if (!m_context->mempool) return CFeeRate{DUST_RELAY_TX_FEE};
+ return m_context->mempool->m_dust_relay_feerate;
+ }
UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
{
JSONRPCRequest req;
@@ -389,6 +387,7 @@ public:
{
m_context = context;
}
+ ChainstateManager& chainman() { return *Assert(m_context->chainman); }
NodeContext* m_context{nullptr};
};
@@ -401,6 +400,7 @@ bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<Rec
if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax();
if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast();
if (block.m_in_active_chain) *block.m_in_active_chain = active[index->nHeight] == index;
+ if (block.m_locator) { *block.m_locator = active.GetLocator(index); }
if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active);
if (block.m_data) {
REVERSE_LOCK(lock);
@@ -426,11 +426,11 @@ public:
}
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
{
- m_notifications->blockConnected(*block, index->nHeight);
+ m_notifications->blockConnected(kernel::MakeBlockInfo(index, block.get()));
}
void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override
{
- m_notifications->blockDisconnected(*block, index->nHeight);
+ m_notifications->blockDisconnected(kernel::MakeBlockInfo(index, block.get()));
}
void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override
{
@@ -500,40 +500,28 @@ public:
class ChainImpl : public Chain
{
-private:
- ChainstateManager& chainman() { return *Assert(m_node.chainman); }
public:
explicit ChainImpl(NodeContext& node) : m_node(node) {}
std::optional<int> getHeight() override
{
- LOCK(::cs_main);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- int height = active.Height();
- if (height >= 0) {
- return height;
- }
- return std::nullopt;
+ const int height{WITH_LOCK(::cs_main, return chainman().ActiveChain().Height())};
+ return height >= 0 ? std::optional{height} : std::nullopt;
}
uint256 getBlockHash(int height) override
{
LOCK(::cs_main);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- CBlockIndex* block = active[height];
- assert(block);
- return block->GetBlockHash();
+ return Assert(chainman().ActiveChain()[height])->GetBlockHash();
}
bool haveBlockOnDisk(int height) override
{
LOCK(::cs_main);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- CBlockIndex* block = active[height];
+ const CBlockIndex* block{chainman().ActiveChain()[height]};
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
}
CBlockLocator getTipLocator() override
{
LOCK(::cs_main);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- return active.GetLocator();
+ return chainman().ActiveChain().GetLocator();
}
CBlockLocator getActiveChainLocator(const uint256& block_hash) override
{
@@ -545,8 +533,7 @@ public:
std::optional<int> findLocatorFork(const CBlockLocator& locator) override
{
LOCK(::cs_main);
- const CChainState& active = Assert(m_node.chainman)->ActiveChainstate();
- if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
+ if (const CBlockIndex* fork = chainman().ActiveChainstate().FindForkInGlobalIndex(locator)) {
return fork->nHeight;
}
return std::nullopt;
@@ -554,20 +541,19 @@ public:
bool findBlock(const uint256& hash, const FoundBlock& block) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- return FillBlock(m_node.chainman->m_blockman.LookupBlockIndex(hash), block, lock, active);
+ return FillBlock(chainman().m_blockman.LookupBlockIndex(hash), block, lock, chainman().ActiveChain());
}
bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
+ const CChain& active = chainman().ActiveChain();
return FillBlock(active.FindEarliestAtLeast(min_time, min_height), block, lock, active);
}
bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- if (const CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash)) {
+ const CChain& active = chainman().ActiveChain();
+ if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) {
return FillBlock(ancestor, ancestor_out, lock, active);
}
@@ -577,18 +563,17 @@ public:
bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- const CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash);
- const CBlockIndex* ancestor = m_node.chainman->m_blockman.LookupBlockIndex(ancestor_hash);
+ const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash);
+ const CBlockIndex* ancestor = chainman().m_blockman.LookupBlockIndex(ancestor_hash);
if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;
- return FillBlock(ancestor, ancestor_out, lock, active);
+ return FillBlock(ancestor, ancestor_out, lock, chainman().ActiveChain());
}
bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override
{
WAIT_LOCK(cs_main, lock);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- const CBlockIndex* block1 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash1);
- const CBlockIndex* block2 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash2);
+ const CChain& active = chainman().ActiveChain();
+ const CBlockIndex* block1 = chainman().m_blockman.LookupBlockIndex(block_hash1);
+ const CBlockIndex* block2 = chainman().m_blockman.LookupBlockIndex(block_hash2);
const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;
// Using & instead of && below to avoid short circuiting and leaving
// output uninitialized. Cast bool to int to avoid -Wbitwise-instead-of-logical
@@ -695,13 +680,25 @@ public:
if (!m_node.mempool) return {};
return m_node.mempool->GetMinFee();
}
- CFeeRate relayMinFee() override { return ::minRelayTxFee; }
- CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
- CFeeRate relayDustFee() override { return ::dustRelayFee; }
+ CFeeRate relayMinFee() override
+ {
+ if (!m_node.mempool) return CFeeRate{DEFAULT_MIN_RELAY_TX_FEE};
+ return m_node.mempool->m_min_relay_feerate;
+ }
+ CFeeRate relayIncrementalFee() override
+ {
+ if (!m_node.mempool) return CFeeRate{DEFAULT_INCREMENTAL_RELAY_FEE};
+ return m_node.mempool->m_incremental_relay_feerate;
+ }
+ CFeeRate relayDustFee() override
+ {
+ if (!m_node.mempool) return CFeeRate{DUST_RELAY_TX_FEE};
+ return m_node.mempool->m_dust_relay_feerate;
+ }
bool havePruned() override
{
LOCK(::cs_main);
- return m_node.chainman->m_blockman.m_have_pruned;
+ return chainman().m_blockman.m_have_pruned;
}
bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
bool isInitialBlockDownload() override {
@@ -721,11 +718,7 @@ public:
}
void waitForNotificationsIfTipChanged(const uint256& old_tip) override
{
- if (!old_tip.IsNull()) {
- LOCK(::cs_main);
- const CChain& active = Assert(m_node.chainman)->ActiveChain();
- if (old_tip == active.Tip()->GetBlockHash()) return;
- }
+ if (!old_tip.IsNull() && old_tip == WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()->GetBlockHash())) return;
SyncWithValidationInterfaceQueue();
}
std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
@@ -775,6 +768,13 @@ public:
notifications.transactionAddedToMempool(entry.GetSharedTx(), 0 /* mempool_sequence */);
}
}
+ bool hasAssumedValidChain() override
+ {
+ return chainman().IsSnapshotActive();
+ }
+
+ NodeContext* context() override { return &m_node; }
+ ChainstateManager& chainman() { return *Assert(m_node.chainman); }
NodeContext& m_node;
};
} // namespace
diff --git a/src/node/mempool_args.cpp b/src/node/mempool_args.cpp
new file mode 100644
index 0000000000..60993f1d8d
--- /dev/null
+++ b/src/node/mempool_args.cpp
@@ -0,0 +1,99 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <node/mempool_args.h>
+
+#include <kernel/mempool_limits.h>
+#include <kernel/mempool_options.h>
+
+#include <chainparams.h>
+#include <consensus/amount.h>
+#include <logging.h>
+#include <policy/feerate.h>
+#include <policy/policy.h>
+#include <tinyformat.h>
+#include <util/error.h>
+#include <util/moneystr.h>
+#include <util/system.h>
+#include <util/translation.h>
+
+#include <chrono>
+#include <memory>
+
+using kernel::MemPoolLimits;
+using kernel::MemPoolOptions;
+
+namespace {
+void ApplyArgsManOptions(const ArgsManager& argsman, MemPoolLimits& mempool_limits)
+{
+ mempool_limits.ancestor_count = argsman.GetIntArg("-limitancestorcount", mempool_limits.ancestor_count);
+
+ if (auto vkb = argsman.GetIntArg("-limitancestorsize")) mempool_limits.ancestor_size_vbytes = *vkb * 1'000;
+
+ mempool_limits.descendant_count = argsman.GetIntArg("-limitdescendantcount", mempool_limits.descendant_count);
+
+ if (auto vkb = argsman.GetIntArg("-limitdescendantsize")) mempool_limits.descendant_size_vbytes = *vkb * 1'000;
+}
+}
+
+std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& argsman, const CChainParams& chainparams, MemPoolOptions& mempool_opts)
+{
+ mempool_opts.check_ratio = argsman.GetIntArg("-checkmempool", mempool_opts.check_ratio);
+
+ if (auto mb = argsman.GetIntArg("-maxmempool")) mempool_opts.max_size_bytes = *mb * 1'000'000;
+
+ if (auto hours = argsman.GetIntArg("-mempoolexpiry")) mempool_opts.expiry = std::chrono::hours{*hours};
+
+ // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
+ // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
+ if (argsman.IsArgSet("-incrementalrelayfee")) {
+ if (std::optional<CAmount> inc_relay_fee = ParseMoney(argsman.GetArg("-incrementalrelayfee", ""))) {
+ mempool_opts.incremental_relay_feerate = CFeeRate{inc_relay_fee.value()};
+ } else {
+ return AmountErrMsg("incrementalrelayfee", argsman.GetArg("-incrementalrelayfee", ""));
+ }
+ }
+
+ if (argsman.IsArgSet("-minrelaytxfee")) {
+ if (std::optional<CAmount> min_relay_feerate = ParseMoney(argsman.GetArg("-minrelaytxfee", ""))) {
+ // High fee check is done afterward in CWallet::Create()
+ mempool_opts.min_relay_feerate = CFeeRate{min_relay_feerate.value()};
+ } else {
+ return AmountErrMsg("minrelaytxfee", argsman.GetArg("-minrelaytxfee", ""));
+ }
+ } else if (mempool_opts.incremental_relay_feerate > mempool_opts.min_relay_feerate) {
+ // Allow only setting incremental fee to control both
+ mempool_opts.min_relay_feerate = mempool_opts.incremental_relay_feerate;
+ LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n", mempool_opts.min_relay_feerate.ToString());
+ }
+
+ // Feerate used to define dust. Shouldn't be changed lightly as old
+ // implementations may inadvertently create non-standard transactions
+ if (argsman.IsArgSet("-dustrelayfee")) {
+ if (std::optional<CAmount> parsed = ParseMoney(argsman.GetArg("-dustrelayfee", ""))) {
+ mempool_opts.dust_relay_feerate = CFeeRate{parsed.value()};
+ } else {
+ return AmountErrMsg("dustrelayfee", argsman.GetArg("-dustrelayfee", ""));
+ }
+ }
+
+ mempool_opts.permit_bare_multisig = argsman.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG);
+
+ if (argsman.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER)) {
+ mempool_opts.max_datacarrier_bytes = argsman.GetIntArg("-datacarriersize", MAX_OP_RETURN_RELAY);
+ } else {
+ mempool_opts.max_datacarrier_bytes = std::nullopt;
+ }
+
+ mempool_opts.require_standard = !argsman.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
+ if (!chainparams.IsTestChain() && !mempool_opts.require_standard) {
+ return strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.NetworkIDString());
+ }
+
+ mempool_opts.full_rbf = argsman.GetBoolArg("-mempoolfullrbf", mempool_opts.full_rbf);
+
+ ApplyArgsManOptions(argsman, mempool_opts.limits);
+
+ return std::nullopt;
+}
diff --git a/src/mempool_args.h b/src/node/mempool_args.h
index 9a4abe6618..52d8b4f265 100644
--- a/src/mempool_args.h
+++ b/src/node/mempool_args.h
@@ -2,21 +2,26 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_MEMPOOL_ARGS_H
-#define BITCOIN_MEMPOOL_ARGS_H
+#ifndef BITCOIN_NODE_MEMPOOL_ARGS_H
+#define BITCOIN_NODE_MEMPOOL_ARGS_H
+
+#include <optional>
class ArgsManager;
+class CChainParams;
+struct bilingual_str;
namespace kernel {
struct MemPoolOptions;
};
/**
* Overlay the options set in \p argsman on top of corresponding members in \p mempool_opts.
+ * Returns an error if one was encountered.
*
* @param[in] argsman The ArgsManager in which to check set options.
* @param[in,out] mempool_opts The MemPoolOptions to modify according to \p argsman.
*/
-void ApplyArgsManOptions(const ArgsManager& argsman, kernel::MemPoolOptions& mempool_opts);
+[[nodiscard]] std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& argsman, const CChainParams& chainparams, kernel::MemPoolOptions& mempool_opts);
-#endif // BITCOIN_MEMPOOL_ARGS_H
+#endif // BITCOIN_NODE_MEMPOOL_ARGS_H
diff --git a/src/node/mempool_persist_args.cpp b/src/node/mempool_persist_args.cpp
new file mode 100644
index 0000000000..4e775869c6
--- /dev/null
+++ b/src/node/mempool_persist_args.cpp
@@ -0,0 +1,23 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <node/mempool_persist_args.h>
+
+#include <fs.h>
+#include <util/system.h>
+#include <validation.h>
+
+namespace node {
+
+bool ShouldPersistMempool(const ArgsManager& argsman)
+{
+ return argsman.GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL);
+}
+
+fs::path MempoolPath(const ArgsManager& argsman)
+{
+ return argsman.GetDataDirNet() / "mempool.dat";
+}
+
+} // namespace node
diff --git a/src/node/mempool_persist_args.h b/src/node/mempool_persist_args.h
new file mode 100644
index 0000000000..f719ec62ab
--- /dev/null
+++ b/src/node/mempool_persist_args.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_NODE_MEMPOOL_PERSIST_ARGS_H
+#define BITCOIN_NODE_MEMPOOL_PERSIST_ARGS_H
+
+#include <fs.h>
+
+class ArgsManager;
+
+namespace node {
+
+/**
+ * Default for -persistmempool, indicating whether the node should attempt to
+ * automatically load the mempool on start and save to disk on shutdown
+ */
+static constexpr bool DEFAULT_PERSIST_MEMPOOL{true};
+
+bool ShouldPersistMempool(const ArgsManager& argsman);
+fs::path MempoolPath(const ArgsManager& argsman);
+
+} // namespace node
+
+#endif // BITCOIN_NODE_MEMPOOL_PERSIST_ARGS_H
diff --git a/src/node/psbt.cpp b/src/node/psbt.cpp
index 5a932f435d..57162cd679 100644
--- a/src/node/psbt.cpp
+++ b/src/node/psbt.cpp
@@ -137,7 +137,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
if (success) {
CTransaction ctx = CTransaction(mtx);
- size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
+ size_t size(GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS), ::nBytesPerSigOp));
result.estimated_vsize = size;
// Estimate fee rate
CFeeRate feerate(fee, size);
diff --git a/src/node/validation_cache_args.cpp b/src/node/validation_cache_args.cpp
new file mode 100644
index 0000000000..5ea0a8ca0a
--- /dev/null
+++ b/src/node/validation_cache_args.cpp
@@ -0,0 +1,34 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <node/validation_cache_args.h>
+
+#include <kernel/validation_cache_sizes.h>
+
+#include <util/system.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <optional>
+
+using kernel::ValidationCacheSizes;
+
+namespace node {
+void ApplyArgsManOptions(const ArgsManager& argsman, ValidationCacheSizes& cache_sizes)
+{
+ if (auto max_size = argsman.GetIntArg("-maxsigcachesize")) {
+ // 1. When supplied with a max_size of 0, both InitSignatureCache and
+ // InitScriptExecutionCache create the minimum possible cache (2
+ // elements). Therefore, we can use 0 as a floor here.
+ // 2. Multiply first, divide after to avoid integer truncation.
+ size_t clamped_size_each = std::max<int64_t>(*max_size, 0) * (1 << 20) / 2;
+ cache_sizes = {
+ .signature_cache_bytes = clamped_size_each,
+ .script_execution_cache_bytes = clamped_size_each,
+ };
+ }
+}
+} // namespace node
diff --git a/src/node/validation_cache_args.h b/src/node/validation_cache_args.h
new file mode 100644
index 0000000000..f447c13b49
--- /dev/null
+++ b/src/node/validation_cache_args.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_NODE_VALIDATION_CACHE_ARGS_H
+#define BITCOIN_NODE_VALIDATION_CACHE_ARGS_H
+
+class ArgsManager;
+namespace kernel {
+struct ValidationCacheSizes;
+};
+
+namespace node {
+void ApplyArgsManOptions(const ArgsManager& argsman, kernel::ValidationCacheSizes& cache_sizes);
+} // namespace node
+
+#endif // BITCOIN_NODE_VALIDATION_CACHE_ARGS_H
diff --git a/src/outputtype.cpp b/src/outputtype.cpp
index 19366295e6..5be9942d7d 100644
--- a/src/outputtype.cpp
+++ b/src/outputtype.cpp
@@ -91,8 +91,6 @@ CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore,
case OutputType::BECH32: {
CTxDestination witdest = WitnessV0ScriptHash(script);
CScript witprog = GetScriptForDestination(witdest);
- // Check if the resulting program is solvable (i.e. doesn't use an uncompressed key)
- if (!IsSolvable(keystore, witprog)) return ScriptHash(script);
// Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
keystore.AddCScript(witprog);
if (type == OutputType::BECH32) {
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 27a6ab221f..2b940be07e 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -161,13 +161,13 @@ public:
unsigned int GetMaxConfirms() const { return scale * confAvg.size(); }
/** Write state of estimation data to a file*/
- void Write(CAutoFile& fileout) const;
+ void Write(AutoFile& fileout) const;
/**
* Read saved state of estimation data from a file and replace all internal data structures and
* variables with this state.
*/
- void Read(CAutoFile& filein, int nFileVersion, size_t numBuckets);
+ void Read(AutoFile& filein, int nFileVersion, size_t numBuckets);
};
@@ -390,7 +390,7 @@ double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
return median;
}
-void TxConfirmStats::Write(CAutoFile& fileout) const
+void TxConfirmStats::Write(AutoFile& fileout) const
{
fileout << Using<EncodedDoubleFormatter>(decay);
fileout << scale;
@@ -400,7 +400,7 @@ void TxConfirmStats::Write(CAutoFile& fileout) const
fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
}
-void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets)
+void TxConfirmStats::Read(AutoFile& filein, int nFileVersion, size_t numBuckets)
{
// Read data file and do some very basic sanity checking
// buckets and bucketMap are not updated yet, so don't access them
@@ -546,7 +546,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator(const fs::path& estimation_filepath
longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
// If the fee estimation file is present, read recorded estimations
- CAutoFile est_file(fsbridge::fopen(m_estimation_filepath, "rb"), SER_DISK, CLIENT_VERSION);
+ AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "rb")};
if (est_file.IsNull() || !Read(est_file)) {
LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
}
@@ -904,13 +904,13 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
void CBlockPolicyEstimator::Flush() {
FlushUnconfirmed();
- CAutoFile est_file(fsbridge::fopen(m_estimation_filepath, "wb"), SER_DISK, CLIENT_VERSION);
+ AutoFile est_file{fsbridge::fopen(m_estimation_filepath, "wb")};
if (est_file.IsNull() || !Write(est_file)) {
LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(m_estimation_filepath));
}
}
-bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
+bool CBlockPolicyEstimator::Write(AutoFile& fileout) const
{
try {
LOCK(m_cs_fee_estimator);
@@ -935,7 +935,7 @@ bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
return true;
}
-bool CBlockPolicyEstimator::Read(CAutoFile& filein)
+bool CBlockPolicyEstimator::Read(AutoFile& filein)
{
try {
LOCK(m_cs_fee_estimator);
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 9ee5c2938a..e4628bf853 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -20,7 +20,7 @@
#include <string>
#include <vector>
-class CAutoFile;
+class AutoFile;
class CTxMemPoolEntry;
class TxConfirmStats;
@@ -220,11 +220,11 @@ public:
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Write estimation data to a file */
- bool Write(CAutoFile& fileout) const
+ bool Write(AutoFile& fileout) const
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Read estimation data from a file */
- bool Read(CAutoFile& filein)
+ bool Read(AutoFile& filein)
EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
/** Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool */
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index f6452266b7..5086542865 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -67,7 +67,7 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
}
-bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
+bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType)
{
std::vector<std::vector<unsigned char> > vSolutions;
whichType = Solver(scriptPubKey, vSolutions);
@@ -82,15 +82,16 @@ bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
return false;
if (m < 1 || m > n)
return false;
- } else if (whichType == TxoutType::NULL_DATA &&
- (!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) {
- return false;
+ } else if (whichType == TxoutType::NULL_DATA) {
+ if (!max_datacarrier_bytes || scriptPubKey.size() > *max_datacarrier_bytes) {
+ return false;
+ }
}
return true;
}
-bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
+bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
{
if (tx.nVersion > TX_MAX_STANDARD_VERSION || tx.nVersion < 1) {
reason = "version";
@@ -130,7 +131,7 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
unsigned int nDataOut = 0;
TxoutType whichType;
for (const CTxOut& txout : tx.vout) {
- if (!::IsStandard(txout.scriptPubKey, whichType)) {
+ if (!::IsStandard(txout.scriptPubKey, max_datacarrier_bytes, whichType)) {
reason = "scriptpubkey";
return false;
}
diff --git a/src/policy/policy.h b/src/policy/policy.h
index cd98a601a3..3d2660b081 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -47,8 +47,8 @@ static constexpr unsigned int MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE{80};
static constexpr unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE{3600};
/** The maximum size of a standard ScriptSig */
static constexpr unsigned int MAX_STANDARD_SCRIPTSIG_SIZE{1650};
-/** Min feerate for defining dust. Historically this has been based on the
- * minRelayTxFee, however changing the dust limit changes which transactions are
+/** Min feerate for defining dust.
+ * Changing the dust limit changes which transactions are
* standard and should be done with care and ideally rarely. It makes sense to
* only increase the dust limit after prior releases were already not creating
* outputs below the new threshold */
@@ -105,7 +105,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
-bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType);
+bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType);
// Changing the default transaction version requires a two step process: first
@@ -117,7 +117,7 @@ static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{2};
* Check for standard transaction types
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
*/
-bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason);
+bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason);
/**
* Check for standard transaction types
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
diff --git a/src/policy/settings.cpp b/src/policy/settings.cpp
index 0b67d274ce..39e00f1111 100644
--- a/src/policy/settings.cpp
+++ b/src/policy/settings.cpp
@@ -5,11 +5,6 @@
#include <policy/settings.h>
-#include <policy/feerate.h>
#include <policy/policy.h>
-bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
-CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
-CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
-CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
diff --git a/src/policy/settings.h b/src/policy/settings.h
index 2311d01fe8..f0d6f779ae 100644
--- a/src/policy/settings.h
+++ b/src/policy/settings.h
@@ -6,35 +6,6 @@
#ifndef BITCOIN_POLICY_SETTINGS_H
#define BITCOIN_POLICY_SETTINGS_H
-#include <policy/feerate.h>
-#include <policy/policy.h>
-
-#include <cstdint>
-#include <string>
-
-class CTransaction;
-
-// Policy settings which are configurable at runtime.
-extern CFeeRate incrementalRelayFee;
-extern CFeeRate dustRelayFee;
-/** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
-extern CFeeRate minRelayTxFee;
extern unsigned int nBytesPerSigOp;
-extern bool fIsBareMultisigStd;
-
-static inline bool IsStandardTx(const CTransaction& tx, std::string& reason)
-{
- return IsStandardTx(tx, ::fIsBareMultisigStd, ::dustRelayFee, reason);
-}
-
-static inline int64_t GetVirtualTransactionSize(int64_t weight, int64_t sigop_cost)
-{
- return GetVirtualTransactionSize(weight, sigop_cost, ::nBytesPerSigOp);
-}
-
-static inline int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t sigop_cost)
-{
- return GetVirtualTransactionSize(tx, sigop_cost, ::nBytesPerSigOp);
-}
#endif // BITCOIN_POLICY_SETTINGS_H
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index f7f6ae4480..ec48194ee9 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -7,10 +7,15 @@
#include <consensus/amount.h>
#include <hash.h>
+#include <script/script.h>
+#include <serialize.h>
#include <tinyformat.h>
+#include <uint256.h>
#include <util/strencodings.h>
+#include <version.h>
-#include <assert.h>
+#include <cassert>
+#include <stdexcept>
std::string COutPoint::ToString() const
{
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index fb98fb6868..f496ea022e 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -6,13 +6,21 @@
#ifndef BITCOIN_PRIMITIVES_TRANSACTION_H
#define BITCOIN_PRIMITIVES_TRANSACTION_H
-#include <stdint.h>
#include <consensus/amount.h>
+#include <prevector.h>
#include <script/script.h>
#include <serialize.h>
#include <uint256.h>
+#include <cstddef>
+#include <cstdint>
+#include <ios>
+#include <limits>
+#include <memory>
+#include <string>
#include <tuple>
+#include <utility>
+#include <vector>
/**
* A flag that is ORed into the protocol version to designate that a transaction
@@ -303,7 +311,7 @@ private:
public:
/** Convert a CMutableTransaction into a CTransaction. */
explicit CTransaction(const CMutableTransaction& tx);
- CTransaction(CMutableTransaction&& tx);
+ explicit CTransaction(CMutableTransaction&& tx);
template <typename Stream>
inline void Serialize(Stream& s) const {
@@ -368,7 +376,7 @@ struct CMutableTransaction
int32_t nVersion;
uint32_t nLockTime;
- CMutableTransaction();
+ explicit CMutableTransaction();
explicit CMutableTransaction(const CTransaction& tx);
template <typename Stream>
diff --git a/src/protocol.h b/src/protocol.h
index da2d24aff3..b85dc0d820 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -11,6 +11,7 @@
#include <serialize.h>
#include <streams.h>
#include <uint256.h>
+#include <util/time.h>
#include <cstdint>
#include <limits>
@@ -352,7 +353,7 @@ static inline bool MayHaveUsefulAddressDB(ServiceFlags services)
/** A CService with information about it as peer */
class CAddress : public CService
{
- static constexpr uint32_t TIME_INIT{100000000};
+ static constexpr std::chrono::seconds TIME_INIT{100000000};
/** Historically, CAddress disk serialization stored the CLIENT_VERSION, optionally OR'ed with
* the ADDRV2_FORMAT flag to indicate V2 serialization. The first field has since been
@@ -382,7 +383,7 @@ class CAddress : public CService
public:
CAddress() : CService{} {};
CAddress(CService ipIn, ServiceFlags nServicesIn) : CService{ipIn}, nServices{nServicesIn} {};
- CAddress(CService ipIn, ServiceFlags nServicesIn, uint32_t nTimeIn) : CService{ipIn}, nTime{nTimeIn}, nServices{nServicesIn} {};
+ CAddress(CService ipIn, ServiceFlags nServicesIn, NodeSeconds time) : CService{ipIn}, nTime{time}, nServices{nServicesIn} {};
SERIALIZE_METHODS(CAddress, obj)
{
@@ -415,7 +416,7 @@ public:
use_v2 = s.GetVersion() & ADDRV2_FORMAT;
}
- READWRITE(obj.nTime);
+ READWRITE(Using<LossyChronoFormatter<uint32_t>>(obj.nTime));
// nServices is serialized as CompactSize in V2; as uint64_t in V1.
if (use_v2) {
uint64_t services_tmp;
@@ -430,8 +431,8 @@ public:
SerReadWriteMany(os, ser_action, ReadWriteAsHelper<CService>(obj));
}
- //! Always included in serialization.
- uint32_t nTime{TIME_INIT};
+ //! Always included in serialization. The behavior is unspecified if the value is not representable as uint32_t.
+ NodeSeconds nTime{TIME_INIT};
//! Serialized as uint64_t in V1, and as CompactSize in V2.
ServiceFlags nServices{NODE_NONE};
diff --git a/src/psbt.h b/src/psbt.h
index a143a99988..d5c67802c7 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -641,6 +641,9 @@ struct PSBTInput
s >> leaf_hashes;
size_t after_hashes = s.size();
size_t hashes_len = before_hashes - after_hashes;
+ if (hashes_len > value_len) {
+ throw std::ios_base::failure("Input Taproot BIP32 keypath has an invalid length");
+ }
size_t origin_len = value_len - hashes_len;
m_tap_bip32_paths.emplace(xonly, std::make_pair(leaf_hashes, DeserializeKeyOrigin(s, origin_len)));
break;
@@ -866,6 +869,12 @@ struct PSBTOutput
s_tree >> depth;
s_tree >> leaf_ver;
s_tree >> script;
+ if (depth > TAPROOT_CONTROL_MAX_NODE_COUNT) {
+ throw std::ios_base::failure("Output Taproot tree has as leaf greater than Taproot maximum depth");
+ }
+ if ((leaf_ver & ~TAPROOT_LEAF_MASK) != 0) {
+ throw std::ios_base::failure("Output Taproot tree has a leaf with an invalid leaf version");
+ }
m_tap_tree->Add((int)depth, script, (int)leaf_ver, true /* track */);
}
if (!m_tap_tree->IsComplete()) {
@@ -887,6 +896,9 @@ struct PSBTOutput
s >> leaf_hashes;
size_t after_hashes = s.size();
size_t hashes_len = before_hashes - after_hashes;
+ if (hashes_len > value_len) {
+ throw std::ios_base::failure("Output Taproot BIP32 keypath has an invalid length");
+ }
size_t origin_len = value_len - hashes_len;
m_tap_bip32_paths.emplace(xonly, std::make_pair(leaf_hashes, DeserializeKeyOrigin(s, origin_len)));
break;
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index 324f681a0a..2e37e16690 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -211,16 +211,16 @@ bool XOnlyPubKey::VerifySchnorr(const uint256& msg, Span<const unsigned char> si
return secp256k1_schnorrsig_verify(secp256k1_context_verify, sigbytes.data(), msg.begin(), 32, &pubkey);
}
-static const CHashWriter HASHER_TAPTWEAK = TaggedHash("TapTweak");
+static const HashWriter HASHER_TAPTWEAK{TaggedHash("TapTweak")};
uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const
{
if (merkle_root == nullptr) {
// We have no scripts. The actual tweak does not matter, but follow BIP341 here to
// allow for reproducible tweaking.
- return (CHashWriter(HASHER_TAPTWEAK) << m_keydata).GetSHA256();
+ return (HashWriter{HASHER_TAPTWEAK} << m_keydata).GetSHA256();
} else {
- return (CHashWriter(HASHER_TAPTWEAK) << m_keydata << *merkle_root).GetSHA256();
+ return (HashWriter{HASHER_TAPTWEAK} << m_keydata << *merkle_root).GetSHA256();
}
}
@@ -365,6 +365,7 @@ void CExtPubKey::DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VE
}
bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
+ if (nDepth == std::numeric_limits<unsigned char>::max()) return false;
out.nDepth = nDepth + 1;
CKeyID id = pubkey.GetID();
memcpy(out.vchFingerprint, &id, 4);
diff --git a/src/pubkey.h b/src/pubkey.h
index 463efe1b00..0485a38f72 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -218,7 +218,7 @@ public:
bool Decompress();
//! Derive BIP32 child pubkey.
- bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
+ [[nodiscard]] bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
};
class XOnlyPubKey
@@ -327,7 +327,7 @@ struct CExtPubKey {
void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
void EncodeWithVersion(unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]) const;
void DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]);
- bool Derive(CExtPubKey& out, unsigned int nChild) const;
+ [[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild) const;
};
/** Users of this module must hold an ECCVerifyHandle. The constructor and
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index bb50b5384a..8b5da7f9f0 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -384,7 +384,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
return QString();
}
}
- strAddress = EncodeDestination(op_dest.GetObj());
+ strAddress = EncodeDestination(*op_dest);
}
else
{
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 27d3a1b9e2..33c60deafb 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -77,8 +77,6 @@ Q_DECLARE_METATYPE(CAmount)
Q_DECLARE_METATYPE(SynchronizationState)
Q_DECLARE_METATYPE(uint256)
-using node::NodeContext;
-
static void RegisterMetaTypes()
{
// Register meta types used for QMetaObject::invokeMethod and Qt::QueuedConnection
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 35e32f515b..90f228803c 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -430,8 +430,12 @@ void BitcoinGUI::createActions()
if (backup_file.isEmpty()) return;
bool wallet_name_ok;
- //: Title of the Restore Wallet input dialog (where the wallet name is entered)
- QString wallet_name = QInputDialog::getText(this, tr("Restore Name"), tr("Wallet Name:"), QLineEdit::Normal, "", &wallet_name_ok);
+ /*: Title of pop-up window shown when the user is attempting to
++ restore a wallet. */
+ QString title = tr("Restore Wallet");
+ //: Label of the input field where the name of the wallet is entered.
+ QString label = tr("Wallet Name");
+ QString wallet_name = QInputDialog::getText(this, title, label, QLineEdit::Normal, "", &wallet_name_ok);
if (!wallet_name_ok || wallet_name.isEmpty()) return;
auto activity = new RestoreWalletActivity(m_wallet_controller, this);
@@ -1350,6 +1354,12 @@ void BitcoinGUI::setEncryptionStatus(int status)
{
switch(status)
{
+ case WalletModel::NoKeys:
+ labelWalletEncryptionIcon->hide();
+ encryptWalletAction->setChecked(false);
+ changePassphraseAction->setEnabled(false);
+ encryptWalletAction->setEnabled(false);
+ break;
case WalletModel::Unencrypted:
labelWalletEncryptionIcon->hide();
encryptWalletAction->setChecked(false);
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index ba804d6955..13694c638d 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -14,9 +14,28 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring "
"a backup."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"%s request to listen on port %u. This port is considered \"bad\" and thus it "
+"is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports."
+"md for details and a full list."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"-maxtxfee is set very high! Fees this large could be paid on a single "
"transaction."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"-reindex-chainstate option is not compatible with -blockfilterindex. Please "
+"temporarily disable blockfilterindex while using -reindex-chainstate, or "
+"replace -reindex-chainstate with -reindex to fully rebuild all indexes."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"-reindex-chainstate option is not compatible with -coinstatsindex. Please "
+"temporarily disable coinstatsindex while using -reindex-chainstate, or "
+"replace -reindex-chainstate with -reindex to fully rebuild all indexes."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"-reindex-chainstate option is not compatible with -txindex. Please "
+"temporarily disable txindex while using -reindex-chainstate, or replace -"
+"reindex-chainstate with -reindex to fully rebuild all indexes."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Assumed-valid: last wallet synchronisation goes beyond available block data. "
+"You need to wait for the background validation chain to download more blocks."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Cannot downgrade wallet from version %i to version %i. Wallet version "
"unchanged."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -51,7 +70,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and "
"\"bech32\" address types"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
-"Error: Listening for incoming connections failed (listen returned error %s)"),
+"Failed to rename invalid peers.dat file. Please move or delete it and try "
+"again."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -"
"fallbackfee."),
@@ -77,6 +97,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"No wallet file format provided. To use createfromdump, -format=<format> must "
"be provided."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Outbound connections restricted to Tor (-onlynet=onion) but the proxy for "
+"reaching the Tor network is not provided (no -proxy= and no -onion= given) "
+"or it is explicitly forbidden (-onion=0)"),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Please check that your computer's date and time are correct! If your clock "
"is wrong, %s will not work properly."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -85,6 +109,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
QT_TRANSLATE_NOOP("bitcoin-core", ""
"Prune configured below the minimum of %d MiB. Please use a higher number."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Prune mode is incompatible with -reindex-chainstate. Use full -reindex "
+"instead."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Prune: last wallet synchronisation goes beyond pruned data. You need to -"
"reindex (download the whole blockchain again in case of pruned node)"),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -129,6 +156,13 @@ QT_TRANSLATE_NOOP("bitcoin-core", ""
"Unknown wallet file format \"%s\" provided. Please provide one of \"bdb\" or "
"\"sqlite\"."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Unsupported chainstate database format found. Please restart with -reindex-"
+"chainstate. This will rebuild the chainstate database."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
+"Wallet created successfully. The legacy wallet type is being deprecated and "
+"support for creating and opening legacy wallets will be removed in the "
+"future."),
+QT_TRANSLATE_NOOP("bitcoin-core", ""
"Warning: Dumpfile wallet format \"%s\" does not match command line specified "
"format \"%s\"."),
QT_TRANSLATE_NOOP("bitcoin-core", ""
@@ -169,7 +203,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down."),
QT_TRANSLATE_NOOP("bitcoin-core", "Error reading next record from wallet database"),
-QT_TRANSLATE_NOOP("bitcoin-core", "Error upgrading chainstate database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Couldn't create cursor into database"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low for %s"),
QT_TRANSLATE_NOOP("bitcoin-core", "Error: Dumpfile checksum does not match. Computed %s, expected %s"),
@@ -199,6 +232,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -discardfee=<amount>: '%s'
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -fallbackfee=<amount>: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Listening for incoming connections failed (listen returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading P2P addresses…"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading banlist…"),
QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index…"),
@@ -207,10 +241,8 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Missing amount"),
QT_TRANSLATE_NOOP("bitcoin-core", "Missing solving data for estimating transaction size"),
QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "No addresses available"),
-QT_TRANSLATE_NOOP("bitcoin-core", "No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>."),
QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."),
QT_TRANSLATE_NOOP("bitcoin-core", "Prune cannot be configured with a negative value."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -coinstatsindex."),
QT_TRANSLATE_NOOP("bitcoin-core", "Prune mode is incompatible with -txindex."),
QT_TRANSLATE_NOOP("bitcoin-core", "Pruning blockstore…"),
QT_TRANSLATE_NOOP("bitcoin-core", "Reducing -maxconnections from %d to %d, because of system limitations."),
@@ -241,6 +273,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Transaction has too long of a mempool chain")
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction must have at least one recipient"),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction needs a change address, but we can't generate it."),
QT_TRANSLATE_NOOP("bitcoin-core", "Transaction too large"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Unable to allocate memory for -maxsigcachesize: '%s' MiB"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer (bind returned error %s)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to bind to %s on this computer. %s is probably already running."),
QT_TRANSLATE_NOOP("bitcoin-core", "Unable to create the PID file '%s': %s"),
@@ -255,7 +288,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unknown change type '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unknown new rules activated (versionbit %i)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported logging category %s=%s."),
-QT_TRANSLATE_NOOP("bitcoin-core", "Upgrading UTXO database"),
QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe characters."),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks…"),
QT_TRANSLATE_NOOP("bitcoin-core", "Verifying wallet(s)…"),
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 2551be0af3..5cc21dd40b 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -428,7 +428,7 @@ void openDebugLogfile()
bool openBitcoinConf()
{
- fs::path pathConfig = GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME));
+ fs::path pathConfig = GetConfigFile(gArgs.GetPathArg("-conf", BITCOIN_CONF_FILENAME));
/* Create the file */
std::ofstream configFile{pathConfig, std::ios_base::app};
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 35d8201877..0fe69051a4 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -55,7 +55,7 @@
</message>
<message>
<location line="-30"/>
- <location filename="../addressbookpage.cpp" line="+122"/>
+ <location filename="../addressbookpage.cpp" line="+128"/>
<source>&amp;Delete</source>
<translation>&amp;Delete</translation>
</message>
@@ -313,7 +313,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>BitcoinApplication</name>
<message>
- <location filename="../bitcoin.cpp" line="+433"/>
+ <location filename="../bitcoin.cpp" line="+286"/>
+ <source>Settings file %1 might be corrupt or invalid.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+178"/>
<source>Runaway exception</source>
<translation type="unfinished"></translation>
</message>
@@ -336,7 +341,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>BitcoinGUI</name>
<message>
- <location filename="../bitcoingui.cpp" line="+250"/>
+ <location filename="../bitcoingui.cpp" line="+253"/>
<source>&amp;Overview</source>
<translation>&amp;Overview</translation>
</message>
@@ -396,7 +401,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+127"/>
+ <location line="+160"/>
<source>&amp;Minimize</source>
<translation type="unfinished"></translation>
</message>
@@ -406,18 +411,18 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+392"/>
+ <location line="+393"/>
<source>Network activity disabled.</source>
<extracomment>A substring of the tooltip.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+422"/>
+ <location line="+429"/>
<source>Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1109"/>
+ <location line="-1150"/>
<source>Send coins to a Bitcoin address</source>
<translation>Send coins to a Bitcoin address</translation>
</message>
@@ -507,17 +512,17 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+4"/>
+ <location line="+10"/>
<source>Close All Wallets…</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+94"/>
+ <location line="+119"/>
<source>&amp;File</source>
<translation>&amp;File</translation>
</message>
<message>
- <location line="+18"/>
+ <location line="+20"/>
<source>&amp;Settings</source>
<translation>&amp;Settings</translation>
</message>
@@ -532,12 +537,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>Tabs toolbar</translation>
</message>
<message>
- <location line="+456"/>
+ <location line="+457"/>
<source>Syncing Headers (%1%)…</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+47"/>
+ <location line="+48"/>
<source>Synchronizing with network…</source>
<translation type="unfinished"></translation>
</message>
@@ -562,7 +567,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-788"/>
+ <location line="-823"/>
<source>Request payments (generates QR codes and bitcoin: URIs)</source>
<translation type="unfinished"></translation>
</message>
@@ -577,12 +582,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+20"/>
+ <location line="+26"/>
<source>&amp;Command-line options</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
- <location line="+710"/>
+ <location line="+739"/>
<source>Processed %n block(s) of transaction history.</source>
<translation>
<numerusform>Processed %n block of transaction history.</numerusform>
@@ -630,7 +635,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>Up to date</translation>
</message>
<message>
- <location line="-747"/>
+ <location line="-808"/>
+ <source>Ctrl+Q</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+26"/>
<source>Load Partially Signed Bitcoin Transaction</source>
<translation type="unfinished"></translation>
</message>
@@ -686,6 +696,18 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</message>
<message>
<location line="+7"/>
+ <source>Restore Wallet…</source>
+ <extracomment>Name of the menu item that restores wallet from a backup file.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Restore a wallet from a backup file</source>
+ <extracomment>Status tip for Restore Wallet menu item</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Close all wallets</source>
<translation type="unfinished"></translation>
</message>
@@ -715,12 +737,41 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+63"/>
+ <location line="+6"/>
+ <source>Wallet Data</source>
+ <extracomment>Name of the wallet data file format.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Load Wallet Backup</source>
+ <extracomment>The title for Restore Wallet File Windows</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <source>Restore Wallet</source>
+ <extracomment>Title of pop-up window shown when the user is attempting to + restore a wallet.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+2"/>
+ <source>Wallet Name</source>
+ <extracomment>Label of the input field where the name of the wallet is entered.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+71"/>
<source>&amp;Window</source>
<translation type="unfinished">&amp;Window</translation>
</message>
<message>
- <location line="+12"/>
+ <location line="+3"/>
+ <source>Ctrl+M</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+9"/>
<source>Zoom</source>
<translation type="unfinished"></translation>
</message>
@@ -730,7 +781,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+257"/>
+ <location line="+258"/>
<source>%1 client</source>
<translation type="unfinished"></translation>
</message>
@@ -778,7 +829,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+158"/>
+ <location line="+159"/>
<source>Error: %1</source>
<translation type="unfinished"></translation>
</message>
@@ -849,7 +900,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+17"/>
+ <location line="+23"/>
<source>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
<translation>Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</translation>
</message>
@@ -1022,7 +1073,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+155"/>
+ <location line="+154"/>
<source>yes</source>
<translation type="unfinished"></translation>
</message>
@@ -1061,7 +1112,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>CreateWalletActivity</name>
<message>
- <location filename="../walletcontroller.cpp" line="+243"/>
+ <location filename="../walletcontroller.cpp" line="+244"/>
<source>Create Wallet</source>
<extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment>
<translation type="unfinished"></translation>
@@ -1073,7 +1124,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+29"/>
+ <location line="+33"/>
<source>Create wallet failed</source>
<translation type="unfinished"></translation>
</message>
@@ -1087,6 +1138,11 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<source>Can&apos;t list signers</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <location line="+3"/>
+ <source>Too many external signers found</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>CreateWalletDialog</name>
@@ -1276,7 +1332,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>HelpMessageDialog</name>
<message>
- <location filename="../utilitydialog.cpp" line="+37"/>
+ <location filename="../utilitydialog.cpp" line="+38"/>
<source>version</source>
<translation type="unfinished">version</translation>
</message>
@@ -1286,7 +1342,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+19"/>
+ <location line="+18"/>
<source>Command-line options</source>
<translation type="unfinished"></translation>
</message>
@@ -1353,20 +1409,29 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<source>Bitcoin</source>
<translation type="unfinished">Bitcoin</translation>
</message>
- <message>
+ <message numerus="yes">
<location line="+162"/>
- <source>%1 GB of space available</source>
- <translation type="unfinished"></translation>
+ <source>%n GB of space available</source>
+ <translation type="unfinished">
+ <numerusform></numerusform>
+ <numerusform></numerusform>
+ </translation>
</message>
- <message>
+ <message numerus="yes">
<location line="+2"/>
- <source>(of %1 GB needed)</source>
- <translation type="unfinished"></translation>
+ <source>(of %n GB needed)</source>
+ <translation type="unfinished">
+ <numerusform></numerusform>
+ <numerusform></numerusform>
+ </translation>
</message>
- <message>
+ <message numerus="yes">
<location line="+3"/>
- <source>(%1 GB needed for full chain)</source>
- <translation type="unfinished"></translation>
+ <source>(%n GB needed for full chain)</source>
+ <translation type="unfinished">
+ <numerusform></numerusform>
+ <numerusform></numerusform>
+ </translation>
</message>
<message>
<location line="+72"/>
@@ -1411,7 +1476,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>LoadWalletsActivity</name>
<message>
- <location filename="../walletcontroller.cpp" line="+69"/>
+ <location filename="../walletcontroller.cpp" line="+74"/>
<source>Load Wallets</source>
<extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment>
<translation type="unfinished"></translation>
@@ -1521,7 +1586,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>OpenWalletActivity</name>
<message>
- <location filename="../walletcontroller.cpp" line="-42"/>
+ <location filename="../walletcontroller.cpp" line="-46"/>
<source>Open wallet failed</source>
<translation type="unfinished"></translation>
</message>
@@ -1604,7 +1669,12 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+272"/>
+ <location line="+227"/>
+ <source>Options set in this dialog are overridden by the command line:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+45"/>
<source>Open the %1 configuration file from the working directory.</source>
<translation type="unfinished"></translation>
</message>
@@ -1916,12 +1986,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+65"/>
- <source>Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+141"/>
+ <location line="+206"/>
<source>&amp;OK</source>
<translation>&amp;OK</translation>
</message>
@@ -1931,7 +1996,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>&amp;Cancel</translation>
</message>
<message>
- <location filename="../optionsdialog.cpp" line="+99"/>
+ <location filename="../optionsdialog.cpp" line="+96"/>
<source>Compiled without external signing support (required for external signing)</source>
<extracomment>&quot;External signing&quot; means using devices such as hardware wallets.</extracomment>
<translation type="unfinished"></translation>
@@ -1942,28 +2007,37 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation>default</translation>
</message>
<message>
- <location line="+81"/>
+ <location line="+86"/>
<source>none</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+97"/>
+ <location line="+107"/>
<source>Confirm options reset</source>
+ <extracomment>Window title text of pop-up window shown when the user has chosen to reset options.</extracomment>
<translation>Confirm options reset</translation>
</message>
<message>
- <location line="+1"/>
- <location line="+70"/>
+ <location line="-9"/>
+ <location line="+79"/>
<source>Client restart required to activate changes.</source>
+ <extracomment>Text explaining that the settings changed will not come into effect until the client is restarted.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-75"/>
+ <source>Current settings will be backed up at &quot;%1&quot;.</source>
+ <extracomment>Text explaining to the user that the client&apos;s current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location&apos;s path.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-70"/>
+ <location line="+3"/>
<source>Client will be shut down. Do you want to proceed?</source>
+ <extracomment>Text asking the user to confirm if they would like to proceed with a client shutdown.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+18"/>
+ <location line="+20"/>
<source>Configuration options</source>
<extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment>
<translation type="unfinished"></translation>
@@ -2006,6 +2080,14 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</message>
</context>
<context>
+ <name>OptionsModel</name>
+ <message>
+ <location filename="../optionsmodel.cpp" line="+204"/>
+ <source>Could not read setting &quot;%1&quot;, %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>OverviewPage</name>
<message>
<location filename="../forms/overviewpage.ui" line="+14"/>
@@ -2099,7 +2181,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../overviewpage.cpp" line="+187"/>
+ <location filename="../overviewpage.cpp" line="+186"/>
<source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
<translation type="unfinished"></translation>
</message>
@@ -2271,7 +2353,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<context>
<name>PaymentServer</name>
<message>
- <location filename="../paymentserver.cpp" line="+173"/>
+ <location filename="../paymentserver.cpp" line="+152"/>
<source>Payment request error</source>
<translation type="unfinished"></translation>
</message>
@@ -2281,7 +2363,7 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+50"/>
+ <location line="+48"/>
<location line="+16"/>
<location line="+6"/>
<location line="+7"/>
@@ -2315,7 +2397,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<context>
<name>PeerTableModel</name>
<message>
- <location filename="../peertablemodel.h" line="+108"/>
+ <location filename="../peertablemodel.h" line="+112"/>
<source>User Agent</source>
<extracomment>Title of Peers Table column which contains the peer&apos;s User Agent string.</extracomment>
<translation type="unfinished"></translation>
@@ -2327,12 +2409,18 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-15"/>
+ <location line="-18"/>
<source>Peer</source>
<extracomment>Title of Peers Table column which contains a unique number used to identify a connection.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+3"/>
+ <source>Age</source>
+ <extracomment>Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+6"/>
<source>Direction</source>
<extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment>
@@ -2369,7 +2457,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished">Network</translation>
</message>
<message>
- <location filename="../peertablemodel.cpp" line="+79"/>
+ <location filename="../peertablemodel.cpp" line="+78"/>
<source>Inbound</source>
<extracomment>An Inbound Connection from a Peer.</extracomment>
<translation type="unfinished"></translation>
@@ -2384,17 +2472,22 @@ If you are receiving this error you should request the merchant provide a BIP21
<context>
<name>QObject</name>
<message>
- <location filename="../bitcoinunits.cpp" line="+215"/>
+ <location filename="../bitcoinunits.cpp" line="+197"/>
<source>Amount</source>
<translation type="unfinished">Amount</translation>
</message>
<message>
- <location filename="../guiutil.cpp" line="+127"/>
+ <location filename="../guiutil.cpp" line="+129"/>
<source>Enter a Bitcoin address (e.g. %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+546"/>
+ <location line="+288"/>
+ <source>Ctrl+W</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+256"/>
<source>Unroutable</source>
<translation type="unfinished"></translation>
</message>
@@ -2446,23 +2539,27 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+15"/>
+ <location line="+13"/>
+ <location line="+12"/>
<source>%1 d</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="-11"/>
+ <location line="+12"/>
<source>%1 h</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="-11"/>
+ <location line="+12"/>
<source>%1 m</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
- <location line="+28"/>
+ <location line="-10"/>
+ <location line="+11"/>
+ <location line="+26"/>
<source>%1 s</source>
<translation type="unfinished"></translation>
</message>
@@ -2556,7 +2653,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="-276"/>
+ <location filename="../bitcoin.cpp" line="-294"/>
<source>Do you want to reset settings to default values, or to abort without making changes?</source>
<extracomment>Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</extracomment>
<translation type="unfinished"></translation>
@@ -2568,7 +2665,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+373"/>
+ <location line="+393"/>
<source>Error: Specified data directory &quot;%1&quot; does not exist.</source>
<translation type="unfinished"></translation>
</message>
@@ -2583,7 +2680,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+71"/>
+ <location line="+74"/>
<source>%1 didn&apos;t yet exit safely…</source>
<translation type="unfinished"></translation>
</message>
@@ -2672,7 +2769,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<location line="+26"/>
<location line="+26"/>
<location line="+26"/>
- <location filename="../rpcconsole.h" line="+139"/>
+ <location filename="../rpcconsole.h" line="+143"/>
<source>N/A</source>
<translation>N/A</translation>
</message>
@@ -2791,7 +2888,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</message>
<message>
<location line="+68"/>
- <location filename="../rpcconsole.cpp" line="+1160"/>
+ <location filename="../rpcconsole.cpp" line="+1155"/>
<source>Select a peer to view detailed information.</source>
<translation type="unfinished"></translation>
</message>
@@ -2833,34 +2930,37 @@ If you are receiving this error you should request the merchant provide a BIP21
<message>
<location line="+23"/>
<source>Whether we relay addresses to this peer.</source>
- <extracomment>Tooltip text for the Address Relay field in the peer details area.</extracomment>
+ <extracomment>Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+3"/>
<source>Address Relay</source>
+ <extracomment>Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location line="+23"/>
- <source>Total number of addresses processed, excluding those dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Processed field in the peer details area.</extracomment>
+ <source>The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
+ <extracomment>Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Addresses Processed</source>
+ <location line="+26"/>
+ <source>The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+23"/>
- <source>Total number of addresses dropped due to rate-limiting.</source>
- <extracomment>Tooltip text for the Addresses Rate-Limited field in the peer details area.</extracomment>
+ <location line="-23"/>
+ <source>Addresses Processed</source>
+ <extracomment>Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+26"/>
<source>Addresses Rate-Limited</source>
+ <extracomment>Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
@@ -3021,7 +3121,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-201"/>
+ <location filename="../rpcconsole.cpp" line="-202"/>
<source>In:</source>
<translation type="unfinished"></translation>
</message>
@@ -3066,12 +3166,12 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+41"/>
+ <location line="+42"/>
<source>Never</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../rpcconsole.cpp" line="-457"/>
+ <location filename="../rpcconsole.cpp" line="-458"/>
<source>Inbound: initiated by peer</source>
<extracomment>Explanatory text for an inbound peer connection.</extracomment>
<translation type="unfinished"></translation>
@@ -3177,7 +3277,7 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+25"/>
+ <location line="+26"/>
<source>&amp;Copy IP/Netmask</source>
<extracomment>Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer&apos;s IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment>
<translation type="unfinished"></translation>
@@ -3193,17 +3293,37 @@ If you are receiving this error you should request the merchant provide a BIP21
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+77"/>
+ <location line="+78"/>
<source>Executing command without any wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-2"/>
+ <location line="+316"/>
+ <source>Ctrl+I</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Ctrl+T</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Ctrl+N</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
+ <source>Ctrl+P</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-321"/>
<source>Executing command using &quot;%1&quot; wallet</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-145"/>
+ <location line="-146"/>
<source>Welcome to the %1 RPC console.
Use up and down arrows to navigate history, and %2 to clear screen.
Use %3 and %4 to increase or decrease the font size.
@@ -3215,7 +3335,7 @@ For more information on using this console, type %6.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+155"/>
+ <location line="+156"/>
<source>Executing…</source>
<extracomment>A console message indicating an entered command is currently being executed.</extracomment>
<translation type="unfinished"></translation>
@@ -3231,7 +3351,7 @@ For more information on using this console, type %6.
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../rpcconsole.h" line="-41"/>
+ <location filename="../rpcconsole.h" line="-42"/>
<source>Unknown</source>
<translation type="unfinished"></translation>
</message>
@@ -3446,7 +3566,7 @@ For more information on using this console, type %6.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+41"/>
+ <location line="+38"/>
<source>(no label)</source>
<translation type="unfinished"></translation>
</message>
@@ -3467,10 +3587,43 @@ For more information on using this console, type %6.
</message>
</context>
<context>
+ <name>RestoreWalletActivity</name>
+ <message>
+ <location filename="../walletcontroller.cpp" line="+49"/>
+ <source>Restore Wallet</source>
+ <extracomment>Title of progress window which is displayed when wallets are being restored.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <extracomment>Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+19"/>
+ <source>Restore wallet failed</source>
+ <extracomment>Title of message box which is displayed when the wallet could not be restored.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Restore wallet warning</source>
+ <extracomment>Title of message box which is displayed when the wallet is restored with some warning.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Restore wallet message</source>
+ <extracomment>Title of message box which is displayed when the wallet is successfully restored.</extracomment>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
<name>SendCoinsDialog</name>
<message>
<location filename="../forms/sendcoinsdialog.ui" line="+14"/>
- <location filename="../sendcoinsdialog.cpp" line="+752"/>
+ <location filename="../sendcoinsdialog.cpp" line="+759"/>
<source>Send Coins</source>
<translation>Send Coins</translation>
</message>
@@ -3657,7 +3810,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation>S&amp;end</translation>
</message>
<message>
- <location filename="../sendcoinsdialog.cpp" line="-653"/>
+ <location filename="../sendcoinsdialog.cpp" line="-660"/>
<source>Copy quantity</source>
<translation type="unfinished"></translation>
</message>
@@ -3739,29 +3892,29 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+67"/>
+ <location line="+66"/>
<source>To review recipient list click &quot;Show Details…&quot;</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+44"/>
+ <location line="+60"/>
<source>Sign failed</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+5"/>
<source>External signer not found</source>
<extracomment>&quot;External signer&quot; means using devices such as hardware wallets.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+5"/>
<source>External signer failure</source>
<extracomment>&quot;External signer&quot; means using devices such as hardware wallets.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+58"/>
+ <location line="-34"/>
<source>Save Transaction Data</source>
<translation type="unfinished"></translation>
</message>
@@ -3777,17 +3930,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+176"/>
+ <location line="+266"/>
<source>External balance:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-303"/>
+ <location line="-315"/>
<source>or</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-19"/>
+ <location line="-18"/>
<source>You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
<translation type="unfinished"></translation>
</message>
@@ -3826,17 +3979,17 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+14"/>
+ <location line="+13"/>
<source>Total Amount</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+25"/>
+ <location line="+99"/>
<source>Confirm send coins</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+284"/>
+ <location line="+222"/>
<source>Watch-only balance:</source>
<translation type="unfinished"></translation>
</message>
@@ -3875,13 +4028,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<source>A fee higher than %1 is considered an absurdly high fee.</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <location line="+3"/>
- <source>Payment request expired.</source>
- <translation type="unfinished"></translation>
- </message>
<message numerus="yes">
- <location line="+124"/>
+ <location line="+123"/>
<source>Estimated to begin confirmation within %n block(s).</source>
<translation>
<numerusform>Estimated to begin confirmation within %n block.</numerusform>
@@ -3917,14 +4065,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<context>
<name>SendCoinsEntry</name>
<message>
- <location filename="../forms/sendcoinsentry.ui" line="+155"/>
- <location line="+550"/>
- <location line="+533"/>
+ <location filename="../forms/sendcoinsentry.ui" line="+151"/>
<source>A&amp;mount:</source>
<translation>A&amp;mount:</translation>
</message>
<message>
- <location line="-1199"/>
+ <location line="-116"/>
<source>Pay &amp;To:</source>
<translation>Pay &amp;To:</translation>
</message>
@@ -3960,13 +4106,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</message>
<message>
<location line="+7"/>
- <location line="+562"/>
- <location line="+533"/>
<source>Remove this entry</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1035"/>
+ <location line="+60"/>
<source>The amount to send in the selected unit</source>
<translation type="unfinished"></translation>
</message>
@@ -3991,17 +4135,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+443"/>
- <source>This is an unauthenticated payment request.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+529"/>
- <source>This is an authenticated payment request.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="-1023"/>
+ <location line="-51"/>
<location line="+3"/>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished"></translation>
@@ -4011,23 +4145,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<source>A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <location line="+448"/>
- <location line="+529"/>
- <source>Pay To:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="-495"/>
- <location line="+533"/>
- <source>Memo:</source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>SendConfirmationDialog</name>
<message>
- <location filename="../sendcoinsdialog.h" line="+131"/>
+ <location filename="../sendcoinsdialog.h" line="+144"/>
<source>Send</source>
<translation type="unfinished"></translation>
</message>
@@ -4274,42 +4396,43 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<context>
<name>TransactionDesc</name>
<message>
- <location filename="../transactiondesc.cpp" line="+40"/>
+ <location filename="../transactiondesc.cpp" line="+43"/>
<source>conflicted with a transaction with %1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>0/unconfirmed, %1</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+0"/>
- <source>in memory pool</source>
+ <location line="+7"/>
+ <source>0/unconfirmed, in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+0"/>
- <source>not in memory pool</source>
+ <location line="+5"/>
+ <source>0/unconfirmed, not in memory pool</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1"/>
+ <location line="+6"/>
<source>abandoned</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+8"/>
<source>%1/unconfirmed</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+2"/>
+ <location line="+5"/>
<source>%1 confirmations</source>
+ <extracomment>Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+51"/>
+ <location line="+50"/>
<source>Status</source>
<translation type="unfinished"></translation>
</message>
@@ -4507,7 +4630,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<context>
<name>TransactionTableModel</name>
<message>
- <location filename="../transactiontablemodel.cpp" line="+260"/>
+ <location filename="../transactiontablemodel.cpp" line="+261"/>
<source>Date</source>
<translation type="unfinished">Date</translation>
</message>
@@ -4844,7 +4967,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
<context>
<name>WalletController</name>
<message>
- <location filename="../walletcontroller.cpp" line="-259"/>
+ <location filename="../walletcontroller.cpp" line="-344"/>
<source>Close wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -4884,19 +5007,19 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+154"/>
- <location line="+9"/>
+ <location line="+151"/>
<location line="+10"/>
+ <location line="+18"/>
<source>Error</source>
<translation type="unfinished">Error</translation>
</message>
<message>
- <location line="-19"/>
+ <location line="-28"/>
<source>Unable to decode PSBT from clipboard (invalid base64)</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+5"/>
+ <location line="+6"/>
<source>Load Transaction Data</source>
<translation type="unfinished"></translation>
</message>
@@ -4911,7 +5034,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+10"/>
+ <location line="+18"/>
<source>Unable to decode PSBT</source>
<translation type="unfinished"></translation>
</message>
@@ -4924,7 +5047,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished">Send Coins</translation>
</message>
<message>
- <location line="+260"/>
+ <location line="+263"/>
<location line="+52"/>
<location line="+15"/>
<location line="+5"/>
@@ -5001,7 +5124,7 @@ Go to File &gt; Open Wallet to load a wallet.
<context>
<name>WalletView</name>
<message>
- <location filename="../walletview.cpp" line="+52"/>
+ <location filename="../walletview.cpp" line="+51"/>
<source>&amp;Export</source>
<translation type="unfinished">&amp;Export</translation>
</message>
@@ -5011,7 +5134,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished">Export the data in the current tab to a file</translation>
</message>
<message>
- <location line="+164"/>
+ <location line="+162"/>
<source>Backup Wallet</source>
<translation type="unfinished"></translation>
</message>
@@ -5060,12 +5183,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+7"/>
<source>-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
+ <location line="+18"/>
<source>Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
<translation type="unfinished"></translation>
</message>
@@ -5115,12 +5238,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+3"/>
- <source>Error: Listening for incoming connections failed (listen returned error %s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+2"/>
+ <location line="+6"/>
<source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
<translation type="unfinished"></translation>
</message>
@@ -5161,6 +5279,11 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+3"/>
+ <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided (no -proxy= and no -onion= given) or it is explicitly forbidden (-onion=0)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
<source>Please check that your computer&apos;s date and time are correct! If your clock is wrong, %s will not work properly.</source>
<translation type="unfinished"></translation>
</message>
@@ -5176,6 +5299,11 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+2"/>
+ <source>Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
<source>Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source>
<translation type="unfinished"></translation>
</message>
@@ -5241,6 +5369,16 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+3"/>
+ <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+3"/>
+ <source>Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
<source>Warning: Dumpfile wallet format &quot;%s&quot; does not match command line specified format &quot;%s&quot;.</source>
<translation type="unfinished"></translation>
</message>
@@ -5300,12 +5438,37 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-58"/>
+ <location line="-65"/>
<source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-69"/>
+ <location line="-104"/>
+ <source>%s request to listen on port %u. This port is considered &quot;bad&quot; and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+4"/>
+ <source>Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
<source>Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
<translation type="unfinished"></translation>
</message>
@@ -5315,7 +5478,12 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+118"/>
+ <location line="+19"/>
+ <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+114"/>
<source>Config setting for %s only applied on %s network when in [%s] section.</source>
<translation type="unfinished"></translation>
</message>
@@ -5416,11 +5584,6 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
- <source>Error upgrading chainstate database</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
<source>Error: Couldn&apos;t create cursor into database</source>
<translation type="unfinished"></translation>
</message>
@@ -5566,6 +5729,11 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
+ <source>Listening for incoming connections failed (listen returned error %s)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Loading P2P addresses…</source>
<translation type="unfinished"></translation>
</message>
@@ -5606,11 +5774,6 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
- <source>No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
<source>Not enough file descriptors available.</source>
<translation type="unfinished"></translation>
</message>
@@ -5621,11 +5784,6 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
- <source>Prune mode is incompatible with -coinstatsindex.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
<source>Prune mode is incompatible with -txindex.</source>
<translation type="unfinished"></translation>
</message>
@@ -5776,6 +5934,11 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
+ <source>Unable to allocate memory for -maxsigcachesize: &apos;%s&apos; MiB</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+1"/>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation type="unfinished"></translation>
</message>
@@ -5846,11 +6009,6 @@ Go to File &gt; Open Wallet to load a wallet.
</message>
<message>
<location line="+1"/>
- <source>Upgrading UTXO database</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+1"/>
<source>User Agent comment (%s) contains unsafe characters.</source>
<translation type="unfinished"></translation>
</message>
@@ -5870,7 +6028,7 @@ Go to File &gt; Open Wallet to load a wallet.
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="../bitcoin.cpp" line="-496"/>
+ <location filename="../bitcoin.cpp" line="-519"/>
<source>Settings file could not be read</source>
<translation type="unfinished"></translation>
</message>
diff --git a/src/qt/locale/bitcoin_en.xlf b/src/qt/locale/bitcoin_en.xlf
index 30ee5e4de6..c5f0c933f4 100644
--- a/src/qt/locale/bitcoin_en.xlf
+++ b/src/qt/locale/bitcoin_en.xlf
@@ -45,7 +45,7 @@
<trans-unit id="_msg11">
<source xml:space="preserve">&amp;Delete</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
- <context-group purpose="location"><context context-type="sourcefile">../addressbookpage.cpp</context><context context-type="linenumber">122</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../addressbookpage.cpp</context><context context-type="linenumber">128</context></context-group>
</trans-unit>
</group>
</body></file>
@@ -53,62 +53,62 @@
<group restype="x-trolltech-linguist-context" resname="AddressBookPage">
<trans-unit id="_msg12">
<source xml:space="preserve">Choose the address to send coins to</source>
- <context-group purpose="location"><context context-type="linenumber">84</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
<trans-unit id="_msg13">
<source xml:space="preserve">Choose the address to receive coins with</source>
- <context-group purpose="location"><context context-type="linenumber">85</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">91</context></context-group>
</trans-unit>
<trans-unit id="_msg14">
<source xml:space="preserve">C&amp;hoose</source>
- <context-group purpose="location"><context context-type="linenumber">90</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
<trans-unit id="_msg15">
<source xml:space="preserve">Sending addresses</source>
- <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">102</context></context-group>
</trans-unit>
<trans-unit id="_msg16">
<source xml:space="preserve">Receiving addresses</source>
- <context-group purpose="location"><context context-type="linenumber">97</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">103</context></context-group>
</trans-unit>
<trans-unit id="_msg17">
<source xml:space="preserve">These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
- <context-group purpose="location"><context context-type="linenumber">104</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">110</context></context-group>
</trans-unit>
<trans-unit id="_msg18">
<source xml:space="preserve">These are your Bitcoin addresses for receiving payments. Use the &apos;Create new receiving address&apos; button in the receive tab to create new addresses.
Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
- <context-group purpose="location"><context context-type="linenumber">109</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">115</context></context-group>
</trans-unit>
<trans-unit id="_msg19">
<source xml:space="preserve">&amp;Copy Address</source>
- <context-group purpose="location"><context context-type="linenumber">117</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
<trans-unit id="_msg20">
<source xml:space="preserve">Copy &amp;Label</source>
- <context-group purpose="location"><context context-type="linenumber">118</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
<trans-unit id="_msg21">
<source xml:space="preserve">&amp;Edit</source>
- <context-group purpose="location"><context context-type="linenumber">119</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">125</context></context-group>
</trans-unit>
<trans-unit id="_msg22">
<source xml:space="preserve">Export Address List</source>
- <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
</trans-unit>
<trans-unit id="_msg23">
<source xml:space="preserve">Comma separated file</source>
- <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
<note annotates="source" from="developer">Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</note>
</trans-unit>
<trans-unit id="_msg24">
<source xml:space="preserve">There was an error trying to save the address list to %1. Please try again.</source>
- <context-group purpose="location"><context context-type="linenumber">302</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
<note annotates="source" from="developer">An error message. %1 is a stand-in argument for the name of the file we attempted to save to.</note>
</trans-unit>
<trans-unit id="_msg25">
<source xml:space="preserve">Exporting Failed</source>
- <context-group purpose="location"><context context-type="linenumber">299</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
</group>
</body></file>
@@ -267,568 +267,610 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
<file original="../bitcoin.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="BitcoinApplication">
<trans-unit id="_msg58">
- <source xml:space="preserve">Runaway exception</source>
- <context-group purpose="location"><context context-type="linenumber">433</context></context-group>
+ <source xml:space="preserve">Settings file %1 might be corrupt or invalid.</source>
+ <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
</trans-unit>
<trans-unit id="_msg59">
- <source xml:space="preserve">A fatal error occurred. %1 can no longer continue safely and will quit.</source>
- <context-group purpose="location"><context context-type="linenumber">434</context></context-group>
+ <source xml:space="preserve">Runaway exception</source>
+ <context-group purpose="location"><context context-type="linenumber">464</context></context-group>
</trans-unit>
<trans-unit id="_msg60">
- <source xml:space="preserve">Internal error</source>
- <context-group purpose="location"><context context-type="linenumber">443</context></context-group>
+ <source xml:space="preserve">A fatal error occurred. %1 can no longer continue safely and will quit.</source>
+ <context-group purpose="location"><context context-type="linenumber">465</context></context-group>
</trans-unit>
<trans-unit id="_msg61">
+ <source xml:space="preserve">Internal error</source>
+ <context-group purpose="location"><context context-type="linenumber">474</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg62">
<source xml:space="preserve">An internal error occurred. %1 will attempt to continue safely. This is an unexpected bug which can be reported as described below.</source>
- <context-group purpose="location"><context context-type="linenumber">444</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">475</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg62">
+ <trans-unit id="_msg63">
<source xml:space="preserve">Do you want to reset settings to default values, or to abort without making changes?</source>
- <context-group purpose="location"><context context-type="linenumber">168</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">181</context></context-group>
<note annotates="source" from="developer">Explanatory text shown on startup when the settings file cannot be read. Prompts user to make a choice between resetting or aborting.</note>
</trans-unit>
- <trans-unit id="_msg63">
+ <trans-unit id="_msg64">
<source xml:space="preserve">A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source>
- <context-group purpose="location"><context context-type="linenumber">192</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">205</context></context-group>
<note annotates="source" from="developer">Explanatory text shown on startup when the settings file could not be written. Prompts user to check that we have the ability to write to the file. Explains that the user has the option of running without a settings file.</note>
</trans-unit>
- <trans-unit id="_msg64">
+ <trans-unit id="_msg65">
<source xml:space="preserve">Error: Specified data directory &quot;%1&quot; does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">565</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">598</context></context-group>
</trans-unit>
- <trans-unit id="_msg65">
+ <trans-unit id="_msg66">
<source xml:space="preserve">Error: Cannot parse configuration file: %1.</source>
- <context-group purpose="location"><context context-type="linenumber">571</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">604</context></context-group>
</trans-unit>
- <trans-unit id="_msg66">
+ <trans-unit id="_msg67">
<source xml:space="preserve">Error: %1</source>
- <context-group purpose="location"><context context-type="linenumber">586</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">619</context></context-group>
</trans-unit>
- <trans-unit id="_msg67">
+ <trans-unit id="_msg68">
<source xml:space="preserve">%1 didn&apos;t yet exit safely…</source>
- <context-group purpose="location"><context context-type="linenumber">657</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">693</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="bitcoin-core">
- <trans-unit id="_msg68">
+ <trans-unit id="_msg69">
<source xml:space="preserve">Settings file could not be read</source>
- <context-group purpose="location"><context context-type="linenumber">161</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">174</context></context-group>
</trans-unit>
- <trans-unit id="_msg69">
+ <trans-unit id="_msg70">
<source xml:space="preserve">Settings file could not be written</source>
- <context-group purpose="location"><context context-type="linenumber">184</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">197</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../bitcoingui.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="BitcoinGUI">
- <trans-unit id="_msg70">
- <source xml:space="preserve">&amp;Overview</source>
- <context-group purpose="location"><context context-type="linenumber">250</context></context-group>
- </trans-unit>
<trans-unit id="_msg71">
- <source xml:space="preserve">Show general overview of wallet</source>
- <context-group purpose="location"><context context-type="linenumber">251</context></context-group>
+ <source xml:space="preserve">&amp;Overview</source>
+ <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
</trans-unit>
<trans-unit id="_msg72">
- <source xml:space="preserve">&amp;Transactions</source>
- <context-group purpose="location"><context context-type="linenumber">271</context></context-group>
+ <source xml:space="preserve">Show general overview of wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">254</context></context-group>
</trans-unit>
<trans-unit id="_msg73">
- <source xml:space="preserve">Browse transaction history</source>
- <context-group purpose="location"><context context-type="linenumber">272</context></context-group>
+ <source xml:space="preserve">&amp;Transactions</source>
+ <context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
<trans-unit id="_msg74">
- <source xml:space="preserve">E&amp;xit</source>
- <context-group purpose="location"><context context-type="linenumber">291</context></context-group>
+ <source xml:space="preserve">Browse transaction history</source>
+ <context-group purpose="location"><context context-type="linenumber">275</context></context-group>
</trans-unit>
<trans-unit id="_msg75">
- <source xml:space="preserve">Quit application</source>
- <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
+ <source xml:space="preserve">E&amp;xit</source>
+ <context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
<trans-unit id="_msg76">
- <source xml:space="preserve">&amp;About %1</source>
+ <source xml:space="preserve">Quit application</source>
<context-group purpose="location"><context context-type="linenumber">295</context></context-group>
</trans-unit>
<trans-unit id="_msg77">
- <source xml:space="preserve">Show information about %1</source>
- <context-group purpose="location"><context context-type="linenumber">296</context></context-group>
+ <source xml:space="preserve">&amp;About %1</source>
+ <context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
<trans-unit id="_msg78">
- <source xml:space="preserve">About &amp;Qt</source>
+ <source xml:space="preserve">Show information about %1</source>
<context-group purpose="location"><context context-type="linenumber">299</context></context-group>
</trans-unit>
<trans-unit id="_msg79">
- <source xml:space="preserve">Show information about Qt</source>
- <context-group purpose="location"><context context-type="linenumber">300</context></context-group>
+ <source xml:space="preserve">About &amp;Qt</source>
+ <context-group purpose="location"><context context-type="linenumber">302</context></context-group>
</trans-unit>
<trans-unit id="_msg80">
- <source xml:space="preserve">Modify configuration options for %1</source>
+ <source xml:space="preserve">Show information about Qt</source>
<context-group purpose="location"><context context-type="linenumber">303</context></context-group>
</trans-unit>
<trans-unit id="_msg81">
- <source xml:space="preserve">Create a new wallet</source>
- <context-group purpose="location"><context context-type="linenumber">347</context></context-group>
+ <source xml:space="preserve">Modify configuration options for %1</source>
+ <context-group purpose="location"><context context-type="linenumber">306</context></context-group>
</trans-unit>
<trans-unit id="_msg82">
- <source xml:space="preserve">&amp;Minimize</source>
- <context-group purpose="location"><context context-type="linenumber">474</context></context-group>
+ <source xml:space="preserve">Create a new wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">350</context></context-group>
</trans-unit>
<trans-unit id="_msg83">
- <source xml:space="preserve">Wallet:</source>
- <context-group purpose="location"><context context-type="linenumber">553</context></context-group>
+ <source xml:space="preserve">&amp;Minimize</source>
+ <context-group purpose="location"><context context-type="linenumber">510</context></context-group>
</trans-unit>
<trans-unit id="_msg84">
- <source xml:space="preserve">Network activity disabled.</source>
- <context-group purpose="location"><context context-type="linenumber">945</context></context-group>
- <note annotates="source" from="developer">A substring of the tooltip.</note>
+ <source xml:space="preserve">Wallet:</source>
+ <context-group purpose="location"><context context-type="linenumber">589</context></context-group>
</trans-unit>
<trans-unit id="_msg85">
- <source xml:space="preserve">Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1367</context></context-group>
+ <source xml:space="preserve">Network activity disabled.</source>
+ <context-group purpose="location"><context context-type="linenumber">982</context></context-group>
+ <note annotates="source" from="developer">A substring of the tooltip.</note>
</trans-unit>
<trans-unit id="_msg86">
- <source xml:space="preserve">Send coins to a Bitcoin address</source>
- <context-group purpose="location"><context context-type="linenumber">258</context></context-group>
+ <source xml:space="preserve">Proxy is &lt;b&gt;enabled&lt;/b&gt;: %1</source>
+ <context-group purpose="location"><context context-type="linenumber">1411</context></context-group>
</trans-unit>
<trans-unit id="_msg87">
- <source xml:space="preserve">Backup wallet to another location</source>
- <context-group purpose="location"><context context-type="linenumber">311</context></context-group>
+ <source xml:space="preserve">Send coins to a Bitcoin address</source>
+ <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
<trans-unit id="_msg88">
- <source xml:space="preserve">Change the passphrase used for wallet encryption</source>
- <context-group purpose="location"><context context-type="linenumber">313</context></context-group>
+ <source xml:space="preserve">Backup wallet to another location</source>
+ <context-group purpose="location"><context context-type="linenumber">314</context></context-group>
</trans-unit>
<trans-unit id="_msg89">
- <source xml:space="preserve">&amp;Send</source>
- <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
+ <source xml:space="preserve">Change the passphrase used for wallet encryption</source>
+ <context-group purpose="location"><context context-type="linenumber">316</context></context-group>
</trans-unit>
<trans-unit id="_msg90">
- <source xml:space="preserve">&amp;Receive</source>
- <context-group purpose="location"><context context-type="linenumber">264</context></context-group>
+ <source xml:space="preserve">&amp;Send</source>
+ <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
<trans-unit id="_msg91">
- <source xml:space="preserve">&amp;Options…</source>
- <context-group purpose="location"><context context-type="linenumber">302</context></context-group>
+ <source xml:space="preserve">&amp;Receive</source>
+ <context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
<trans-unit id="_msg92">
- <source xml:space="preserve">&amp;Encrypt Wallet…</source>
- <context-group purpose="location"><context context-type="linenumber">307</context></context-group>
+ <source xml:space="preserve">&amp;Options…</source>
+ <context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
<trans-unit id="_msg93">
- <source xml:space="preserve">Encrypt the private keys that belong to your wallet</source>
- <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
+ <source xml:space="preserve">&amp;Encrypt Wallet…</source>
+ <context-group purpose="location"><context context-type="linenumber">310</context></context-group>
</trans-unit>
<trans-unit id="_msg94">
- <source xml:space="preserve">&amp;Backup Wallet…</source>
- <context-group purpose="location"><context context-type="linenumber">310</context></context-group>
+ <source xml:space="preserve">Encrypt the private keys that belong to your wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">311</context></context-group>
</trans-unit>
<trans-unit id="_msg95">
- <source xml:space="preserve">&amp;Change Passphrase…</source>
- <context-group purpose="location"><context context-type="linenumber">312</context></context-group>
+ <source xml:space="preserve">&amp;Backup Wallet…</source>
+ <context-group purpose="location"><context context-type="linenumber">313</context></context-group>
</trans-unit>
<trans-unit id="_msg96">
- <source xml:space="preserve">Sign &amp;message…</source>
- <context-group purpose="location"><context context-type="linenumber">314</context></context-group>
+ <source xml:space="preserve">&amp;Change Passphrase…</source>
+ <context-group purpose="location"><context context-type="linenumber">315</context></context-group>
</trans-unit>
<trans-unit id="_msg97">
- <source xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</source>
- <context-group purpose="location"><context context-type="linenumber">315</context></context-group>
+ <source xml:space="preserve">Sign &amp;message…</source>
+ <context-group purpose="location"><context context-type="linenumber">317</context></context-group>
</trans-unit>
<trans-unit id="_msg98">
- <source xml:space="preserve">&amp;Verify message…</source>
- <context-group purpose="location"><context context-type="linenumber">316</context></context-group>
+ <source xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</source>
+ <context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
<trans-unit id="_msg99">
- <source xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</source>
- <context-group purpose="location"><context context-type="linenumber">317</context></context-group>
+ <source xml:space="preserve">&amp;Verify message…</source>
+ <context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
<trans-unit id="_msg100">
- <source xml:space="preserve">&amp;Load PSBT from file…</source>
- <context-group purpose="location"><context context-type="linenumber">318</context></context-group>
+ <source xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <context-group purpose="location"><context context-type="linenumber">320</context></context-group>
</trans-unit>
<trans-unit id="_msg101">
- <source xml:space="preserve">Open &amp;URI…</source>
- <context-group purpose="location"><context context-type="linenumber">334</context></context-group>
+ <source xml:space="preserve">&amp;Load PSBT from file…</source>
+ <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
<trans-unit id="_msg102">
- <source xml:space="preserve">Close Wallet…</source>
- <context-group purpose="location"><context context-type="linenumber">342</context></context-group>
+ <source xml:space="preserve">Open &amp;URI…</source>
+ <context-group purpose="location"><context context-type="linenumber">337</context></context-group>
</trans-unit>
<trans-unit id="_msg103">
- <source xml:space="preserve">Create Wallet…</source>
+ <source xml:space="preserve">Close Wallet…</source>
<context-group purpose="location"><context context-type="linenumber">345</context></context-group>
</trans-unit>
<trans-unit id="_msg104">
- <source xml:space="preserve">Close All Wallets…</source>
- <context-group purpose="location"><context context-type="linenumber">349</context></context-group>
+ <source xml:space="preserve">Create Wallet…</source>
+ <context-group purpose="location"><context context-type="linenumber">348</context></context-group>
</trans-unit>
<trans-unit id="_msg105">
- <source xml:space="preserve">&amp;File</source>
- <context-group purpose="location"><context context-type="linenumber">443</context></context-group>
+ <source xml:space="preserve">Close All Wallets…</source>
+ <context-group purpose="location"><context context-type="linenumber">358</context></context-group>
</trans-unit>
<trans-unit id="_msg106">
- <source xml:space="preserve">&amp;Settings</source>
- <context-group purpose="location"><context context-type="linenumber">461</context></context-group>
+ <source xml:space="preserve">&amp;File</source>
+ <context-group purpose="location"><context context-type="linenumber">477</context></context-group>
</trans-unit>
<trans-unit id="_msg107">
- <source xml:space="preserve">&amp;Help</source>
- <context-group purpose="location"><context context-type="linenumber">522</context></context-group>
+ <source xml:space="preserve">&amp;Settings</source>
+ <context-group purpose="location"><context context-type="linenumber">497</context></context-group>
</trans-unit>
<trans-unit id="_msg108">
- <source xml:space="preserve">Tabs toolbar</source>
- <context-group purpose="location"><context context-type="linenumber">533</context></context-group>
+ <source xml:space="preserve">&amp;Help</source>
+ <context-group purpose="location"><context context-type="linenumber">558</context></context-group>
</trans-unit>
<trans-unit id="_msg109">
- <source xml:space="preserve">Syncing Headers (%1%)…</source>
- <context-group purpose="location"><context context-type="linenumber">989</context></context-group>
+ <source xml:space="preserve">Tabs toolbar</source>
+ <context-group purpose="location"><context context-type="linenumber">569</context></context-group>
</trans-unit>
<trans-unit id="_msg110">
- <source xml:space="preserve">Synchronizing with network…</source>
- <context-group purpose="location"><context context-type="linenumber">1036</context></context-group>
+ <source xml:space="preserve">Syncing Headers (%1%)…</source>
+ <context-group purpose="location"><context context-type="linenumber">1026</context></context-group>
</trans-unit>
<trans-unit id="_msg111">
- <source xml:space="preserve">Indexing blocks on disk…</source>
- <context-group purpose="location"><context context-type="linenumber">1041</context></context-group>
+ <source xml:space="preserve">Synchronizing with network…</source>
+ <context-group purpose="location"><context context-type="linenumber">1074</context></context-group>
</trans-unit>
<trans-unit id="_msg112">
- <source xml:space="preserve">Processing blocks on disk…</source>
- <context-group purpose="location"><context context-type="linenumber">1043</context></context-group>
+ <source xml:space="preserve">Indexing blocks on disk…</source>
+ <context-group purpose="location"><context context-type="linenumber">1079</context></context-group>
</trans-unit>
<trans-unit id="_msg113">
- <source xml:space="preserve">Reindexing blocks on disk…</source>
- <context-group purpose="location"><context context-type="linenumber">1047</context></context-group>
+ <source xml:space="preserve">Processing blocks on disk…</source>
+ <context-group purpose="location"><context context-type="linenumber">1081</context></context-group>
</trans-unit>
<trans-unit id="_msg114">
- <source xml:space="preserve">Connecting to peers…</source>
- <context-group purpose="location"><context context-type="linenumber">1053</context></context-group>
+ <source xml:space="preserve">Reindexing blocks on disk…</source>
+ <context-group purpose="location"><context context-type="linenumber">1085</context></context-group>
</trans-unit>
<trans-unit id="_msg115">
- <source xml:space="preserve">Request payments (generates QR codes and bitcoin: URIs)</source>
- <context-group purpose="location"><context context-type="linenumber">265</context></context-group>
+ <source xml:space="preserve">Connecting to peers…</source>
+ <context-group purpose="location"><context context-type="linenumber">1091</context></context-group>
</trans-unit>
<trans-unit id="_msg116">
- <source xml:space="preserve">Show the list of used sending addresses and labels</source>
- <context-group purpose="location"><context context-type="linenumber">330</context></context-group>
+ <source xml:space="preserve">Request payments (generates QR codes and bitcoin: URIs)</source>
+ <context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
<trans-unit id="_msg117">
- <source xml:space="preserve">Show the list of used receiving addresses and labels</source>
- <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
+ <source xml:space="preserve">Show the list of used sending addresses and labels</source>
+ <context-group purpose="location"><context context-type="linenumber">333</context></context-group>
</trans-unit>
<trans-unit id="_msg118">
+ <source xml:space="preserve">Show the list of used receiving addresses and labels</source>
+ <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg119">
<source xml:space="preserve">&amp;Command-line options</source>
- <context-group purpose="location"><context context-type="linenumber">352</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">361</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">1062</context></context-group>
- <trans-unit id="_msg119[0]">
+ <context-group purpose="location"><context context-type="linenumber">1100</context></context-group>
+ <trans-unit id="_msg120[0]">
<source xml:space="preserve">Processed %n block(s) of transaction history.</source>
</trans-unit>
- <trans-unit id="_msg119[1]">
+ <trans-unit id="_msg120[1]">
<source xml:space="preserve">Processed %n block(s) of transaction history.</source>
</trans-unit>
</group>
- <trans-unit id="_msg120">
- <source xml:space="preserve">%1 behind</source>
- <context-group purpose="location"><context context-type="linenumber">1085</context></context-group>
- </trans-unit>
<trans-unit id="_msg121">
- <source xml:space="preserve">Catching up…</source>
- <context-group purpose="location"><context context-type="linenumber">1090</context></context-group>
+ <source xml:space="preserve">%1 behind</source>
+ <context-group purpose="location"><context context-type="linenumber">1123</context></context-group>
</trans-unit>
<trans-unit id="_msg122">
- <source xml:space="preserve">Last received block was generated %1 ago.</source>
- <context-group purpose="location"><context context-type="linenumber">1109</context></context-group>
+ <source xml:space="preserve">Catching up…</source>
+ <context-group purpose="location"><context context-type="linenumber">1128</context></context-group>
</trans-unit>
<trans-unit id="_msg123">
- <source xml:space="preserve">Transactions after this will not yet be visible.</source>
- <context-group purpose="location"><context context-type="linenumber">1111</context></context-group>
+ <source xml:space="preserve">Last received block was generated %1 ago.</source>
+ <context-group purpose="location"><context context-type="linenumber">1147</context></context-group>
</trans-unit>
<trans-unit id="_msg124">
- <source xml:space="preserve">Error</source>
- <context-group purpose="location"><context context-type="linenumber">1136</context></context-group>
+ <source xml:space="preserve">Transactions after this will not yet be visible.</source>
+ <context-group purpose="location"><context context-type="linenumber">1149</context></context-group>
</trans-unit>
<trans-unit id="_msg125">
- <source xml:space="preserve">Warning</source>
- <context-group purpose="location"><context context-type="linenumber">1140</context></context-group>
+ <source xml:space="preserve">Error</source>
+ <context-group purpose="location"><context context-type="linenumber">1174</context></context-group>
</trans-unit>
<trans-unit id="_msg126">
- <source xml:space="preserve">Information</source>
- <context-group purpose="location"><context context-type="linenumber">1144</context></context-group>
+ <source xml:space="preserve">Warning</source>
+ <context-group purpose="location"><context context-type="linenumber">1178</context></context-group>
</trans-unit>
<trans-unit id="_msg127">
- <source xml:space="preserve">Up to date</source>
- <context-group purpose="location"><context context-type="linenumber">1066</context></context-group>
+ <source xml:space="preserve">Information</source>
+ <context-group purpose="location"><context context-type="linenumber">1182</context></context-group>
</trans-unit>
<trans-unit id="_msg128">
- <source xml:space="preserve">Load Partially Signed Bitcoin Transaction</source>
- <context-group purpose="location"><context context-type="linenumber">319</context></context-group>
+ <source xml:space="preserve">Up to date</source>
+ <context-group purpose="location"><context context-type="linenumber">1104</context></context-group>
</trans-unit>
<trans-unit id="_msg129">
- <source xml:space="preserve">Load PSBT from &amp;clipboard…</source>
- <context-group purpose="location"><context context-type="linenumber">320</context></context-group>
+ <source xml:space="preserve">Ctrl+Q</source>
+ <context-group purpose="location"><context context-type="linenumber">296</context></context-group>
</trans-unit>
<trans-unit id="_msg130">
- <source xml:space="preserve">Load Partially Signed Bitcoin Transaction from clipboard</source>
- <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
+ <source xml:space="preserve">Load Partially Signed Bitcoin Transaction</source>
+ <context-group purpose="location"><context context-type="linenumber">322</context></context-group>
</trans-unit>
<trans-unit id="_msg131">
- <source xml:space="preserve">Node window</source>
+ <source xml:space="preserve">Load PSBT from &amp;clipboard…</source>
<context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
<trans-unit id="_msg132">
- <source xml:space="preserve">Open node debugging and diagnostic console</source>
+ <source xml:space="preserve">Load Partially Signed Bitcoin Transaction from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
<trans-unit id="_msg133">
- <source xml:space="preserve">&amp;Sending addresses</source>
- <context-group purpose="location"><context context-type="linenumber">329</context></context-group>
+ <source xml:space="preserve">Node window</source>
+ <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
<trans-unit id="_msg134">
- <source xml:space="preserve">&amp;Receiving addresses</source>
- <context-group purpose="location"><context context-type="linenumber">331</context></context-group>
+ <source xml:space="preserve">Open node debugging and diagnostic console</source>
+ <context-group purpose="location"><context context-type="linenumber">327</context></context-group>
</trans-unit>
<trans-unit id="_msg135">
- <source xml:space="preserve">Open a bitcoin: URI</source>
- <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
+ <source xml:space="preserve">&amp;Sending addresses</source>
+ <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
<trans-unit id="_msg136">
- <source xml:space="preserve">Open Wallet</source>
- <context-group purpose="location"><context context-type="linenumber">337</context></context-group>
+ <source xml:space="preserve">&amp;Receiving addresses</source>
+ <context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
<trans-unit id="_msg137">
- <source xml:space="preserve">Open a wallet</source>
- <context-group purpose="location"><context context-type="linenumber">339</context></context-group>
+ <source xml:space="preserve">Open a bitcoin: URI</source>
+ <context-group purpose="location"><context context-type="linenumber">338</context></context-group>
</trans-unit>
<trans-unit id="_msg138">
- <source xml:space="preserve">Close wallet</source>
- <context-group purpose="location"><context context-type="linenumber">343</context></context-group>
+ <source xml:space="preserve">Open Wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">340</context></context-group>
</trans-unit>
<trans-unit id="_msg139">
- <source xml:space="preserve">Close all wallets</source>
- <context-group purpose="location"><context context-type="linenumber">350</context></context-group>
+ <source xml:space="preserve">Open a wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">342</context></context-group>
</trans-unit>
<trans-unit id="_msg140">
- <source xml:space="preserve">Show the %1 help message to get a list with possible Bitcoin command-line options</source>
- <context-group purpose="location"><context context-type="linenumber">354</context></context-group>
+ <source xml:space="preserve">Close wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">346</context></context-group>
</trans-unit>
<trans-unit id="_msg141">
- <source xml:space="preserve">&amp;Mask values</source>
- <context-group purpose="location"><context context-type="linenumber">356</context></context-group>
+ <source xml:space="preserve">Restore Wallet…</source>
+ <context-group purpose="location"><context context-type="linenumber">353</context></context-group>
+ <note annotates="source" from="developer">Name of the menu item that restores wallet from a backup file.</note>
</trans-unit>
<trans-unit id="_msg142">
- <source xml:space="preserve">Mask the values in the Overview tab</source>
- <context-group purpose="location"><context context-type="linenumber">358</context></context-group>
+ <source xml:space="preserve">Restore a wallet from a backup file</source>
+ <context-group purpose="location"><context context-type="linenumber">356</context></context-group>
+ <note annotates="source" from="developer">Status tip for Restore Wallet menu item</note>
</trans-unit>
<trans-unit id="_msg143">
- <source xml:space="preserve">default wallet</source>
- <context-group purpose="location"><context context-type="linenumber">389</context></context-group>
+ <source xml:space="preserve">Close all wallets</source>
+ <context-group purpose="location"><context context-type="linenumber">359</context></context-group>
</trans-unit>
<trans-unit id="_msg144">
- <source xml:space="preserve">No wallets available</source>
- <context-group purpose="location"><context context-type="linenumber">409</context></context-group>
+ <source xml:space="preserve">Show the %1 help message to get a list with possible Bitcoin command-line options</source>
+ <context-group purpose="location"><context context-type="linenumber">363</context></context-group>
</trans-unit>
<trans-unit id="_msg145">
- <source xml:space="preserve">&amp;Window</source>
- <context-group purpose="location"><context context-type="linenumber">472</context></context-group>
+ <source xml:space="preserve">&amp;Mask values</source>
+ <context-group purpose="location"><context context-type="linenumber">365</context></context-group>
</trans-unit>
<trans-unit id="_msg146">
- <source xml:space="preserve">Zoom</source>
- <context-group purpose="location"><context context-type="linenumber">484</context></context-group>
+ <source xml:space="preserve">Mask the values in the Overview tab</source>
+ <context-group purpose="location"><context context-type="linenumber">367</context></context-group>
</trans-unit>
<trans-unit id="_msg147">
- <source xml:space="preserve">Main Window</source>
- <context-group purpose="location"><context context-type="linenumber">502</context></context-group>
+ <source xml:space="preserve">default wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">398</context></context-group>
</trans-unit>
<trans-unit id="_msg148">
- <source xml:space="preserve">%1 client</source>
- <context-group purpose="location"><context context-type="linenumber">759</context></context-group>
+ <source xml:space="preserve">No wallets available</source>
+ <context-group purpose="location"><context context-type="linenumber">418</context></context-group>
</trans-unit>
<trans-unit id="_msg149">
- <source xml:space="preserve">&amp;Hide</source>
- <context-group purpose="location"><context context-type="linenumber">824</context></context-group>
+ <source xml:space="preserve">Wallet Data</source>
+ <context-group purpose="location"><context context-type="linenumber">424</context></context-group>
+ <note annotates="source" from="developer">Name of the wallet data file format.</note>
</trans-unit>
<trans-unit id="_msg150">
+ <source xml:space="preserve">Load Wallet Backup</source>
+ <context-group purpose="location"><context context-type="linenumber">427</context></context-group>
+ <note annotates="source" from="developer">The title for Restore Wallet File Windows</note>
+ </trans-unit>
+ <trans-unit id="_msg151">
+ <source xml:space="preserve">Restore Wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">435</context></context-group>
+ <note annotates="source" from="developer">Title of pop-up window shown when the user is attempting to + restore a wallet.</note>
+ </trans-unit>
+ <trans-unit id="_msg152">
+ <source xml:space="preserve">Wallet Name</source>
+ <context-group purpose="location"><context context-type="linenumber">437</context></context-group>
+ <note annotates="source" from="developer">Label of the input field where the name of the wallet is entered.</note>
+ </trans-unit>
+ <trans-unit id="_msg153">
+ <source xml:space="preserve">&amp;Window</source>
+ <context-group purpose="location"><context context-type="linenumber">508</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg154">
+ <source xml:space="preserve">Ctrl+M</source>
+ <context-group purpose="location"><context context-type="linenumber">511</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg155">
+ <source xml:space="preserve">Zoom</source>
+ <context-group purpose="location"><context context-type="linenumber">520</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg156">
+ <source xml:space="preserve">Main Window</source>
+ <context-group purpose="location"><context context-type="linenumber">538</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg157">
+ <source xml:space="preserve">%1 client</source>
+ <context-group purpose="location"><context context-type="linenumber">796</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg158">
+ <source xml:space="preserve">&amp;Hide</source>
+ <context-group purpose="location"><context context-type="linenumber">861</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg159">
<source xml:space="preserve">S&amp;how</source>
- <context-group purpose="location"><context context-type="linenumber">825</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">862</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">942</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">979</context></context-group>
<note annotates="source" from="developer">A substring of the tooltip.</note>
- <trans-unit id="_msg151[0]">
+ <trans-unit id="_msg160[0]">
<source xml:space="preserve">%n active connection(s) to Bitcoin network.</source>
</trans-unit>
- <trans-unit id="_msg151[1]">
+ <trans-unit id="_msg160[1]">
<source xml:space="preserve">%n active connection(s) to Bitcoin network.</source>
</trans-unit>
</group>
- <trans-unit id="_msg152">
+ <trans-unit id="_msg161">
<source xml:space="preserve">Click for more actions.</source>
- <context-group purpose="location"><context context-type="linenumber">952</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">989</context></context-group>
<note annotates="source" from="developer">A substring of the tooltip. &quot;More actions&quot; are available via the context menu.</note>
</trans-unit>
- <trans-unit id="_msg153">
+ <trans-unit id="_msg162">
<source xml:space="preserve">Show Peers tab</source>
- <context-group purpose="location"><context context-type="linenumber">969</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1006</context></context-group>
<note annotates="source" from="developer">A context menu item. The &quot;Peers tab&quot; is an element of the &quot;Node window&quot;.</note>
</trans-unit>
- <trans-unit id="_msg154">
+ <trans-unit id="_msg163">
<source xml:space="preserve">Disable network activity</source>
- <context-group purpose="location"><context context-type="linenumber">977</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1014</context></context-group>
<note annotates="source" from="developer">A context menu item.</note>
</trans-unit>
- <trans-unit id="_msg155">
+ <trans-unit id="_msg164">
<source xml:space="preserve">Enable network activity</source>
- <context-group purpose="location"><context context-type="linenumber">979</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1016</context></context-group>
<note annotates="source" from="developer">A context menu item. The network activity was disabled previously.</note>
</trans-unit>
- <trans-unit id="_msg156">
+ <trans-unit id="_msg165">
<source xml:space="preserve">Error: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1137</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1175</context></context-group>
</trans-unit>
- <trans-unit id="_msg157">
+ <trans-unit id="_msg166">
<source xml:space="preserve">Warning: %1</source>
- <context-group purpose="location"><context context-type="linenumber">1141</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1179</context></context-group>
</trans-unit>
- <trans-unit id="_msg158">
+ <trans-unit id="_msg167">
<source xml:space="preserve">Date: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1249</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1287</context></context-group>
</trans-unit>
- <trans-unit id="_msg159">
+ <trans-unit id="_msg168">
<source xml:space="preserve">Amount: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1250</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1288</context></context-group>
</trans-unit>
- <trans-unit id="_msg160">
+ <trans-unit id="_msg169">
<source xml:space="preserve">Wallet: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1252</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1290</context></context-group>
</trans-unit>
- <trans-unit id="_msg161">
+ <trans-unit id="_msg170">
<source xml:space="preserve">Type: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1254</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1292</context></context-group>
</trans-unit>
- <trans-unit id="_msg162">
+ <trans-unit id="_msg171">
<source xml:space="preserve">Label: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1256</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1294</context></context-group>
</trans-unit>
- <trans-unit id="_msg163">
+ <trans-unit id="_msg172">
<source xml:space="preserve">Address: %1
</source>
- <context-group purpose="location"><context context-type="linenumber">1258</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1296</context></context-group>
</trans-unit>
- <trans-unit id="_msg164">
+ <trans-unit id="_msg173">
<source xml:space="preserve">Sent transaction</source>
- <context-group purpose="location"><context context-type="linenumber">1259</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1297</context></context-group>
</trans-unit>
- <trans-unit id="_msg165">
+ <trans-unit id="_msg174">
<source xml:space="preserve">Incoming transaction</source>
- <context-group purpose="location"><context context-type="linenumber">1259</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1297</context></context-group>
</trans-unit>
- <trans-unit id="_msg166">
+ <trans-unit id="_msg175">
<source xml:space="preserve">HD key generation is &lt;b&gt;enabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1311</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1349</context></context-group>
</trans-unit>
- <trans-unit id="_msg167">
+ <trans-unit id="_msg176">
<source xml:space="preserve">HD key generation is &lt;b&gt;disabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1311</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1349</context></context-group>
</trans-unit>
- <trans-unit id="_msg168">
+ <trans-unit id="_msg177">
<source xml:space="preserve">Private key &lt;b&gt;disabled&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1311</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1349</context></context-group>
</trans-unit>
- <trans-unit id="_msg169">
+ <trans-unit id="_msg178">
<source xml:space="preserve">Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;unlocked&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1328</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1372</context></context-group>
</trans-unit>
- <trans-unit id="_msg170">
+ <trans-unit id="_msg179">
<source xml:space="preserve">Wallet is &lt;b&gt;encrypted&lt;/b&gt; and currently &lt;b&gt;locked&lt;/b&gt;</source>
- <context-group purpose="location"><context context-type="linenumber">1336</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1380</context></context-group>
</trans-unit>
- <trans-unit id="_msg171">
+ <trans-unit id="_msg180">
<source xml:space="preserve">Original message:</source>
- <context-group purpose="location"><context context-type="linenumber">1455</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1499</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="UnitDisplayStatusBarControl">
- <trans-unit id="_msg172">
+ <trans-unit id="_msg181">
<source xml:space="preserve">Unit to show amounts in. Click to select another unit.</source>
- <context-group purpose="location"><context context-type="linenumber">1496</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1540</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/coincontroldialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CoinControlDialog">
- <trans-unit id="_msg173">
+ <trans-unit id="_msg182">
<source xml:space="preserve">Coin Selection</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg174">
+ <trans-unit id="_msg183">
<source xml:space="preserve">Quantity:</source>
<context-group purpose="location"><context context-type="linenumber">48</context></context-group>
</trans-unit>
- <trans-unit id="_msg175">
+ <trans-unit id="_msg184">
<source xml:space="preserve">Bytes:</source>
<context-group purpose="location"><context context-type="linenumber">77</context></context-group>
</trans-unit>
- <trans-unit id="_msg176">
+ <trans-unit id="_msg185">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
- <trans-unit id="_msg177">
+ <trans-unit id="_msg186">
<source xml:space="preserve">Fee:</source>
<context-group purpose="location"><context context-type="linenumber">202</context></context-group>
</trans-unit>
- <trans-unit id="_msg178">
+ <trans-unit id="_msg187">
<source xml:space="preserve">Dust:</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
</trans-unit>
- <trans-unit id="_msg179">
+ <trans-unit id="_msg188">
<source xml:space="preserve">After Fee:</source>
<context-group purpose="location"><context context-type="linenumber">247</context></context-group>
</trans-unit>
- <trans-unit id="_msg180">
+ <trans-unit id="_msg189">
<source xml:space="preserve">Change:</source>
<context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg181">
+ <trans-unit id="_msg190">
<source xml:space="preserve">(un)select all</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg182">
+ <trans-unit id="_msg191">
<source xml:space="preserve">Tree mode</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
</trans-unit>
- <trans-unit id="_msg183">
+ <trans-unit id="_msg192">
<source xml:space="preserve">List mode</source>
<context-group purpose="location"><context context-type="linenumber">364</context></context-group>
</trans-unit>
- <trans-unit id="_msg184">
+ <trans-unit id="_msg193">
<source xml:space="preserve">Amount</source>
<context-group purpose="location"><context context-type="linenumber">420</context></context-group>
</trans-unit>
- <trans-unit id="_msg185">
+ <trans-unit id="_msg194">
<source xml:space="preserve">Received with label</source>
<context-group purpose="location"><context context-type="linenumber">425</context></context-group>
</trans-unit>
- <trans-unit id="_msg186">
+ <trans-unit id="_msg195">
<source xml:space="preserve">Received with address</source>
<context-group purpose="location"><context context-type="linenumber">430</context></context-group>
</trans-unit>
- <trans-unit id="_msg187">
+ <trans-unit id="_msg196">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">435</context></context-group>
</trans-unit>
- <trans-unit id="_msg188">
+ <trans-unit id="_msg197">
<source xml:space="preserve">Confirmations</source>
<context-group purpose="location"><context context-type="linenumber">440</context></context-group>
</trans-unit>
- <trans-unit id="_msg189">
+ <trans-unit id="_msg198">
<source xml:space="preserve">Confirmed</source>
<context-group purpose="location"><context context-type="linenumber">443</context></context-group>
</trans-unit>
@@ -836,232 +878,263 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../coincontroldialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CoinControlDialog">
- <trans-unit id="_msg190">
+ <trans-unit id="_msg199">
<source xml:space="preserve">Copy amount</source>
<context-group purpose="location"><context context-type="linenumber">69</context></context-group>
</trans-unit>
- <trans-unit id="_msg191">
+ <trans-unit id="_msg200">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg192">
+ <trans-unit id="_msg201">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">59</context></context-group>
</trans-unit>
- <trans-unit id="_msg193">
+ <trans-unit id="_msg202">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg194">
+ <trans-unit id="_msg203">
<source xml:space="preserve">Copy transaction &amp;ID and output index</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg195">
+ <trans-unit id="_msg204">
<source xml:space="preserve">L&amp;ock unspent</source>
<context-group purpose="location"><context context-type="linenumber">63</context></context-group>
</trans-unit>
- <trans-unit id="_msg196">
+ <trans-unit id="_msg205">
<source xml:space="preserve">&amp;Unlock unspent</source>
<context-group purpose="location"><context context-type="linenumber">64</context></context-group>
</trans-unit>
- <trans-unit id="_msg197">
+ <trans-unit id="_msg206">
<source xml:space="preserve">Copy quantity</source>
<context-group purpose="location"><context context-type="linenumber">68</context></context-group>
</trans-unit>
- <trans-unit id="_msg198">
+ <trans-unit id="_msg207">
<source xml:space="preserve">Copy fee</source>
<context-group purpose="location"><context context-type="linenumber">70</context></context-group>
</trans-unit>
- <trans-unit id="_msg199">
+ <trans-unit id="_msg208">
<source xml:space="preserve">Copy after fee</source>
<context-group purpose="location"><context context-type="linenumber">71</context></context-group>
</trans-unit>
- <trans-unit id="_msg200">
+ <trans-unit id="_msg209">
<source xml:space="preserve">Copy bytes</source>
<context-group purpose="location"><context context-type="linenumber">72</context></context-group>
</trans-unit>
- <trans-unit id="_msg201">
+ <trans-unit id="_msg210">
<source xml:space="preserve">Copy dust</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg202">
+ <trans-unit id="_msg211">
<source xml:space="preserve">Copy change</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
- <trans-unit id="_msg203">
+ <trans-unit id="_msg212">
<source xml:space="preserve">(%1 locked)</source>
<context-group purpose="location"><context context-type="linenumber">380</context></context-group>
</trans-unit>
- <trans-unit id="_msg204">
+ <trans-unit id="_msg213">
<source xml:space="preserve">yes</source>
- <context-group purpose="location"><context context-type="linenumber">535</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">534</context></context-group>
</trans-unit>
- <trans-unit id="_msg205">
+ <trans-unit id="_msg214">
<source xml:space="preserve">no</source>
- <context-group purpose="location"><context context-type="linenumber">535</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">534</context></context-group>
</trans-unit>
- <trans-unit id="_msg206">
+ <trans-unit id="_msg215">
<source xml:space="preserve">This label turns red if any recipient receives an amount smaller than the current dust threshold.</source>
- <context-group purpose="location"><context context-type="linenumber">549</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">548</context></context-group>
</trans-unit>
- <trans-unit id="_msg207">
+ <trans-unit id="_msg216">
<source xml:space="preserve">Can vary +/- %1 satoshi(s) per input.</source>
- <context-group purpose="location"><context context-type="linenumber">554</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">553</context></context-group>
</trans-unit>
- <trans-unit id="_msg208">
+ <trans-unit id="_msg217">
<source xml:space="preserve">(no label)</source>
- <context-group purpose="location"><context context-type="linenumber">601</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">655</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">600</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">654</context></context-group>
</trans-unit>
- <trans-unit id="_msg209">
+ <trans-unit id="_msg218">
<source xml:space="preserve">change from %1 (%2)</source>
- <context-group purpose="location"><context context-type="linenumber">648</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">647</context></context-group>
</trans-unit>
- <trans-unit id="_msg210">
+ <trans-unit id="_msg219">
<source xml:space="preserve">(change)</source>
- <context-group purpose="location"><context context-type="linenumber">649</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">648</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../walletcontroller.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletActivity">
- <trans-unit id="_msg211">
+ <trans-unit id="_msg220">
<source xml:space="preserve">Create Wallet</source>
- <context-group purpose="location"><context context-type="linenumber">243</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">244</context></context-group>
<note annotates="source" from="developer">Title of window indicating the progress of creation of a new wallet.</note>
</trans-unit>
- <trans-unit id="_msg212">
+ <trans-unit id="_msg221">
<source xml:space="preserve">Creating Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
- <context-group purpose="location"><context context-type="linenumber">246</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">247</context></context-group>
<note annotates="source" from="developer">Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</note>
</trans-unit>
- <trans-unit id="_msg213">
+ <trans-unit id="_msg222">
<source xml:space="preserve">Create wallet failed</source>
- <context-group purpose="location"><context context-type="linenumber">275</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">280</context></context-group>
</trans-unit>
- <trans-unit id="_msg214">
+ <trans-unit id="_msg223">
<source xml:space="preserve">Create wallet warning</source>
- <context-group purpose="location"><context context-type="linenumber">277</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">282</context></context-group>
</trans-unit>
- <trans-unit id="_msg215">
+ <trans-unit id="_msg224">
<source xml:space="preserve">Can&apos;t list signers</source>
- <context-group purpose="location"><context context-type="linenumber">293</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">298</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg225">
+ <source xml:space="preserve">Too many external signers found</source>
+ <context-group purpose="location"><context context-type="linenumber">301</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="LoadWalletsActivity">
- <trans-unit id="_msg216">
+ <trans-unit id="_msg226">
<source xml:space="preserve">Load Wallets</source>
- <context-group purpose="location"><context context-type="linenumber">362</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">375</context></context-group>
<note annotates="source" from="developer">Title of progress window which is displayed when wallets are being loaded.</note>
</trans-unit>
- <trans-unit id="_msg217">
+ <trans-unit id="_msg227">
<source xml:space="preserve">Loading wallets…</source>
- <context-group purpose="location"><context context-type="linenumber">365</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">378</context></context-group>
<note annotates="source" from="developer">Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</note>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="OpenWalletActivity">
- <trans-unit id="_msg218">
+ <trans-unit id="_msg228">
<source xml:space="preserve">Open wallet failed</source>
- <context-group purpose="location"><context context-type="linenumber">323</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
</trans-unit>
- <trans-unit id="_msg219">
+ <trans-unit id="_msg229">
<source xml:space="preserve">Open wallet warning</source>
- <context-group purpose="location"><context context-type="linenumber">325</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg220">
+ <trans-unit id="_msg230">
<source xml:space="preserve">default wallet</source>
- <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg221">
+ <trans-unit id="_msg231">
<source xml:space="preserve">Open Wallet</source>
- <context-group purpose="location"><context context-type="linenumber">339</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">348</context></context-group>
<note annotates="source" from="developer">Title of window indicating the progress of opening of a wallet.</note>
</trans-unit>
- <trans-unit id="_msg222">
+ <trans-unit id="_msg232">
<source xml:space="preserve">Opening Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
- <context-group purpose="location"><context context-type="linenumber">342</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">351</context></context-group>
<note annotates="source" from="developer">Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</note>
</trans-unit>
</group>
+ <group restype="x-trolltech-linguist-context" resname="RestoreWalletActivity">
+ <trans-unit id="_msg233">
+ <source xml:space="preserve">Restore Wallet</source>
+ <context-group purpose="location"><context context-type="linenumber">400</context></context-group>
+ <note annotates="source" from="developer">Title of progress window which is displayed when wallets are being restored.</note>
+ </trans-unit>
+ <trans-unit id="_msg234">
+ <source xml:space="preserve">Restoring Wallet &lt;b&gt;%1&lt;/b&gt;…</source>
+ <context-group purpose="location"><context context-type="linenumber">403</context></context-group>
+ <note annotates="source" from="developer">Descriptive text of the restore wallets progress window which indicates to the user that wallets are currently being restored.</note>
+ </trans-unit>
+ <trans-unit id="_msg235">
+ <source xml:space="preserve">Restore wallet failed</source>
+ <context-group purpose="location"><context context-type="linenumber">422</context></context-group>
+ <note annotates="source" from="developer">Title of message box which is displayed when the wallet could not be restored.</note>
+ </trans-unit>
+ <trans-unit id="_msg236">
+ <source xml:space="preserve">Restore wallet warning</source>
+ <context-group purpose="location"><context context-type="linenumber">425</context></context-group>
+ <note annotates="source" from="developer">Title of message box which is displayed when the wallet is restored with some warning.</note>
+ </trans-unit>
+ <trans-unit id="_msg237">
+ <source xml:space="preserve">Restore wallet message</source>
+ <context-group purpose="location"><context context-type="linenumber">428</context></context-group>
+ <note annotates="source" from="developer">Title of message box which is displayed when the wallet is successfully restored.</note>
+ </trans-unit>
+ </group>
<group restype="x-trolltech-linguist-context" resname="WalletController">
- <trans-unit id="_msg223">
+ <trans-unit id="_msg238">
<source xml:space="preserve">Close wallet</source>
- <context-group purpose="location"><context context-type="linenumber">83</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">84</context></context-group>
</trans-unit>
- <trans-unit id="_msg224">
+ <trans-unit id="_msg239">
<source xml:space="preserve">Are you sure you wish to close the wallet &lt;i&gt;%1&lt;/i&gt;?</source>
- <context-group purpose="location"><context context-type="linenumber">84</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
- <trans-unit id="_msg225">
+ <trans-unit id="_msg240">
<source xml:space="preserve">Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source>
- <context-group purpose="location"><context context-type="linenumber">85</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg226">
+ <trans-unit id="_msg241">
<source xml:space="preserve">Close all wallets</source>
- <context-group purpose="location"><context context-type="linenumber">98</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg227">
+ <trans-unit id="_msg242">
<source xml:space="preserve">Are you sure you wish to close all wallets?</source>
- <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/createwalletdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletDialog">
- <trans-unit id="_msg228">
+ <trans-unit id="_msg243">
<source xml:space="preserve">Create Wallet</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg229">
+ <trans-unit id="_msg244">
<source xml:space="preserve">Wallet Name</source>
<context-group purpose="location"><context context-type="linenumber">25</context></context-group>
</trans-unit>
- <trans-unit id="_msg230">
+ <trans-unit id="_msg245">
<source xml:space="preserve">Wallet</source>
<context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg231">
+ <trans-unit id="_msg246">
<source xml:space="preserve">Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source>
<context-group purpose="location"><context context-type="linenumber">47</context></context-group>
</trans-unit>
- <trans-unit id="_msg232">
+ <trans-unit id="_msg247">
<source xml:space="preserve">Encrypt Wallet</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg233">
+ <trans-unit id="_msg248">
<source xml:space="preserve">Advanced Options</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg234">
+ <trans-unit id="_msg249">
<source xml:space="preserve">Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets.</source>
<context-group purpose="location"><context context-type="linenumber">85</context></context-group>
</trans-unit>
- <trans-unit id="_msg235">
+ <trans-unit id="_msg250">
<source xml:space="preserve">Disable Private Keys</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
</trans-unit>
- <trans-unit id="_msg236">
+ <trans-unit id="_msg251">
<source xml:space="preserve">Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time.</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg237">
+ <trans-unit id="_msg252">
<source xml:space="preserve">Make Blank Wallet</source>
<context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg238">
+ <trans-unit id="_msg253">
<source xml:space="preserve">Use descriptors for scriptPubKey management</source>
<context-group purpose="location"><context context-type="linenumber">105</context></context-group>
</trans-unit>
- <trans-unit id="_msg239">
+ <trans-unit id="_msg254">
<source xml:space="preserve">Descriptor Wallet</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
- <trans-unit id="_msg240">
+ <trans-unit id="_msg255">
<source xml:space="preserve">Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source>
<context-group purpose="location"><context context-type="linenumber">118</context></context-group>
</trans-unit>
- <trans-unit id="_msg241">
+ <trans-unit id="_msg256">
<source xml:space="preserve">External signer</source>
<context-group purpose="location"><context context-type="linenumber">121</context></context-group>
</trans-unit>
@@ -1069,15 +1142,15 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../createwalletdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="CreateWalletDialog">
- <trans-unit id="_msg242">
+ <trans-unit id="_msg257">
<source xml:space="preserve">Create</source>
<context-group purpose="location"><context context-type="linenumber">22</context></context-group>
</trans-unit>
- <trans-unit id="_msg243">
+ <trans-unit id="_msg258">
<source xml:space="preserve">Compiled without sqlite support (required for descriptor wallets)</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg244">
+ <trans-unit id="_msg259">
<source xml:space="preserve">Compiled without external signing support (required for external signing)</source>
<context-group purpose="location"><context context-type="linenumber">104</context></context-group>
<note annotates="source" from="developer">&quot;External signing&quot; means using devices such as hardware wallets.</note>
@@ -1086,23 +1159,23 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/editaddressdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="EditAddressDialog">
- <trans-unit id="_msg245">
+ <trans-unit id="_msg260">
<source xml:space="preserve">Edit Address</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg246">
+ <trans-unit id="_msg261">
<source xml:space="preserve">&amp;Label</source>
<context-group purpose="location"><context context-type="linenumber">25</context></context-group>
</trans-unit>
- <trans-unit id="_msg247">
+ <trans-unit id="_msg262">
<source xml:space="preserve">The label associated with this address list entry</source>
<context-group purpose="location"><context context-type="linenumber">35</context></context-group>
</trans-unit>
- <trans-unit id="_msg248">
+ <trans-unit id="_msg263">
<source xml:space="preserve">The address associated with this address list entry. This can only be modified for sending addresses.</source>
<context-group purpose="location"><context context-type="linenumber">52</context></context-group>
</trans-unit>
- <trans-unit id="_msg249">
+ <trans-unit id="_msg264">
<source xml:space="preserve">&amp;Address</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
@@ -1110,35 +1183,35 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../editaddressdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="EditAddressDialog">
- <trans-unit id="_msg250">
+ <trans-unit id="_msg265">
<source xml:space="preserve">New sending address</source>
<context-group purpose="location"><context context-type="linenumber">29</context></context-group>
</trans-unit>
- <trans-unit id="_msg251">
+ <trans-unit id="_msg266">
<source xml:space="preserve">Edit receiving address</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg252">
+ <trans-unit id="_msg267">
<source xml:space="preserve">Edit sending address</source>
<context-group purpose="location"><context context-type="linenumber">36</context></context-group>
</trans-unit>
- <trans-unit id="_msg253">
+ <trans-unit id="_msg268">
<source xml:space="preserve">The entered address &quot;%1&quot; is not a valid Bitcoin address.</source>
<context-group purpose="location"><context context-type="linenumber">113</context></context-group>
</trans-unit>
- <trans-unit id="_msg254">
+ <trans-unit id="_msg269">
<source xml:space="preserve">Address &quot;%1&quot; already exists as a receiving address with label &quot;%2&quot; and so cannot be added as a sending address.</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
- <trans-unit id="_msg255">
+ <trans-unit id="_msg270">
<source xml:space="preserve">The entered address &quot;%1&quot; is already in the address book with label &quot;%2&quot;.</source>
<context-group purpose="location"><context context-type="linenumber">151</context></context-group>
</trans-unit>
- <trans-unit id="_msg256">
+ <trans-unit id="_msg271">
<source xml:space="preserve">Could not unlock wallet.</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
- <trans-unit id="_msg257">
+ <trans-unit id="_msg272">
<source xml:space="preserve">New key generation failed.</source>
<context-group purpose="location"><context context-type="linenumber">128</context></context-group>
</trans-unit>
@@ -1146,75 +1219,90 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../intro.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="FreespaceChecker">
- <trans-unit id="_msg258">
+ <trans-unit id="_msg273">
<source xml:space="preserve">A new data directory will be created.</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg259">
+ <trans-unit id="_msg274">
<source xml:space="preserve">name</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg260">
+ <trans-unit id="_msg275">
<source xml:space="preserve">Directory already exists. Add %1 if you intend to create a new directory here.</source>
<context-group purpose="location"><context context-type="linenumber">97</context></context-group>
</trans-unit>
- <trans-unit id="_msg261">
+ <trans-unit id="_msg276">
<source xml:space="preserve">Path already exists, and is not a directory.</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
- <trans-unit id="_msg262">
+ <trans-unit id="_msg277">
<source xml:space="preserve">Cannot create data directory here.</source>
<context-group purpose="location"><context context-type="linenumber">107</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="Intro">
- <trans-unit id="_msg263">
+ <trans-unit id="_msg278">
<source xml:space="preserve">Bitcoin</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
</trans-unit>
- <trans-unit id="_msg264">
- <source xml:space="preserve">%1 GB of space available</source>
+ <group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
- </trans-unit>
- <trans-unit id="_msg265">
- <source xml:space="preserve">(of %1 GB needed)</source>
+ <trans-unit id="_msg279[0]">
+ <source xml:space="preserve">%n GB of space available</source>
+ </trans-unit>
+ <trans-unit id="_msg279[1]">
+ <source xml:space="preserve">%n GB of space available</source>
+ </trans-unit>
+ </group>
+ <group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">303</context></context-group>
- </trans-unit>
- <trans-unit id="_msg266">
- <source xml:space="preserve">(%1 GB needed for full chain)</source>
+ <trans-unit id="_msg280[0]">
+ <source xml:space="preserve">(of %n GB needed)</source>
+ </trans-unit>
+ <trans-unit id="_msg280[1]">
+ <source xml:space="preserve">(of %n GB needed)</source>
+ </trans-unit>
+ </group>
+ <group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">306</context></context-group>
- </trans-unit>
- <trans-unit id="_msg267">
+ <trans-unit id="_msg281[0]">
+ <source xml:space="preserve">(%n GB needed for full chain)</source>
+ </trans-unit>
+ <trans-unit id="_msg281[1]">
+ <source xml:space="preserve">(%n GB needed for full chain)</source>
+ </trans-unit>
+ </group>
+ <trans-unit id="_msg282">
<source xml:space="preserve">At least %1 GB of data will be stored in this directory, and it will grow over time.</source>
<context-group purpose="location"><context context-type="linenumber">378</context></context-group>
</trans-unit>
- <trans-unit id="_msg268">
+ <trans-unit id="_msg283">
<source xml:space="preserve">Approximately %1 GB of data will be stored in this directory.</source>
<context-group purpose="location"><context context-type="linenumber">381</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
<context-group purpose="location"><context context-type="linenumber">390</context></context-group>
<note annotates="source" from="developer">Explanatory text on the capability of the current prune target.</note>
- <trans-unit id="_msg269[0]">
+ <trans-unit id="_msg284[0]">
<source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source>
</trans-unit>
- <trans-unit id="_msg269[1]">
+ <trans-unit id="_msg284[1]">
<source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source>
</trans-unit>
</group>
- <trans-unit id="_msg270">
+ <trans-unit id="_msg285">
<source xml:space="preserve">%1 will download and store a copy of the Bitcoin block chain.</source>
<context-group purpose="location"><context context-type="linenumber">392</context></context-group>
</trans-unit>
- <trans-unit id="_msg271">
+ <trans-unit id="_msg286">
<source xml:space="preserve">The wallet will also be stored in this directory.</source>
<context-group purpose="location"><context context-type="linenumber">394</context></context-group>
</trans-unit>
- <trans-unit id="_msg272">
+ <trans-unit id="_msg287">
<source xml:space="preserve">Error: Specified data directory &quot;%1&quot; cannot be created.</source>
<context-group purpose="location"><context context-type="linenumber">250</context></context-group>
</trans-unit>
- <trans-unit id="_msg273">
+ <trans-unit id="_msg288">
<source xml:space="preserve">Error</source>
<context-group purpose="location"><context context-type="linenumber">280</context></context-group>
</trans-unit>
@@ -1222,25 +1310,25 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../utilitydialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="HelpMessageDialog">
- <trans-unit id="_msg274">
+ <trans-unit id="_msg289">
<source xml:space="preserve">version</source>
- <context-group purpose="location"><context context-type="linenumber">37</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg275">
+ <trans-unit id="_msg290">
<source xml:space="preserve">About %1</source>
- <context-group purpose="location"><context context-type="linenumber">41</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
- <trans-unit id="_msg276">
+ <trans-unit id="_msg291">
<source xml:space="preserve">Command-line options</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="ShutdownWindow">
- <trans-unit id="_msg277">
+ <trans-unit id="_msg292">
<source xml:space="preserve">%1 is shutting down…</source>
<context-group purpose="location"><context context-type="linenumber">145</context></context-group>
</trans-unit>
- <trans-unit id="_msg278">
+ <trans-unit id="_msg293">
<source xml:space="preserve">Do not shut down the computer until this window disappears.</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
@@ -1248,47 +1336,47 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/intro.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="Intro">
- <trans-unit id="_msg279">
+ <trans-unit id="_msg294">
<source xml:space="preserve">Welcome</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg280">
+ <trans-unit id="_msg295">
<source xml:space="preserve">Welcome to %1.</source>
<context-group purpose="location"><context context-type="linenumber">23</context></context-group>
</trans-unit>
- <trans-unit id="_msg281">
+ <trans-unit id="_msg296">
<source xml:space="preserve">As this is the first time the program is launched, you can choose where %1 will store its data.</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg282">
+ <trans-unit id="_msg297">
<source xml:space="preserve">When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source>
<context-group purpose="location"><context context-type="linenumber">206</context></context-group>
</trans-unit>
- <trans-unit id="_msg283">
+ <trans-unit id="_msg298">
<source xml:space="preserve">Limit block chain storage to</source>
<context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg284">
+ <trans-unit id="_msg299">
<source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg285">
+ <trans-unit id="_msg300">
<source xml:space="preserve"> GB</source>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg286">
+ <trans-unit id="_msg301">
<source xml:space="preserve">This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg287">
+ <trans-unit id="_msg302">
<source xml:space="preserve">If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source>
<context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg288">
+ <trans-unit id="_msg303">
<source xml:space="preserve">Use the default data directory</source>
<context-group purpose="location"><context context-type="linenumber">66</context></context-group>
</trans-unit>
- <trans-unit id="_msg289">
+ <trans-unit id="_msg304">
<source xml:space="preserve">Use a custom data directory:</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
@@ -1296,54 +1384,54 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/modaloverlay.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ModalOverlay">
- <trans-unit id="_msg290">
+ <trans-unit id="_msg305">
<source xml:space="preserve">Form</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg291">
+ <trans-unit id="_msg306">
<source xml:space="preserve">Recent transactions may not yet be visible, and therefore your wallet&apos;s balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source>
<context-group purpose="location"><context context-type="linenumber">133</context></context-group>
</trans-unit>
- <trans-unit id="_msg292">
+ <trans-unit id="_msg307">
<source xml:space="preserve">Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source>
<context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg293">
+ <trans-unit id="_msg308">
<source xml:space="preserve">Number of blocks left</source>
<context-group purpose="location"><context context-type="linenumber">215</context></context-group>
</trans-unit>
- <trans-unit id="_msg294">
+ <trans-unit id="_msg309">
<source xml:space="preserve">Unknown…</source>
<context-group purpose="location"><context context-type="linenumber">222</context></context-group>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
<context-group purpose="location"><context context-type="sourcefile">../modaloverlay.cpp</context><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg295">
+ <trans-unit id="_msg310">
<source xml:space="preserve">calculating…</source>
<context-group purpose="location"><context context-type="linenumber">292</context></context-group>
<context-group purpose="location"><context context-type="linenumber">312</context></context-group>
</trans-unit>
- <trans-unit id="_msg296">
+ <trans-unit id="_msg311">
<source xml:space="preserve">Last block time</source>
<context-group purpose="location"><context context-type="linenumber">235</context></context-group>
</trans-unit>
- <trans-unit id="_msg297">
+ <trans-unit id="_msg312">
<source xml:space="preserve">Progress</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg298">
+ <trans-unit id="_msg313">
<source xml:space="preserve">Progress increase per hour</source>
<context-group purpose="location"><context context-type="linenumber">285</context></context-group>
</trans-unit>
- <trans-unit id="_msg299">
+ <trans-unit id="_msg314">
<source xml:space="preserve">Estimated time left until synced</source>
<context-group purpose="location"><context context-type="linenumber">305</context></context-group>
</trans-unit>
- <trans-unit id="_msg300">
+ <trans-unit id="_msg315">
<source xml:space="preserve">Hide</source>
<context-group purpose="location"><context context-type="linenumber">342</context></context-group>
</trans-unit>
- <trans-unit id="_msg301">
+ <trans-unit id="_msg316">
<source xml:space="preserve">Esc</source>
<context-group purpose="location"><context context-type="linenumber">345</context></context-group>
</trans-unit>
@@ -1351,17 +1439,17 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../modaloverlay.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ModalOverlay">
- <trans-unit id="_msg302">
+ <trans-unit id="_msg317">
<source xml:space="preserve">%1 is currently syncing. It will download headers and blocks from peers and validate them until reaching the tip of the block chain.</source>
<context-group purpose="location"><context context-type="linenumber">34</context></context-group>
</trans-unit>
- <trans-unit id="_msg303">
+ <trans-unit id="_msg318">
<source xml:space="preserve">Unknown. Syncing Headers (%1, %2%)…</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
</group>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg304">
+ <trans-unit id="_msg319">
<source xml:space="preserve">unknown</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
@@ -1369,15 +1457,15 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/openuridialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OpenURIDialog">
- <trans-unit id="_msg305">
+ <trans-unit id="_msg320">
<source xml:space="preserve">Open bitcoin URI</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg306">
+ <trans-unit id="_msg321">
<source xml:space="preserve">URI:</source>
<context-group purpose="location"><context context-type="linenumber">22</context></context-group>
</trans-unit>
- <trans-unit id="_msg307">
+ <trans-unit id="_msg322">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">36</context></context-group>
<note annotates="source" from="developer">Tooltip text for button that allows you to paste an address that is in your clipboard.</note>
@@ -1386,310 +1474,310 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../forms/optionsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsDialog">
- <trans-unit id="_msg308">
+ <trans-unit id="_msg323">
<source xml:space="preserve">Options</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg309">
+ <trans-unit id="_msg324">
<source xml:space="preserve">&amp;Main</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg310">
+ <trans-unit id="_msg325">
<source xml:space="preserve">Automatically start %1 after logging in to the system.</source>
<context-group purpose="location"><context context-type="linenumber">33</context></context-group>
</trans-unit>
- <trans-unit id="_msg311">
+ <trans-unit id="_msg326">
<source xml:space="preserve">&amp;Start %1 on system login</source>
<context-group purpose="location"><context context-type="linenumber">36</context></context-group>
</trans-unit>
- <trans-unit id="_msg312">
+ <trans-unit id="_msg327">
<source xml:space="preserve">Enabling pruning significantly reduces the disk space required to store transactions. All blocks are still fully validated. Reverting this setting requires re-downloading the entire blockchain.</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg313">
+ <trans-unit id="_msg328">
<source xml:space="preserve">Size of &amp;database cache</source>
<context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg314">
+ <trans-unit id="_msg329">
<source xml:space="preserve">Number of script &amp;verification threads</source>
<context-group purpose="location"><context context-type="linenumber">157</context></context-group>
</trans-unit>
- <trans-unit id="_msg315">
+ <trans-unit id="_msg330">
<source xml:space="preserve">IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
<context-group purpose="location"><context context-type="linenumber">388</context></context-group>
<context-group purpose="location"><context context-type="linenumber">575</context></context-group>
</trans-unit>
- <trans-unit id="_msg316">
+ <trans-unit id="_msg331">
<source xml:space="preserve">Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source>
<context-group purpose="location"><context context-type="linenumber">457</context></context-group>
<context-group purpose="location"><context context-type="linenumber">480</context></context-group>
<context-group purpose="location"><context context-type="linenumber">503</context></context-group>
</trans-unit>
- <trans-unit id="_msg317">
+ <trans-unit id="_msg332">
<source xml:space="preserve">Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
<context-group purpose="location"><context context-type="linenumber">672</context></context-group>
</trans-unit>
- <trans-unit id="_msg318">
+ <trans-unit id="_msg333">
+ <source xml:space="preserve">Options set in this dialog are overridden by the command line:</source>
+ <context-group purpose="location"><context context-type="linenumber">899</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg334">
<source xml:space="preserve">Open the %1 configuration file from the working directory.</source>
<context-group purpose="location"><context context-type="linenumber">944</context></context-group>
</trans-unit>
- <trans-unit id="_msg319">
+ <trans-unit id="_msg335">
<source xml:space="preserve">Open Configuration File</source>
<context-group purpose="location"><context context-type="linenumber">947</context></context-group>
</trans-unit>
- <trans-unit id="_msg320">
+ <trans-unit id="_msg336">
<source xml:space="preserve">Reset all client options to default.</source>
<context-group purpose="location"><context context-type="linenumber">957</context></context-group>
</trans-unit>
- <trans-unit id="_msg321">
+ <trans-unit id="_msg337">
<source xml:space="preserve">&amp;Reset Options</source>
<context-group purpose="location"><context context-type="linenumber">960</context></context-group>
</trans-unit>
- <trans-unit id="_msg322">
+ <trans-unit id="_msg338">
<source xml:space="preserve">&amp;Network</source>
<context-group purpose="location"><context context-type="linenumber">315</context></context-group>
</trans-unit>
- <trans-unit id="_msg323">
+ <trans-unit id="_msg339">
<source xml:space="preserve">Prune &amp;block storage to</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg324">
+ <trans-unit id="_msg340">
<source xml:space="preserve">GB</source>
<context-group purpose="location"><context context-type="linenumber">71</context></context-group>
</trans-unit>
- <trans-unit id="_msg325">
+ <trans-unit id="_msg341">
<source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg326">
+ <trans-unit id="_msg342">
<source xml:space="preserve">Maximum database cache size. A larger cache can contribute to faster sync, after which the benefit is less pronounced for most use cases. Lowering the cache size will reduce memory usage. Unused mempool memory is shared for this cache.</source>
<context-group purpose="location"><context context-type="linenumber">108</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</note>
</trans-unit>
- <trans-unit id="_msg327">
+ <trans-unit id="_msg343">
<source xml:space="preserve">MiB</source>
<context-group purpose="location"><context context-type="linenumber">127</context></context-group>
</trans-unit>
- <trans-unit id="_msg328">
+ <trans-unit id="_msg344">
<source xml:space="preserve">Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source>
<context-group purpose="location"><context context-type="linenumber">154</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets the number of script verification threads. Explains that negative values mean to leave these many cores free to the system.</note>
</trans-unit>
- <trans-unit id="_msg329">
+ <trans-unit id="_msg345">
<source xml:space="preserve">(0 = auto, &lt;0 = leave that many cores free)</source>
<context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg330">
+ <trans-unit id="_msg346">
<source xml:space="preserve">This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source>
<context-group purpose="location"><context context-type="linenumber">192</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that enables the RPC server.</note>
</trans-unit>
- <trans-unit id="_msg331">
+ <trans-unit id="_msg347">
<source xml:space="preserve">Enable R&amp;PC server</source>
<context-group purpose="location"><context context-type="linenumber">195</context></context-group>
<note annotates="source" from="developer">An Options window setting to enable the RPC server.</note>
</trans-unit>
- <trans-unit id="_msg332">
+ <trans-unit id="_msg348">
<source xml:space="preserve">W&amp;allet</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg333">
+ <trans-unit id="_msg349">
<source xml:space="preserve">Whether to set subtract fee from amount as default or not.</source>
<context-group purpose="location"><context context-type="linenumber">222</context></context-group>
<note annotates="source" from="developer">Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</note>
</trans-unit>
- <trans-unit id="_msg334">
+ <trans-unit id="_msg350">
<source xml:space="preserve">Subtract &amp;fee from amount by default</source>
<context-group purpose="location"><context context-type="linenumber">225</context></context-group>
<note annotates="source" from="developer">An Options window setting to set subtracting the fee from a sending amount as default.</note>
</trans-unit>
- <trans-unit id="_msg335">
+ <trans-unit id="_msg351">
<source xml:space="preserve">Expert</source>
<context-group purpose="location"><context context-type="linenumber">232</context></context-group>
</trans-unit>
- <trans-unit id="_msg336">
+ <trans-unit id="_msg352">
<source xml:space="preserve">Enable coin &amp;control features</source>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg337">
+ <trans-unit id="_msg353">
<source xml:space="preserve">If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source>
<context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg338">
+ <trans-unit id="_msg354">
<source xml:space="preserve">&amp;Spend unconfirmed change</source>
<context-group purpose="location"><context context-type="linenumber">251</context></context-group>
</trans-unit>
- <trans-unit id="_msg339">
+ <trans-unit id="_msg355">
<source xml:space="preserve">Enable &amp;PSBT controls</source>
<context-group purpose="location"><context context-type="linenumber">258</context></context-group>
<note annotates="source" from="developer">An options window setting to enable PSBT controls.</note>
</trans-unit>
- <trans-unit id="_msg340">
+ <trans-unit id="_msg356">
<source xml:space="preserve">Whether to show PSBT controls.</source>
<context-group purpose="location"><context context-type="linenumber">261</context></context-group>
<note annotates="source" from="developer">Tooltip text for options window setting that enables PSBT controls.</note>
</trans-unit>
- <trans-unit id="_msg341">
+ <trans-unit id="_msg357">
<source xml:space="preserve">External Signer (e.g. hardware wallet)</source>
<context-group purpose="location"><context context-type="linenumber">271</context></context-group>
</trans-unit>
- <trans-unit id="_msg342">
+ <trans-unit id="_msg358">
<source xml:space="preserve">&amp;External signer script path</source>
<context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg343">
+ <trans-unit id="_msg359">
<source xml:space="preserve">Full path to a Bitcoin Core compatible script (e.g. C:\Downloads\hwi.exe or /Users/you/Downloads/hwi.py). Beware: malware can steal your coins!</source>
<context-group purpose="location"><context context-type="linenumber">289</context></context-group>
</trans-unit>
- <trans-unit id="_msg344">
+ <trans-unit id="_msg360">
<source xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg345">
+ <trans-unit id="_msg361">
<source xml:space="preserve">Map port using &amp;UPnP</source>
<context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg346">
+ <trans-unit id="_msg362">
<source xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports NAT-PMP and it is enabled. The external port could be random.</source>
<context-group purpose="location"><context context-type="linenumber">331</context></context-group>
</trans-unit>
- <trans-unit id="_msg347">
+ <trans-unit id="_msg363">
<source xml:space="preserve">Map port using NA&amp;T-PMP</source>
<context-group purpose="location"><context context-type="linenumber">334</context></context-group>
</trans-unit>
- <trans-unit id="_msg348">
+ <trans-unit id="_msg364">
<source xml:space="preserve">Accept connections from outside.</source>
<context-group purpose="location"><context context-type="linenumber">341</context></context-group>
</trans-unit>
- <trans-unit id="_msg349">
+ <trans-unit id="_msg365">
<source xml:space="preserve">Allow incomin&amp;g connections</source>
<context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg350">
+ <trans-unit id="_msg366">
<source xml:space="preserve">Connect to the Bitcoin network through a SOCKS5 proxy.</source>
<context-group purpose="location"><context context-type="linenumber">351</context></context-group>
</trans-unit>
- <trans-unit id="_msg351">
+ <trans-unit id="_msg367">
<source xml:space="preserve">&amp;Connect through SOCKS5 proxy (default proxy):</source>
<context-group purpose="location"><context context-type="linenumber">354</context></context-group>
</trans-unit>
- <trans-unit id="_msg352">
+ <trans-unit id="_msg368">
<source xml:space="preserve">Proxy &amp;IP:</source>
<context-group purpose="location"><context context-type="linenumber">363</context></context-group>
<context-group purpose="location"><context context-type="linenumber">550</context></context-group>
</trans-unit>
- <trans-unit id="_msg353">
+ <trans-unit id="_msg369">
<source xml:space="preserve">&amp;Port:</source>
<context-group purpose="location"><context context-type="linenumber">395</context></context-group>
<context-group purpose="location"><context context-type="linenumber">582</context></context-group>
</trans-unit>
- <trans-unit id="_msg354">
+ <trans-unit id="_msg370">
<source xml:space="preserve">Port of the proxy (e.g. 9050)</source>
<context-group purpose="location"><context context-type="linenumber">420</context></context-group>
<context-group purpose="location"><context context-type="linenumber">607</context></context-group>
</trans-unit>
- <trans-unit id="_msg355">
+ <trans-unit id="_msg371">
<source xml:space="preserve">Used for reaching peers via:</source>
<context-group purpose="location"><context context-type="linenumber">444</context></context-group>
</trans-unit>
- <trans-unit id="_msg356">
+ <trans-unit id="_msg372">
<source xml:space="preserve">IPv4</source>
<context-group purpose="location"><context context-type="linenumber">467</context></context-group>
</trans-unit>
- <trans-unit id="_msg357">
+ <trans-unit id="_msg373">
<source xml:space="preserve">IPv6</source>
<context-group purpose="location"><context context-type="linenumber">490</context></context-group>
</trans-unit>
- <trans-unit id="_msg358">
+ <trans-unit id="_msg374">
<source xml:space="preserve">Tor</source>
<context-group purpose="location"><context context-type="linenumber">513</context></context-group>
</trans-unit>
- <trans-unit id="_msg359">
+ <trans-unit id="_msg375">
<source xml:space="preserve">&amp;Window</source>
<context-group purpose="location"><context context-type="linenumber">643</context></context-group>
</trans-unit>
- <trans-unit id="_msg360">
+ <trans-unit id="_msg376">
<source xml:space="preserve">Show the icon in the system tray.</source>
<context-group purpose="location"><context context-type="linenumber">649</context></context-group>
</trans-unit>
- <trans-unit id="_msg361">
+ <trans-unit id="_msg377">
<source xml:space="preserve">&amp;Show tray icon</source>
<context-group purpose="location"><context context-type="linenumber">652</context></context-group>
</trans-unit>
- <trans-unit id="_msg362">
+ <trans-unit id="_msg378">
<source xml:space="preserve">Show only a tray icon after minimizing the window.</source>
<context-group purpose="location"><context context-type="linenumber">662</context></context-group>
</trans-unit>
- <trans-unit id="_msg363">
+ <trans-unit id="_msg379">
<source xml:space="preserve">&amp;Minimize to the tray instead of the taskbar</source>
<context-group purpose="location"><context context-type="linenumber">665</context></context-group>
</trans-unit>
- <trans-unit id="_msg364">
+ <trans-unit id="_msg380">
<source xml:space="preserve">M&amp;inimize on close</source>
<context-group purpose="location"><context context-type="linenumber">675</context></context-group>
</trans-unit>
- <trans-unit id="_msg365">
+ <trans-unit id="_msg381">
<source xml:space="preserve">&amp;Display</source>
<context-group purpose="location"><context context-type="linenumber">696</context></context-group>
</trans-unit>
- <trans-unit id="_msg366">
+ <trans-unit id="_msg382">
<source xml:space="preserve">User Interface &amp;language:</source>
<context-group purpose="location"><context context-type="linenumber">704</context></context-group>
</trans-unit>
- <trans-unit id="_msg367">
+ <trans-unit id="_msg383">
<source xml:space="preserve">The user interface language can be set here. This setting will take effect after restarting %1.</source>
<context-group purpose="location"><context context-type="linenumber">717</context></context-group>
</trans-unit>
- <trans-unit id="_msg368">
+ <trans-unit id="_msg384">
<source xml:space="preserve">&amp;Unit to show amounts in:</source>
<context-group purpose="location"><context context-type="linenumber">728</context></context-group>
</trans-unit>
- <trans-unit id="_msg369">
+ <trans-unit id="_msg385">
<source xml:space="preserve">Choose the default subdivision unit to show in the interface and when sending coins.</source>
<context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
- <trans-unit id="_msg370">
+ <trans-unit id="_msg386">
<source xml:space="preserve">Third-party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<context-group purpose="location"><context context-type="linenumber">752</context></context-group>
<context-group purpose="location"><context context-type="linenumber">765</context></context-group>
</trans-unit>
- <trans-unit id="_msg371">
+ <trans-unit id="_msg387">
<source xml:space="preserve">&amp;Third-party transaction URLs</source>
<context-group purpose="location"><context context-type="linenumber">755</context></context-group>
</trans-unit>
- <trans-unit id="_msg372">
+ <trans-unit id="_msg388">
<source xml:space="preserve">Whether to show coin control features or not.</source>
<context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg373">
+ <trans-unit id="_msg389">
<source xml:space="preserve">Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source>
<context-group purpose="location"><context context-type="linenumber">538</context></context-group>
</trans-unit>
- <trans-unit id="_msg374">
+ <trans-unit id="_msg390">
<source xml:space="preserve">Use separate SOCKS&amp;5 proxy to reach peers via Tor onion services:</source>
<context-group purpose="location"><context context-type="linenumber">541</context></context-group>
</trans-unit>
- <trans-unit id="_msg375">
+ <trans-unit id="_msg391">
<source xml:space="preserve">Monospaced font in the Overview tab:</source>
<context-group purpose="location"><context context-type="linenumber">777</context></context-group>
</trans-unit>
- <trans-unit id="_msg376">
+ <trans-unit id="_msg392">
<source xml:space="preserve">embedded &quot;%1&quot;</source>
<context-group purpose="location"><context context-type="linenumber">785</context></context-group>
</trans-unit>
- <trans-unit id="_msg377">
+ <trans-unit id="_msg393">
<source xml:space="preserve">closest matching &quot;%1&quot;</source>
<context-group purpose="location"><context context-type="linenumber">834</context></context-group>
</trans-unit>
- <trans-unit id="_msg378">
- <source xml:space="preserve">Options set in this dialog are overridden by the command line or in the configuration file:</source>
- <context-group purpose="location"><context context-type="linenumber">899</context></context-group>
- </trans-unit>
- <trans-unit id="_msg379">
+ <trans-unit id="_msg394">
<source xml:space="preserve">&amp;OK</source>
<context-group purpose="location"><context context-type="linenumber">1040</context></context-group>
</trans-unit>
- <trans-unit id="_msg380">
+ <trans-unit id="_msg395">
<source xml:space="preserve">&amp;Cancel</source>
<context-group purpose="location"><context context-type="linenumber">1053</context></context-group>
</trans-unit>
@@ -1697,140 +1785,156 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../optionsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OptionsDialog">
- <trans-unit id="_msg381">
+ <trans-unit id="_msg396">
<source xml:space="preserve">Compiled without external signing support (required for external signing)</source>
- <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
<note annotates="source" from="developer">&quot;External signing&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg382">
+ <trans-unit id="_msg397">
<source xml:space="preserve">default</source>
- <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">108</context></context-group>
</trans-unit>
- <trans-unit id="_msg383">
+ <trans-unit id="_msg398">
<source xml:space="preserve">none</source>
- <context-group purpose="location"><context context-type="linenumber">192</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">194</context></context-group>
</trans-unit>
- <trans-unit id="_msg384">
+ <trans-unit id="_msg399">
<source xml:space="preserve">Confirm options reset</source>
- <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">301</context></context-group>
+ <note annotates="source" from="developer">Window title text of pop-up window shown when the user has chosen to reset options.</note>
</trans-unit>
- <trans-unit id="_msg385">
+ <trans-unit id="_msg400">
<source xml:space="preserve">Client restart required to activate changes.</source>
- <context-group purpose="location"><context context-type="linenumber">290</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">360</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">371</context></context-group>
+ <note annotates="source" from="developer">Text explaining that the settings changed will not come into effect until the client is restarted.</note>
</trans-unit>
- <trans-unit id="_msg386">
+ <trans-unit id="_msg401">
+ <source xml:space="preserve">Current settings will be backed up at &quot;%1&quot;.</source>
+ <context-group purpose="location"><context context-type="linenumber">296</context></context-group>
+ <note annotates="source" from="developer">Text explaining to the user that the client&apos;s current settings will be backed up at a specific location. %1 is a stand-in argument for the backup location&apos;s path.</note>
+ </trans-unit>
+ <trans-unit id="_msg402">
<source xml:space="preserve">Client will be shut down. Do you want to proceed?</source>
- <context-group purpose="location"><context context-type="linenumber">290</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">299</context></context-group>
+ <note annotates="source" from="developer">Text asking the user to confirm if they would like to proceed with a client shutdown.</note>
</trans-unit>
- <trans-unit id="_msg387">
+ <trans-unit id="_msg403">
<source xml:space="preserve">Configuration options</source>
- <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">319</context></context-group>
<note annotates="source" from="developer">Window title text of pop-up box that allows opening up of configuration file.</note>
</trans-unit>
- <trans-unit id="_msg388">
+ <trans-unit id="_msg404">
<source xml:space="preserve">The configuration file is used to specify advanced user options which override GUI settings. Additionally, any command-line options will override this configuration file.</source>
- <context-group purpose="location"><context context-type="linenumber">311</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">322</context></context-group>
<note annotates="source" from="developer">Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</note>
</trans-unit>
- <trans-unit id="_msg389">
+ <trans-unit id="_msg405">
<source xml:space="preserve">Continue</source>
- <context-group purpose="location"><context context-type="linenumber">314</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg390">
+ <trans-unit id="_msg406">
<source xml:space="preserve">Cancel</source>
- <context-group purpose="location"><context context-type="linenumber">315</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg391">
+ <trans-unit id="_msg407">
<source xml:space="preserve">Error</source>
- <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg392">
+ <trans-unit id="_msg408">
<source xml:space="preserve">The configuration file could not be opened.</source>
- <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg393">
+ <trans-unit id="_msg409">
<source xml:space="preserve">This change would require a client restart.</source>
- <context-group purpose="location"><context context-type="linenumber">364</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">375</context></context-group>
</trans-unit>
- <trans-unit id="_msg394">
+ <trans-unit id="_msg410">
<source xml:space="preserve">The supplied proxy address is invalid.</source>
- <context-group purpose="location"><context context-type="linenumber">392</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">403</context></context-group>
+ </trans-unit>
+ </group>
+ </body></file>
+ <file original="../optionsmodel.cpp" datatype="cpp" source-language="en"><body>
+ <group restype="x-trolltech-linguist-context" resname="OptionsModel">
+ <trans-unit id="_msg411">
+ <source xml:space="preserve">Could not read setting &quot;%1&quot;, %2.</source>
+ <context-group purpose="location"><context context-type="linenumber">204</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/overviewpage.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OverviewPage">
- <trans-unit id="_msg395">
+ <trans-unit id="_msg412">
<source xml:space="preserve">Form</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg396">
+ <trans-unit id="_msg413">
<source xml:space="preserve">The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
<context-group purpose="location"><context context-type="linenumber">411</context></context-group>
</trans-unit>
- <trans-unit id="_msg397">
+ <trans-unit id="_msg414">
<source xml:space="preserve">Watch-only:</source>
<context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg398">
+ <trans-unit id="_msg415">
<source xml:space="preserve">Available:</source>
<context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
- <trans-unit id="_msg399">
+ <trans-unit id="_msg416">
<source xml:space="preserve">Your current spendable balance</source>
<context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg400">
+ <trans-unit id="_msg417">
<source xml:space="preserve">Pending:</source>
<context-group purpose="location"><context context-type="linenumber">339</context></context-group>
</trans-unit>
- <trans-unit id="_msg401">
+ <trans-unit id="_msg418">
<source xml:space="preserve">Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
</trans-unit>
- <trans-unit id="_msg402">
+ <trans-unit id="_msg419">
<source xml:space="preserve">Immature:</source>
<context-group purpose="location"><context context-type="linenumber">239</context></context-group>
</trans-unit>
- <trans-unit id="_msg403">
+ <trans-unit id="_msg420">
<source xml:space="preserve">Mined balance that has not yet matured</source>
<context-group purpose="location"><context context-type="linenumber">210</context></context-group>
</trans-unit>
- <trans-unit id="_msg404">
+ <trans-unit id="_msg421">
<source xml:space="preserve">Balances</source>
<context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg405">
+ <trans-unit id="_msg422">
<source xml:space="preserve">Total:</source>
<context-group purpose="location"><context context-type="linenumber">200</context></context-group>
</trans-unit>
- <trans-unit id="_msg406">
+ <trans-unit id="_msg423">
<source xml:space="preserve">Your current total balance</source>
<context-group purpose="location"><context context-type="linenumber">249</context></context-group>
</trans-unit>
- <trans-unit id="_msg407">
+ <trans-unit id="_msg424">
<source xml:space="preserve">Your current balance in watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg408">
+ <trans-unit id="_msg425">
<source xml:space="preserve">Spendable:</source>
<context-group purpose="location"><context context-type="linenumber">346</context></context-group>
</trans-unit>
- <trans-unit id="_msg409">
+ <trans-unit id="_msg426">
<source xml:space="preserve">Recent transactions</source>
<context-group purpose="location"><context context-type="linenumber">395</context></context-group>
</trans-unit>
- <trans-unit id="_msg410">
+ <trans-unit id="_msg427">
<source xml:space="preserve">Unconfirmed transactions to watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg411">
+ <trans-unit id="_msg428">
<source xml:space="preserve">Mined balance in watch-only addresses that has not yet matured</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg412">
+ <trans-unit id="_msg429">
<source xml:space="preserve">Current total balance in watch-only addresses</source>
<context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
@@ -1838,35 +1942,35 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../overviewpage.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="OverviewPage">
- <trans-unit id="_msg413">
+ <trans-unit id="_msg430">
<source xml:space="preserve">Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings-&gt;Mask values.</source>
- <context-group purpose="location"><context context-type="linenumber">187</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">186</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/psbtoperationsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog">
- <trans-unit id="_msg414">
+ <trans-unit id="_msg431">
<source xml:space="preserve">Dialog</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg415">
+ <trans-unit id="_msg432">
<source xml:space="preserve">Sign Tx</source>
<context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg416">
+ <trans-unit id="_msg433">
<source xml:space="preserve">Broadcast Tx</source>
<context-group purpose="location"><context context-type="linenumber">102</context></context-group>
</trans-unit>
- <trans-unit id="_msg417">
+ <trans-unit id="_msg434">
<source xml:space="preserve">Copy to Clipboard</source>
<context-group purpose="location"><context context-type="linenumber">122</context></context-group>
</trans-unit>
- <trans-unit id="_msg418">
+ <trans-unit id="_msg435">
<source xml:space="preserve">Save…</source>
<context-group purpose="location"><context context-type="linenumber">129</context></context-group>
</trans-unit>
- <trans-unit id="_msg419">
+ <trans-unit id="_msg436">
<source xml:space="preserve">Close</source>
<context-group purpose="location"><context context-type="linenumber">136</context></context-group>
</trans-unit>
@@ -1874,108 +1978,108 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../psbtoperationsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog">
- <trans-unit id="_msg420">
+ <trans-unit id="_msg437">
<source xml:space="preserve">Failed to load transaction: %1</source>
<context-group purpose="location"><context context-type="linenumber">61</context></context-group>
</trans-unit>
- <trans-unit id="_msg421">
+ <trans-unit id="_msg438">
<source xml:space="preserve">Failed to sign transaction: %1</source>
<context-group purpose="location"><context context-type="linenumber">86</context></context-group>
</trans-unit>
- <trans-unit id="_msg422">
+ <trans-unit id="_msg439">
<source xml:space="preserve">Cannot sign inputs while wallet is locked.</source>
<context-group purpose="location"><context context-type="linenumber">94</context></context-group>
</trans-unit>
- <trans-unit id="_msg423">
+ <trans-unit id="_msg440">
<source xml:space="preserve">Could not sign any more inputs.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg424">
+ <trans-unit id="_msg441">
<source xml:space="preserve">Signed %1 inputs, but more signatures are still required.</source>
<context-group purpose="location"><context context-type="linenumber">98</context></context-group>
</trans-unit>
- <trans-unit id="_msg425">
+ <trans-unit id="_msg442">
<source xml:space="preserve">Signed transaction successfully. Transaction is ready to broadcast.</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg426">
+ <trans-unit id="_msg443">
<source xml:space="preserve">Unknown error processing transaction.</source>
<context-group purpose="location"><context context-type="linenumber">113</context></context-group>
</trans-unit>
- <trans-unit id="_msg427">
+ <trans-unit id="_msg444">
<source xml:space="preserve">Transaction broadcast successfully! Transaction ID: %1</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
- <trans-unit id="_msg428">
+ <trans-unit id="_msg445">
<source xml:space="preserve">Transaction broadcast failed: %1</source>
<context-group purpose="location"><context context-type="linenumber">126</context></context-group>
</trans-unit>
- <trans-unit id="_msg429">
+ <trans-unit id="_msg446">
<source xml:space="preserve">PSBT copied to clipboard.</source>
<context-group purpose="location"><context context-type="linenumber">135</context></context-group>
</trans-unit>
- <trans-unit id="_msg430">
+ <trans-unit id="_msg447">
<source xml:space="preserve">Save Transaction Data</source>
<context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg431">
+ <trans-unit id="_msg448">
<source xml:space="preserve">Partially Signed Transaction (Binary)</source>
<context-group purpose="location"><context context-type="linenumber">160</context></context-group>
<note annotates="source" from="developer">Expanded name of the binary PSBT file format. See: BIP 174.</note>
</trans-unit>
- <trans-unit id="_msg432">
+ <trans-unit id="_msg449">
<source xml:space="preserve">PSBT saved to disk.</source>
<context-group purpose="location"><context context-type="linenumber">167</context></context-group>
</trans-unit>
- <trans-unit id="_msg433">
+ <trans-unit id="_msg450">
<source xml:space="preserve"> * Sends %1 to %2</source>
<context-group purpose="location"><context context-type="linenumber">183</context></context-group>
</trans-unit>
- <trans-unit id="_msg434">
+ <trans-unit id="_msg451">
<source xml:space="preserve">Unable to calculate transaction fee or total transaction amount.</source>
<context-group purpose="location"><context context-type="linenumber">193</context></context-group>
</trans-unit>
- <trans-unit id="_msg435">
+ <trans-unit id="_msg452">
<source xml:space="preserve">Pays transaction fee: </source>
<context-group purpose="location"><context context-type="linenumber">195</context></context-group>
</trans-unit>
- <trans-unit id="_msg436">
+ <trans-unit id="_msg453">
<source xml:space="preserve">Total Amount</source>
<context-group purpose="location"><context context-type="linenumber">207</context></context-group>
</trans-unit>
- <trans-unit id="_msg437">
+ <trans-unit id="_msg454">
<source xml:space="preserve">or</source>
<context-group purpose="location"><context context-type="linenumber">210</context></context-group>
</trans-unit>
- <trans-unit id="_msg438">
+ <trans-unit id="_msg455">
<source xml:space="preserve">Transaction has %1 unsigned inputs.</source>
<context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg439">
+ <trans-unit id="_msg456">
<source xml:space="preserve">Transaction is missing some information about inputs.</source>
<context-group purpose="location"><context context-type="linenumber">262</context></context-group>
</trans-unit>
- <trans-unit id="_msg440">
+ <trans-unit id="_msg457">
<source xml:space="preserve">Transaction still needs signature(s).</source>
<context-group purpose="location"><context context-type="linenumber">266</context></context-group>
</trans-unit>
- <trans-unit id="_msg441">
+ <trans-unit id="_msg458">
<source xml:space="preserve">(But no wallet is loaded.)</source>
<context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg442">
+ <trans-unit id="_msg459">
<source xml:space="preserve">(But this wallet cannot sign transactions.)</source>
<context-group purpose="location"><context context-type="linenumber">272</context></context-group>
</trans-unit>
- <trans-unit id="_msg443">
+ <trans-unit id="_msg460">
<source xml:space="preserve">(But this wallet does not have the right keys.)</source>
<context-group purpose="location"><context context-type="linenumber">275</context></context-group>
</trans-unit>
- <trans-unit id="_msg444">
+ <trans-unit id="_msg461">
<source xml:space="preserve">Transaction is fully signed and ready for broadcast.</source>
<context-group purpose="location"><context context-type="linenumber">283</context></context-group>
</trans-unit>
- <trans-unit id="_msg445">
+ <trans-unit id="_msg462">
<source xml:space="preserve">Transaction status is unknown.</source>
<context-group purpose="location"><context context-type="linenumber">287</context></context-group>
</trans-unit>
@@ -1983,295 +2087,308 @@ Signing is only possible with addresses of the type &apos;legacy&apos;.</source>
</body></file>
<file original="../paymentserver.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PaymentServer">
- <trans-unit id="_msg446">
+ <trans-unit id="_msg463">
<source xml:space="preserve">Payment request error</source>
- <context-group purpose="location"><context context-type="linenumber">173</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg447">
+ <trans-unit id="_msg464">
<source xml:space="preserve">Cannot start bitcoin: click-to-pay handler</source>
- <context-group purpose="location"><context context-type="linenumber">174</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">153</context></context-group>
</trans-unit>
- <trans-unit id="_msg448">
+ <trans-unit id="_msg465">
<source xml:space="preserve">URI handling</source>
- <context-group purpose="location"><context context-type="linenumber">224</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">246</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">201</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">217</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">223</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">230</context></context-group>
</trans-unit>
- <trans-unit id="_msg449">
+ <trans-unit id="_msg466">
<source xml:space="preserve">&apos;bitcoin://&apos; is not a valid URI. Use &apos;bitcoin:&apos; instead.</source>
- <context-group purpose="location"><context context-type="linenumber">224</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">201</context></context-group>
</trans-unit>
- <trans-unit id="_msg450">
+ <trans-unit id="_msg467">
<source xml:space="preserve">Cannot process payment request because BIP70 is not supported.
Due to widespread security flaws in BIP70 it&apos;s strongly recommended that any merchant instructions to switch wallets be ignored.
If you are receiving this error you should request the merchant provide a BIP21 compatible URI.</source>
+ <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">264</context></context-group>
</trans-unit>
- <trans-unit id="_msg451">
+ <trans-unit id="_msg468">
<source xml:space="preserve">URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
- <context-group purpose="location"><context context-type="linenumber">254</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">231</context></context-group>
</trans-unit>
- <trans-unit id="_msg452">
+ <trans-unit id="_msg469">
<source xml:space="preserve">Payment request file handling</source>
- <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../peertablemodel.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PeerTableModel">
- <trans-unit id="_msg453">
+ <trans-unit id="_msg470">
<source xml:space="preserve">User Agent</source>
- <context-group purpose="location"><context context-type="linenumber">108</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">112</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains the peer&apos;s User Agent string.</note>
</trans-unit>
- <trans-unit id="_msg454">
+ <trans-unit id="_msg471">
<source xml:space="preserve">Ping</source>
- <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">103</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the current latency of the connection with the peer.</note>
</trans-unit>
- <trans-unit id="_msg455">
+ <trans-unit id="_msg472">
<source xml:space="preserve">Peer</source>
- <context-group purpose="location"><context context-type="linenumber">84</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">85</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains a unique number used to identify a connection.</note>
</trans-unit>
- <trans-unit id="_msg456">
+ <trans-unit id="_msg473">
+ <source xml:space="preserve">Age</source>
+ <context-group purpose="location"><context context-type="linenumber">88</context></context-group>
+ <note annotates="source" from="developer">Title of Peers Table column which indicates the duration (length of time) since the peer connection started.</note>
+ </trans-unit>
+ <trans-unit id="_msg474">
<source xml:space="preserve">Direction</source>
- <context-group purpose="location"><context context-type="linenumber">90</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">94</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the direction the peer connection was initiated from.</note>
</trans-unit>
- <trans-unit id="_msg457">
+ <trans-unit id="_msg475">
<source xml:space="preserve">Sent</source>
- <context-group purpose="location"><context context-type="linenumber">102</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">106</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</note>
</trans-unit>
- <trans-unit id="_msg458">
+ <trans-unit id="_msg476">
<source xml:space="preserve">Received</source>
- <context-group purpose="location"><context context-type="linenumber">105</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">109</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which indicates the total amount of network information we have received from the peer.</note>
</trans-unit>
- <trans-unit id="_msg459">
+ <trans-unit id="_msg477">
<source xml:space="preserve">Address</source>
- <context-group purpose="location"><context context-type="linenumber">87</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">91</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</note>
</trans-unit>
- <trans-unit id="_msg460">
+ <trans-unit id="_msg478">
<source xml:space="preserve">Type</source>
- <context-group purpose="location"><context context-type="linenumber">93</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">97</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which describes the type of peer connection. The &quot;type&quot; describes why the connection exists.</note>
</trans-unit>
- <trans-unit id="_msg461">
+ <trans-unit id="_msg479">
<source xml:space="preserve">Network</source>
- <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">100</context></context-group>
<note annotates="source" from="developer">Title of Peers Table column which states the network the peer connected through.</note>
</trans-unit>
</group>
</body></file>
<file original="../peertablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="PeerTableModel">
- <trans-unit id="_msg462">
+ <trans-unit id="_msg480">
<source xml:space="preserve">Inbound</source>
- <context-group purpose="location"><context context-type="linenumber">79</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">78</context></context-group>
<note annotates="source" from="developer">An Inbound Connection from a Peer.</note>
</trans-unit>
- <trans-unit id="_msg463">
+ <trans-unit id="_msg481">
<source xml:space="preserve">Outbound</source>
- <context-group purpose="location"><context context-type="linenumber">81</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">80</context></context-group>
<note annotates="source" from="developer">An Outbound Connection to a Peer.</note>
</trans-unit>
</group>
</body></file>
<file original="../bitcoinunits.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg464">
+ <trans-unit id="_msg482">
<source xml:space="preserve">Amount</source>
- <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">197</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../guiutil.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QObject">
- <trans-unit id="_msg465">
+ <trans-unit id="_msg483">
<source xml:space="preserve">Enter a Bitcoin address (e.g. %1)</source>
- <context-group purpose="location"><context context-type="linenumber">127</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">129</context></context-group>
</trans-unit>
- <trans-unit id="_msg466">
+ <trans-unit id="_msg484">
+ <source xml:space="preserve">Ctrl+W</source>
+ <context-group purpose="location"><context context-type="linenumber">417</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg485">
<source xml:space="preserve">Unroutable</source>
<context-group purpose="location"><context context-type="linenumber">673</context></context-group>
</trans-unit>
- <trans-unit id="_msg467">
+ <trans-unit id="_msg486">
<source xml:space="preserve">Internal</source>
<context-group purpose="location"><context context-type="linenumber">679</context></context-group>
</trans-unit>
- <trans-unit id="_msg468">
+ <trans-unit id="_msg487">
<source xml:space="preserve">Inbound</source>
<context-group purpose="location"><context context-type="linenumber">692</context></context-group>
<note annotates="source" from="developer">An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</note>
</trans-unit>
- <trans-unit id="_msg469">
+ <trans-unit id="_msg488">
<source xml:space="preserve">Outbound</source>
<context-group purpose="location"><context context-type="linenumber">695</context></context-group>
<note annotates="source" from="developer">An outbound connection to a peer. An outbound connection is a connection initiated by us.</note>
</trans-unit>
- <trans-unit id="_msg470">
+ <trans-unit id="_msg489">
<source xml:space="preserve">Full Relay</source>
<context-group purpose="location"><context context-type="linenumber">700</context></context-group>
<note annotates="source" from="developer">Peer connection type that relays all network information.</note>
</trans-unit>
- <trans-unit id="_msg471">
+ <trans-unit id="_msg490">
<source xml:space="preserve">Block Relay</source>
<context-group purpose="location"><context context-type="linenumber">703</context></context-group>
<note annotates="source" from="developer">Peer connection type that relays network information about blocks and not transactions or addresses.</note>
</trans-unit>
- <trans-unit id="_msg472">
+ <trans-unit id="_msg491">
<source xml:space="preserve">Manual</source>
<context-group purpose="location"><context context-type="linenumber">705</context></context-group>
<note annotates="source" from="developer">Peer connection type established manually through one of several methods.</note>
</trans-unit>
- <trans-unit id="_msg473">
+ <trans-unit id="_msg492">
<source xml:space="preserve">Feeler</source>
<context-group purpose="location"><context context-type="linenumber">707</context></context-group>
<note annotates="source" from="developer">Short-lived peer connection type that tests the aliveness of known addresses.</note>
</trans-unit>
- <trans-unit id="_msg474">
+ <trans-unit id="_msg493">
<source xml:space="preserve">Address Fetch</source>
<context-group purpose="location"><context context-type="linenumber">709</context></context-group>
<note annotates="source" from="developer">Short-lived peer connection type that solicits known addresses from a peer.</note>
</trans-unit>
- <trans-unit id="_msg475">
+ <trans-unit id="_msg494">
<source xml:space="preserve">%1 d</source>
- <context-group purpose="location"><context context-type="linenumber">724</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">722</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">734</context></context-group>
</trans-unit>
- <trans-unit id="_msg476">
+ <trans-unit id="_msg495">
<source xml:space="preserve">%1 h</source>
- <context-group purpose="location"><context context-type="linenumber">726</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">723</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">735</context></context-group>
</trans-unit>
- <trans-unit id="_msg477">
+ <trans-unit id="_msg496">
<source xml:space="preserve">%1 m</source>
- <context-group purpose="location"><context context-type="linenumber">728</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">724</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">736</context></context-group>
</trans-unit>
- <trans-unit id="_msg478">
+ <trans-unit id="_msg497">
<source xml:space="preserve">%1 s</source>
- <context-group purpose="location"><context context-type="linenumber">730</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">758</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">726</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">737</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">763</context></context-group>
</trans-unit>
- <trans-unit id="_msg479">
+ <trans-unit id="_msg498">
<source xml:space="preserve">None</source>
- <context-group purpose="location"><context context-type="linenumber">746</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">751</context></context-group>
</trans-unit>
- <trans-unit id="_msg480">
+ <trans-unit id="_msg499">
<source xml:space="preserve">N/A</source>
- <context-group purpose="location"><context context-type="linenumber">752</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">757</context></context-group>
</trans-unit>
- <trans-unit id="_msg481">
+ <trans-unit id="_msg500">
<source xml:space="preserve">%1 ms</source>
- <context-group purpose="location"><context context-type="linenumber">753</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">758</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">771</context></context-group>
- <trans-unit id="_msg482[0]">
+ <context-group purpose="location"><context context-type="linenumber">776</context></context-group>
+ <trans-unit id="_msg501[0]">
<source xml:space="preserve">%n second(s)</source>
</trans-unit>
- <trans-unit id="_msg482[1]">
+ <trans-unit id="_msg501[1]">
<source xml:space="preserve">%n second(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">775</context></context-group>
- <trans-unit id="_msg483[0]">
+ <context-group purpose="location"><context context-type="linenumber">780</context></context-group>
+ <trans-unit id="_msg502[0]">
<source xml:space="preserve">%n minute(s)</source>
</trans-unit>
- <trans-unit id="_msg483[1]">
+ <trans-unit id="_msg502[1]">
<source xml:space="preserve">%n minute(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">779</context></context-group>
- <trans-unit id="_msg484[0]">
+ <context-group purpose="location"><context context-type="linenumber">784</context></context-group>
+ <trans-unit id="_msg503[0]">
<source xml:space="preserve">%n hour(s)</source>
</trans-unit>
- <trans-unit id="_msg484[1]">
+ <trans-unit id="_msg503[1]">
<source xml:space="preserve">%n hour(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">783</context></context-group>
- <trans-unit id="_msg485[0]">
+ <context-group purpose="location"><context context-type="linenumber">788</context></context-group>
+ <trans-unit id="_msg504[0]">
<source xml:space="preserve">%n day(s)</source>
</trans-unit>
- <trans-unit id="_msg485[1]">
+ <trans-unit id="_msg504[1]">
<source xml:space="preserve">%n day(s)</source>
</trans-unit>
</group>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">787</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">793</context></context-group>
- <trans-unit id="_msg486[0]">
+ <context-group purpose="location"><context context-type="linenumber">792</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">798</context></context-group>
+ <trans-unit id="_msg505[0]">
<source xml:space="preserve">%n week(s)</source>
</trans-unit>
- <trans-unit id="_msg486[1]">
+ <trans-unit id="_msg505[1]">
<source xml:space="preserve">%n week(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg487">
+ <trans-unit id="_msg506">
<source xml:space="preserve">%1 and %2</source>
- <context-group purpose="location"><context context-type="linenumber">793</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">798</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">793</context></context-group>
- <trans-unit id="_msg488[0]">
+ <context-group purpose="location"><context context-type="linenumber">798</context></context-group>
+ <trans-unit id="_msg507[0]">
<source xml:space="preserve">%n year(s)</source>
</trans-unit>
- <trans-unit id="_msg488[1]">
+ <trans-unit id="_msg507[1]">
<source xml:space="preserve">%n year(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg489">
+ <trans-unit id="_msg508">
<source xml:space="preserve">%1 B</source>
- <context-group purpose="location"><context context-type="linenumber">801</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">806</context></context-group>
</trans-unit>
- <trans-unit id="_msg490">
+ <trans-unit id="_msg509">
<source xml:space="preserve">%1 kB</source>
- <context-group purpose="location"><context context-type="linenumber">803</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">808</context></context-group>
</trans-unit>
- <trans-unit id="_msg491">
+ <trans-unit id="_msg510">
<source xml:space="preserve">%1 MB</source>
- <context-group purpose="location"><context context-type="linenumber">805</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">810</context></context-group>
</trans-unit>
- <trans-unit id="_msg492">
+ <trans-unit id="_msg511">
<source xml:space="preserve">%1 GB</source>
- <context-group purpose="location"><context context-type="linenumber">807</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">812</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../qrimagewidget.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="QRImageWidget">
- <trans-unit id="_msg493">
+ <trans-unit id="_msg512">
<source xml:space="preserve">&amp;Save Image…</source>
<context-group purpose="location"><context context-type="linenumber">30</context></context-group>
</trans-unit>
- <trans-unit id="_msg494">
+ <trans-unit id="_msg513">
<source xml:space="preserve">&amp;Copy Image</source>
<context-group purpose="location"><context context-type="linenumber">31</context></context-group>
</trans-unit>
- <trans-unit id="_msg495">
+ <trans-unit id="_msg514">
<source xml:space="preserve">Resulting URI too long, try to reduce the text for label / message.</source>
<context-group purpose="location"><context context-type="linenumber">42</context></context-group>
</trans-unit>
- <trans-unit id="_msg496">
+ <trans-unit id="_msg515">
<source xml:space="preserve">Error encoding URI into QR Code.</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg497">
+ <trans-unit id="_msg516">
<source xml:space="preserve">QR code support not available.</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg498">
+ <trans-unit id="_msg517">
<source xml:space="preserve">Save QR Code</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg499">
+ <trans-unit id="_msg518">
<source xml:space="preserve">PNG Image</source>
<context-group purpose="location"><context context-type="linenumber">123</context></context-group>
<note annotates="source" from="developer">Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</note>
@@ -2280,7 +2397,7 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../forms/debugwindow.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg500">
+ <trans-unit id="_msg519">
<source xml:space="preserve">N/A</source>
<context-group purpose="location"><context context-type="linenumber">75</context></context-group>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
@@ -2319,290 +2436,293 @@ If you are receiving this error you should request the merchant provide a BIP21
<context-group purpose="location"><context context-type="linenumber">1610</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1636</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1662</context></context-group>
- <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.h</context><context context-type="linenumber">139</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.h</context><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg501">
+ <trans-unit id="_msg520">
<source xml:space="preserve">Client version</source>
<context-group purpose="location"><context context-type="linenumber">65</context></context-group>
</trans-unit>
- <trans-unit id="_msg502">
+ <trans-unit id="_msg521">
<source xml:space="preserve">&amp;Information</source>
<context-group purpose="location"><context context-type="linenumber">43</context></context-group>
</trans-unit>
- <trans-unit id="_msg503">
+ <trans-unit id="_msg522">
<source xml:space="preserve">General</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
</trans-unit>
- <trans-unit id="_msg504">
+ <trans-unit id="_msg523">
<source xml:space="preserve">Datadir</source>
<context-group purpose="location"><context context-type="linenumber">114</context></context-group>
</trans-unit>
- <trans-unit id="_msg505">
+ <trans-unit id="_msg524">
<source xml:space="preserve">To specify a non-default location of the data directory use the &apos;%1&apos; option.</source>
<context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
- <trans-unit id="_msg506">
+ <trans-unit id="_msg525">
<source xml:space="preserve">Blocksdir</source>
<context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg507">
+ <trans-unit id="_msg526">
<source xml:space="preserve">To specify a non-default location of the blocks directory use the &apos;%1&apos; option.</source>
<context-group purpose="location"><context context-type="linenumber">153</context></context-group>
</trans-unit>
- <trans-unit id="_msg508">
+ <trans-unit id="_msg527">
<source xml:space="preserve">Startup time</source>
<context-group purpose="location"><context context-type="linenumber">172</context></context-group>
</trans-unit>
- <trans-unit id="_msg509">
+ <trans-unit id="_msg528">
<source xml:space="preserve">Network</source>
<context-group purpose="location"><context context-type="linenumber">201</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1093</context></context-group>
</trans-unit>
- <trans-unit id="_msg510">
+ <trans-unit id="_msg529">
<source xml:space="preserve">Name</source>
<context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg511">
+ <trans-unit id="_msg530">
<source xml:space="preserve">Number of connections</source>
<context-group purpose="location"><context context-type="linenumber">231</context></context-group>
</trans-unit>
- <trans-unit id="_msg512">
+ <trans-unit id="_msg531">
<source xml:space="preserve">Block chain</source>
<context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg513">
+ <trans-unit id="_msg532">
<source xml:space="preserve">Memory Pool</source>
<context-group purpose="location"><context context-type="linenumber">319</context></context-group>
</trans-unit>
- <trans-unit id="_msg514">
+ <trans-unit id="_msg533">
<source xml:space="preserve">Current number of transactions</source>
<context-group purpose="location"><context context-type="linenumber">326</context></context-group>
</trans-unit>
- <trans-unit id="_msg515">
+ <trans-unit id="_msg534">
<source xml:space="preserve">Memory usage</source>
<context-group purpose="location"><context context-type="linenumber">349</context></context-group>
</trans-unit>
- <trans-unit id="_msg516">
+ <trans-unit id="_msg535">
<source xml:space="preserve">Wallet: </source>
<context-group purpose="location"><context context-type="linenumber">443</context></context-group>
</trans-unit>
- <trans-unit id="_msg517">
+ <trans-unit id="_msg536">
<source xml:space="preserve">(none)</source>
<context-group purpose="location"><context context-type="linenumber">454</context></context-group>
</trans-unit>
- <trans-unit id="_msg518">
+ <trans-unit id="_msg537">
<source xml:space="preserve">&amp;Reset</source>
<context-group purpose="location"><context context-type="linenumber">665</context></context-group>
</trans-unit>
- <trans-unit id="_msg519">
+ <trans-unit id="_msg538">
<source xml:space="preserve">Received</source>
<context-group purpose="location"><context context-type="linenumber">745</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1453</context></context-group>
</trans-unit>
- <trans-unit id="_msg520">
+ <trans-unit id="_msg539">
<source xml:space="preserve">Sent</source>
<context-group purpose="location"><context context-type="linenumber">825</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1430</context></context-group>
</trans-unit>
- <trans-unit id="_msg521">
+ <trans-unit id="_msg540">
<source xml:space="preserve">&amp;Peers</source>
<context-group purpose="location"><context context-type="linenumber">866</context></context-group>
</trans-unit>
- <trans-unit id="_msg522">
+ <trans-unit id="_msg541">
<source xml:space="preserve">Banned peers</source>
<context-group purpose="location"><context context-type="linenumber">942</context></context-group>
</trans-unit>
- <trans-unit id="_msg523">
+ <trans-unit id="_msg542">
<source xml:space="preserve">Select a peer to view detailed information.</source>
<context-group purpose="location"><context context-type="linenumber">1010</context></context-group>
- <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1160</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1155</context></context-group>
</trans-unit>
- <trans-unit id="_msg524">
+ <trans-unit id="_msg543">
<source xml:space="preserve">Version</source>
<context-group purpose="location"><context context-type="linenumber">1116</context></context-group>
</trans-unit>
- <trans-unit id="_msg525">
+ <trans-unit id="_msg544">
<source xml:space="preserve">Starting Block</source>
<context-group purpose="location"><context context-type="linenumber">1240</context></context-group>
</trans-unit>
- <trans-unit id="_msg526">
+ <trans-unit id="_msg545">
<source xml:space="preserve">Synced Headers</source>
<context-group purpose="location"><context context-type="linenumber">1263</context></context-group>
</trans-unit>
- <trans-unit id="_msg527">
+ <trans-unit id="_msg546">
<source xml:space="preserve">Synced Blocks</source>
<context-group purpose="location"><context context-type="linenumber">1286</context></context-group>
</trans-unit>
- <trans-unit id="_msg528">
+ <trans-unit id="_msg547">
<source xml:space="preserve">Last Transaction</source>
<context-group purpose="location"><context context-type="linenumber">1361</context></context-group>
</trans-unit>
- <trans-unit id="_msg529">
+ <trans-unit id="_msg548">
<source xml:space="preserve">The mapped Autonomous System used for diversifying peer selection.</source>
<context-group purpose="location"><context context-type="linenumber">1571</context></context-group>
</trans-unit>
- <trans-unit id="_msg530">
+ <trans-unit id="_msg549">
<source xml:space="preserve">Mapped AS</source>
<context-group purpose="location"><context context-type="linenumber">1574</context></context-group>
</trans-unit>
- <trans-unit id="_msg531">
+ <trans-unit id="_msg550">
<source xml:space="preserve">Whether we relay addresses to this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1597</context></context-group>
- <note annotates="source" from="developer">Tooltip text for the Address Relay field in the peer details area.</note>
+ <note annotates="source" from="developer">Tooltip text for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</note>
</trans-unit>
- <trans-unit id="_msg532">
+ <trans-unit id="_msg551">
<source xml:space="preserve">Address Relay</source>
<context-group purpose="location"><context context-type="linenumber">1600</context></context-group>
+ <note annotates="source" from="developer">Text title for the Address Relay field in the peer details area, which displays whether we relay addresses to this peer (Yes/No).</note>
</trans-unit>
- <trans-unit id="_msg533">
- <source xml:space="preserve">Total number of addresses processed, excluding those dropped due to rate-limiting.</source>
+ <trans-unit id="_msg552">
+ <source xml:space="preserve">The total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</source>
<context-group purpose="location"><context context-type="linenumber">1623</context></context-group>
- <note annotates="source" from="developer">Tooltip text for the Addresses Processed field in the peer details area.</note>
+ <note annotates="source" from="developer">Tooltip text for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</note>
</trans-unit>
- <trans-unit id="_msg534">
+ <trans-unit id="_msg553">
+ <source xml:space="preserve">The total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</source>
+ <context-group purpose="location"><context context-type="linenumber">1649</context></context-group>
+ <note annotates="source" from="developer">Tooltip text for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</note>
+ </trans-unit>
+ <trans-unit id="_msg554">
<source xml:space="preserve">Addresses Processed</source>
<context-group purpose="location"><context context-type="linenumber">1626</context></context-group>
+ <note annotates="source" from="developer">Text title for the Addresses Processed field in the peer details area, which displays the total number of addresses received from this peer that were processed (excludes addresses that were dropped due to rate-limiting).</note>
</trans-unit>
- <trans-unit id="_msg535">
- <source xml:space="preserve">Total number of addresses dropped due to rate-limiting.</source>
- <context-group purpose="location"><context context-type="linenumber">1649</context></context-group>
- <note annotates="source" from="developer">Tooltip text for the Addresses Rate-Limited field in the peer details area.</note>
- </trans-unit>
- <trans-unit id="_msg536">
+ <trans-unit id="_msg555">
<source xml:space="preserve">Addresses Rate-Limited</source>
<context-group purpose="location"><context context-type="linenumber">1652</context></context-group>
+ <note annotates="source" from="developer">Text title for the Addresses Rate-Limited field in the peer details area, which displays the total number of addresses received from this peer that were dropped (not processed) due to rate-limiting.</note>
</trans-unit>
- <trans-unit id="_msg537">
+ <trans-unit id="_msg556">
<source xml:space="preserve">User Agent</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
<context-group purpose="location"><context context-type="linenumber">1139</context></context-group>
</trans-unit>
- <trans-unit id="_msg538">
+ <trans-unit id="_msg557">
<source xml:space="preserve">Node window</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg539">
+ <trans-unit id="_msg558">
<source xml:space="preserve">Current block height</source>
<context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg540">
+ <trans-unit id="_msg559">
<source xml:space="preserve">Open the %1 debug log file from the current data directory. This can take a few seconds for large log files.</source>
<context-group purpose="location"><context context-type="linenumber">397</context></context-group>
</trans-unit>
- <trans-unit id="_msg541">
+ <trans-unit id="_msg560">
<source xml:space="preserve">Decrease font size</source>
<context-group purpose="location"><context context-type="linenumber">475</context></context-group>
</trans-unit>
- <trans-unit id="_msg542">
+ <trans-unit id="_msg561">
<source xml:space="preserve">Increase font size</source>
<context-group purpose="location"><context context-type="linenumber">495</context></context-group>
</trans-unit>
- <trans-unit id="_msg543">
+ <trans-unit id="_msg562">
<source xml:space="preserve">Permissions</source>
<context-group purpose="location"><context context-type="linenumber">1041</context></context-group>
</trans-unit>
- <trans-unit id="_msg544">
+ <trans-unit id="_msg563">
<source xml:space="preserve">The direction and type of peer connection: %1</source>
<context-group purpose="location"><context context-type="linenumber">1064</context></context-group>
</trans-unit>
- <trans-unit id="_msg545">
+ <trans-unit id="_msg564">
<source xml:space="preserve">Direction/Type</source>
<context-group purpose="location"><context context-type="linenumber">1067</context></context-group>
</trans-unit>
- <trans-unit id="_msg546">
+ <trans-unit id="_msg565">
<source xml:space="preserve">The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source>
<context-group purpose="location"><context context-type="linenumber">1090</context></context-group>
</trans-unit>
- <trans-unit id="_msg547">
+ <trans-unit id="_msg566">
<source xml:space="preserve">Services</source>
<context-group purpose="location"><context context-type="linenumber">1162</context></context-group>
</trans-unit>
- <trans-unit id="_msg548">
+ <trans-unit id="_msg567">
<source xml:space="preserve">Whether the peer requested us to relay transactions.</source>
<context-group purpose="location"><context context-type="linenumber">1188</context></context-group>
</trans-unit>
- <trans-unit id="_msg549">
+ <trans-unit id="_msg568">
<source xml:space="preserve">Wants Tx Relay</source>
<context-group purpose="location"><context context-type="linenumber">1191</context></context-group>
</trans-unit>
- <trans-unit id="_msg550">
+ <trans-unit id="_msg569">
<source xml:space="preserve">High bandwidth BIP152 compact block relay: %1</source>
<context-group purpose="location"><context context-type="linenumber">1214</context></context-group>
</trans-unit>
- <trans-unit id="_msg551">
+ <trans-unit id="_msg570">
<source xml:space="preserve">High Bandwidth</source>
<context-group purpose="location"><context context-type="linenumber">1217</context></context-group>
</trans-unit>
- <trans-unit id="_msg552">
+ <trans-unit id="_msg571">
<source xml:space="preserve">Connection Time</source>
<context-group purpose="location"><context context-type="linenumber">1309</context></context-group>
</trans-unit>
- <trans-unit id="_msg553">
+ <trans-unit id="_msg572">
<source xml:space="preserve">Elapsed time since a novel block passing initial validity checks was received from this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1332</context></context-group>
</trans-unit>
- <trans-unit id="_msg554">
+ <trans-unit id="_msg573">
<source xml:space="preserve">Last Block</source>
<context-group purpose="location"><context context-type="linenumber">1335</context></context-group>
</trans-unit>
- <trans-unit id="_msg555">
+ <trans-unit id="_msg574">
<source xml:space="preserve">Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source>
<context-group purpose="location"><context context-type="linenumber">1358</context></context-group>
<note annotates="source" from="developer">Tooltip text for the Last Transaction field in the peer details area.</note>
</trans-unit>
- <trans-unit id="_msg556">
+ <trans-unit id="_msg575">
<source xml:space="preserve">Last Send</source>
<context-group purpose="location"><context context-type="linenumber">1384</context></context-group>
</trans-unit>
- <trans-unit id="_msg557">
+ <trans-unit id="_msg576">
<source xml:space="preserve">Last Receive</source>
<context-group purpose="location"><context context-type="linenumber">1407</context></context-group>
</trans-unit>
- <trans-unit id="_msg558">
+ <trans-unit id="_msg577">
<source xml:space="preserve">Ping Time</source>
<context-group purpose="location"><context context-type="linenumber">1476</context></context-group>
</trans-unit>
- <trans-unit id="_msg559">
+ <trans-unit id="_msg578">
<source xml:space="preserve">The duration of a currently outstanding ping.</source>
<context-group purpose="location"><context context-type="linenumber">1499</context></context-group>
</trans-unit>
- <trans-unit id="_msg560">
+ <trans-unit id="_msg579">
<source xml:space="preserve">Ping Wait</source>
<context-group purpose="location"><context context-type="linenumber">1502</context></context-group>
</trans-unit>
- <trans-unit id="_msg561">
+ <trans-unit id="_msg580">
<source xml:space="preserve">Min Ping</source>
<context-group purpose="location"><context context-type="linenumber">1525</context></context-group>
</trans-unit>
- <trans-unit id="_msg562">
+ <trans-unit id="_msg581">
<source xml:space="preserve">Time Offset</source>
<context-group purpose="location"><context context-type="linenumber">1548</context></context-group>
</trans-unit>
- <trans-unit id="_msg563">
+ <trans-unit id="_msg582">
<source xml:space="preserve">Last block time</source>
<context-group purpose="location"><context context-type="linenumber">290</context></context-group>
</trans-unit>
- <trans-unit id="_msg564">
+ <trans-unit id="_msg583">
<source xml:space="preserve">&amp;Open</source>
<context-group purpose="location"><context context-type="linenumber">400</context></context-group>
</trans-unit>
- <trans-unit id="_msg565">
+ <trans-unit id="_msg584">
<source xml:space="preserve">&amp;Console</source>
<context-group purpose="location"><context context-type="linenumber">426</context></context-group>
</trans-unit>
- <trans-unit id="_msg566">
+ <trans-unit id="_msg585">
<source xml:space="preserve">&amp;Network Traffic</source>
<context-group purpose="location"><context context-type="linenumber">613</context></context-group>
</trans-unit>
- <trans-unit id="_msg567">
+ <trans-unit id="_msg586">
<source xml:space="preserve">Totals</source>
<context-group purpose="location"><context context-type="linenumber">681</context></context-group>
</trans-unit>
- <trans-unit id="_msg568">
+ <trans-unit id="_msg587">
<source xml:space="preserve">Debug log file</source>
<context-group purpose="location"><context context-type="linenumber">390</context></context-group>
</trans-unit>
- <trans-unit id="_msg569">
+ <trans-unit id="_msg588">
<source xml:space="preserve">Clear console</source>
<context-group purpose="location"><context context-type="linenumber">515</context></context-group>
</trans-unit>
@@ -2610,123 +2730,139 @@ If you are receiving this error you should request the merchant provide a BIP21
</body></file>
<file original="../rpcconsole.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg570">
+ <trans-unit id="_msg589">
<source xml:space="preserve">In:</source>
- <context-group purpose="location"><context context-type="linenumber">959</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">953</context></context-group>
</trans-unit>
- <trans-unit id="_msg571">
+ <trans-unit id="_msg590">
<source xml:space="preserve">Out:</source>
- <context-group purpose="location"><context context-type="linenumber">960</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">954</context></context-group>
</trans-unit>
- <trans-unit id="_msg572">
+ <trans-unit id="_msg591">
<source xml:space="preserve">Inbound: initiated by peer</source>
- <context-group purpose="location"><context context-type="linenumber">503</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">496</context></context-group>
<note annotates="source" from="developer">Explanatory text for an inbound peer connection.</note>
</trans-unit>
- <trans-unit id="_msg573">
+ <trans-unit id="_msg592">
<source xml:space="preserve">Outbound Full Relay: default</source>
- <context-group purpose="location"><context context-type="linenumber">507</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">500</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</note>
</trans-unit>
- <trans-unit id="_msg574">
+ <trans-unit id="_msg593">
<source xml:space="preserve">Outbound Block Relay: does not relay transactions or addresses</source>
- <context-group purpose="location"><context context-type="linenumber">510</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">503</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</note>
</trans-unit>
- <trans-unit id="_msg575">
+ <trans-unit id="_msg594">
<source xml:space="preserve">Outbound Manual: added using RPC %1 or %2/%3 configuration options</source>
- <context-group purpose="location"><context context-type="linenumber">515</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">508</context></context-group>
<note annotates="source" from="developer">Explanatory text for an outbound peer connection that was established manually through one of several methods. The numbered arguments are stand-ins for the methods available to establish manual connections.</note>
</trans-unit>
- <trans-unit id="_msg576">
+ <trans-unit id="_msg595">
<source xml:space="preserve">Outbound Feeler: short-lived, for testing addresses</source>
- <context-group purpose="location"><context context-type="linenumber">521</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">514</context></context-group>
<note annotates="source" from="developer">Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</note>
</trans-unit>
- <trans-unit id="_msg577">
+ <trans-unit id="_msg596">
<source xml:space="preserve">Outbound Address Fetch: short-lived, for soliciting addresses</source>
- <context-group purpose="location"><context context-type="linenumber">524</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">517</context></context-group>
<note annotates="source" from="developer">Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</note>
</trans-unit>
- <trans-unit id="_msg578">
+ <trans-unit id="_msg597">
<source xml:space="preserve">we selected the peer for high bandwidth relay</source>
- <context-group purpose="location"><context context-type="linenumber">528</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg579">
+ <trans-unit id="_msg598">
<source xml:space="preserve">the peer selected us for high bandwidth relay</source>
- <context-group purpose="location"><context context-type="linenumber">529</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">522</context></context-group>
</trans-unit>
- <trans-unit id="_msg580">
+ <trans-unit id="_msg599">
<source xml:space="preserve">no high bandwidth relay selected</source>
- <context-group purpose="location"><context context-type="linenumber">530</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">523</context></context-group>
</trans-unit>
- <trans-unit id="_msg581">
+ <trans-unit id="_msg600">
<source xml:space="preserve">Ctrl++</source>
- <context-group purpose="location"><context context-type="linenumber">543</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">536</context></context-group>
<note annotates="source" from="developer">Main shortcut to increase the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg582">
+ <trans-unit id="_msg601">
<source xml:space="preserve">Ctrl+=</source>
- <context-group purpose="location"><context context-type="linenumber">545</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">538</context></context-group>
<note annotates="source" from="developer">Secondary shortcut to increase the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg583">
+ <trans-unit id="_msg602">
<source xml:space="preserve">Ctrl+-</source>
- <context-group purpose="location"><context context-type="linenumber">549</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">542</context></context-group>
<note annotates="source" from="developer">Main shortcut to decrease the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg584">
+ <trans-unit id="_msg603">
<source xml:space="preserve">Ctrl+_</source>
- <context-group purpose="location"><context context-type="linenumber">551</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">544</context></context-group>
<note annotates="source" from="developer">Secondary shortcut to decrease the RPC console font size.</note>
</trans-unit>
- <trans-unit id="_msg585">
+ <trans-unit id="_msg604">
<source xml:space="preserve">&amp;Copy address</source>
- <context-group purpose="location"><context context-type="linenumber">702</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">695</context></context-group>
<note annotates="source" from="developer">Context menu action to copy the address of a peer.</note>
</trans-unit>
- <trans-unit id="_msg586">
+ <trans-unit id="_msg605">
<source xml:space="preserve">&amp;Disconnect</source>
- <context-group purpose="location"><context context-type="linenumber">706</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">699</context></context-group>
</trans-unit>
- <trans-unit id="_msg587">
+ <trans-unit id="_msg606">
<source xml:space="preserve">1 &amp;hour</source>
- <context-group purpose="location"><context context-type="linenumber">707</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">700</context></context-group>
</trans-unit>
- <trans-unit id="_msg588">
+ <trans-unit id="_msg607">
<source xml:space="preserve">1 d&amp;ay</source>
- <context-group purpose="location"><context context-type="linenumber">708</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">701</context></context-group>
</trans-unit>
- <trans-unit id="_msg589">
+ <trans-unit id="_msg608">
<source xml:space="preserve">1 &amp;week</source>
- <context-group purpose="location"><context context-type="linenumber">709</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">702</context></context-group>
</trans-unit>
- <trans-unit id="_msg590">
+ <trans-unit id="_msg609">
<source xml:space="preserve">1 &amp;year</source>
- <context-group purpose="location"><context context-type="linenumber">710</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">703</context></context-group>
</trans-unit>
- <trans-unit id="_msg591">
+ <trans-unit id="_msg610">
<source xml:space="preserve">&amp;Copy IP/Netmask</source>
- <context-group purpose="location"><context context-type="linenumber">735</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">729</context></context-group>
<note annotates="source" from="developer">Context menu action to copy the IP/Netmask of a banned peer. IP/Netmask is the combination of a peer&apos;s IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</note>
</trans-unit>
- <trans-unit id="_msg592">
+ <trans-unit id="_msg611">
<source xml:space="preserve">&amp;Unban</source>
- <context-group purpose="location"><context context-type="linenumber">739</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">733</context></context-group>
</trans-unit>
- <trans-unit id="_msg593">
+ <trans-unit id="_msg612">
<source xml:space="preserve">Network activity disabled</source>
- <context-group purpose="location"><context context-type="linenumber">963</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">957</context></context-group>
</trans-unit>
- <trans-unit id="_msg594">
+ <trans-unit id="_msg613">
<source xml:space="preserve">Executing command without any wallet</source>
- <context-group purpose="location"><context context-type="linenumber">1040</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1035</context></context-group>
</trans-unit>
- <trans-unit id="_msg595">
+ <trans-unit id="_msg614">
+ <source xml:space="preserve">Ctrl+I</source>
+ <context-group purpose="location"><context context-type="linenumber">1351</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg615">
+ <source xml:space="preserve">Ctrl+T</source>
+ <context-group purpose="location"><context context-type="linenumber">1352</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg616">
+ <source xml:space="preserve">Ctrl+N</source>
+ <context-group purpose="location"><context context-type="linenumber">1353</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg617">
+ <source xml:space="preserve">Ctrl+P</source>
+ <context-group purpose="location"><context context-type="linenumber">1354</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg618">
<source xml:space="preserve">Executing command using &quot;%1&quot; wallet</source>
- <context-group purpose="location"><context context-type="linenumber">1038</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1033</context></context-group>
</trans-unit>
- <trans-unit id="_msg596">
+ <trans-unit id="_msg619">
<source xml:space="preserve">Welcome to the %1 RPC console.
Use up and down arrows to navigate history, and %2 to clear screen.
Use %3 and %4 to increase or decrease the font size.
@@ -2734,124 +2870,124 @@ Type %5 for an overview of available commands.
For more information on using this console, type %6.
%7WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.%8</source>
- <context-group purpose="location"><context context-type="linenumber">893</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">887</context></context-group>
<note annotates="source" from="developer">RPC console welcome message. Placeholders %7 and %8 are style tags for the warning content, and they are not space separated from the rest of the text intentionally.</note>
</trans-unit>
- <trans-unit id="_msg597">
+ <trans-unit id="_msg620">
<source xml:space="preserve">Executing…</source>
- <context-group purpose="location"><context context-type="linenumber">1048</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1043</context></context-group>
<note annotates="source" from="developer">A console message indicating an entered command is currently being executed.</note>
</trans-unit>
- <trans-unit id="_msg598">
+ <trans-unit id="_msg621">
<source xml:space="preserve">(peer: %1)</source>
- <context-group purpose="location"><context context-type="linenumber">1166</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1161</context></context-group>
</trans-unit>
- <trans-unit id="_msg599">
+ <trans-unit id="_msg622">
<source xml:space="preserve">via %1</source>
- <context-group purpose="location"><context context-type="linenumber">1168</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1163</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../rpcconsole.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RPCConsole">
- <trans-unit id="_msg600">
+ <trans-unit id="_msg623">
<source xml:space="preserve">Yes</source>
- <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg601">
+ <trans-unit id="_msg624">
<source xml:space="preserve">No</source>
- <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg602">
+ <trans-unit id="_msg625">
<source xml:space="preserve">To</source>
- <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg603">
+ <trans-unit id="_msg626">
<source xml:space="preserve">From</source>
- <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">142</context></context-group>
</trans-unit>
- <trans-unit id="_msg604">
+ <trans-unit id="_msg627">
<source xml:space="preserve">Ban for</source>
- <context-group purpose="location"><context context-type="linenumber">139</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
- <trans-unit id="_msg605">
+ <trans-unit id="_msg628">
<source xml:space="preserve">Never</source>
- <context-group purpose="location"><context context-type="linenumber">180</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">185</context></context-group>
</trans-unit>
- <trans-unit id="_msg606">
+ <trans-unit id="_msg629">
<source xml:space="preserve">Unknown</source>
- <context-group purpose="location"><context context-type="linenumber">139</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">143</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/receivecoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog">
- <trans-unit id="_msg607">
+ <trans-unit id="_msg630">
<source xml:space="preserve">&amp;Amount:</source>
<context-group purpose="location"><context context-type="linenumber">37</context></context-group>
</trans-unit>
- <trans-unit id="_msg608">
+ <trans-unit id="_msg631">
<source xml:space="preserve">&amp;Label:</source>
<context-group purpose="location"><context context-type="linenumber">83</context></context-group>
</trans-unit>
- <trans-unit id="_msg609">
+ <trans-unit id="_msg632">
<source xml:space="preserve">&amp;Message:</source>
<context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg610">
+ <trans-unit id="_msg633">
<source xml:space="preserve">An optional message to attach to the payment request, which will be displayed when the request is opened. Note: The message will not be sent with the payment over the Bitcoin network.</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg611">
+ <trans-unit id="_msg634">
<source xml:space="preserve">An optional label to associate with the new receiving address.</source>
<context-group purpose="location"><context context-type="linenumber">80</context></context-group>
</trans-unit>
- <trans-unit id="_msg612">
+ <trans-unit id="_msg635">
<source xml:space="preserve">Use this form to request payments. All fields are &lt;b&gt;optional&lt;/b&gt;.</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
</trans-unit>
- <trans-unit id="_msg613">
+ <trans-unit id="_msg636">
<source xml:space="preserve">An optional amount to request. Leave this empty or zero to not request a specific amount.</source>
<context-group purpose="location"><context context-type="linenumber">34</context></context-group>
<context-group purpose="location"><context context-type="linenumber">193</context></context-group>
</trans-unit>
- <trans-unit id="_msg614">
+ <trans-unit id="_msg637">
<source xml:space="preserve">An optional label to associate with the new receiving address (used by you to identify an invoice). It is also attached to the payment request.</source>
<context-group purpose="location"><context context-type="linenumber">66</context></context-group>
</trans-unit>
- <trans-unit id="_msg615">
+ <trans-unit id="_msg638">
<source xml:space="preserve">An optional message that is attached to the payment request and may be displayed to the sender.</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg616">
+ <trans-unit id="_msg639">
<source xml:space="preserve">&amp;Create new receiving address</source>
<context-group purpose="location"><context context-type="linenumber">111</context></context-group>
</trans-unit>
- <trans-unit id="_msg617">
+ <trans-unit id="_msg640">
<source xml:space="preserve">Clear all fields of the form.</source>
<context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg618">
+ <trans-unit id="_msg641">
<source xml:space="preserve">Clear</source>
<context-group purpose="location"><context context-type="linenumber">137</context></context-group>
</trans-unit>
- <trans-unit id="_msg619">
+ <trans-unit id="_msg642">
<source xml:space="preserve">Requested payments history</source>
<context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg620">
+ <trans-unit id="_msg643">
<source xml:space="preserve">Show the selected request (does the same as double clicking an entry)</source>
<context-group purpose="location"><context context-type="linenumber">298</context></context-group>
</trans-unit>
- <trans-unit id="_msg621">
+ <trans-unit id="_msg644">
<source xml:space="preserve">Show</source>
<context-group purpose="location"><context context-type="linenumber">301</context></context-group>
</trans-unit>
- <trans-unit id="_msg622">
+ <trans-unit id="_msg645">
<source xml:space="preserve">Remove the selected entries from the list</source>
<context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg623">
+ <trans-unit id="_msg646">
<source xml:space="preserve">Remove</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
@@ -2859,31 +2995,31 @@ For more information on using this console, type %6.
</body></file>
<file original="../receivecoinsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog">
- <trans-unit id="_msg624">
+ <trans-unit id="_msg647">
<source xml:space="preserve">Copy &amp;URI</source>
<context-group purpose="location"><context context-type="linenumber">47</context></context-group>
</trans-unit>
- <trans-unit id="_msg625">
+ <trans-unit id="_msg648">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">48</context></context-group>
</trans-unit>
- <trans-unit id="_msg626">
+ <trans-unit id="_msg649">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
- <trans-unit id="_msg627">
+ <trans-unit id="_msg650">
<source xml:space="preserve">Copy &amp;message</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg628">
+ <trans-unit id="_msg651">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">51</context></context-group>
</trans-unit>
- <trans-unit id="_msg629">
+ <trans-unit id="_msg652">
<source xml:space="preserve">Could not unlock wallet.</source>
<context-group purpose="location"><context context-type="linenumber">176</context></context-group>
</trans-unit>
- <trans-unit id="_msg630">
+ <trans-unit id="_msg653">
<source xml:space="preserve">Could not generate new %1 address</source>
<context-group purpose="location"><context context-type="linenumber">181</context></context-group>
</trans-unit>
@@ -2891,51 +3027,51 @@ For more information on using this console, type %6.
</body></file>
<file original="../forms/receiverequestdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog">
- <trans-unit id="_msg631">
+ <trans-unit id="_msg654">
<source xml:space="preserve">Request payment to …</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg632">
+ <trans-unit id="_msg655">
<source xml:space="preserve">Address:</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg633">
+ <trans-unit id="_msg656">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">119</context></context-group>
</trans-unit>
- <trans-unit id="_msg634">
+ <trans-unit id="_msg657">
<source xml:space="preserve">Label:</source>
<context-group purpose="location"><context context-type="linenumber">148</context></context-group>
</trans-unit>
- <trans-unit id="_msg635">
+ <trans-unit id="_msg658">
<source xml:space="preserve">Message:</source>
<context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
- <trans-unit id="_msg636">
+ <trans-unit id="_msg659">
<source xml:space="preserve">Wallet:</source>
<context-group purpose="location"><context context-type="linenumber">212</context></context-group>
</trans-unit>
- <trans-unit id="_msg637">
+ <trans-unit id="_msg660">
<source xml:space="preserve">Copy &amp;URI</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg638">
+ <trans-unit id="_msg661">
<source xml:space="preserve">Copy &amp;Address</source>
<context-group purpose="location"><context context-type="linenumber">250</context></context-group>
</trans-unit>
- <trans-unit id="_msg639">
+ <trans-unit id="_msg662">
<source xml:space="preserve">&amp;Verify</source>
<context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg640">
+ <trans-unit id="_msg663">
<source xml:space="preserve">Verify this address on e.g. a hardware wallet screen</source>
<context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg641">
+ <trans-unit id="_msg664">
<source xml:space="preserve">&amp;Save Image…</source>
<context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg642">
+ <trans-unit id="_msg665">
<source xml:space="preserve">Payment information</source>
<context-group purpose="location"><context context-type="linenumber">39</context></context-group>
</trans-unit>
@@ -2943,7 +3079,7 @@ For more information on using this console, type %6.
</body></file>
<file original="../receiverequestdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog">
- <trans-unit id="_msg643">
+ <trans-unit id="_msg666">
<source xml:space="preserve">Request payment to %1</source>
<context-group purpose="location"><context context-type="linenumber">49</context></context-group>
</trans-unit>
@@ -2951,186 +3087,186 @@ For more information on using this console, type %6.
</body></file>
<file original="../recentrequeststablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="RecentRequestsTableModel">
- <trans-unit id="_msg644">
+ <trans-unit id="_msg667">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg645">
+ <trans-unit id="_msg668">
<source xml:space="preserve">Label</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg646">
+ <trans-unit id="_msg669">
<source xml:space="preserve">Message</source>
<context-group purpose="location"><context context-type="linenumber">32</context></context-group>
</trans-unit>
- <trans-unit id="_msg647">
+ <trans-unit id="_msg670">
<source xml:space="preserve">(no label)</source>
- <context-group purpose="location"><context context-type="linenumber">73</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">70</context></context-group>
</trans-unit>
- <trans-unit id="_msg648">
+ <trans-unit id="_msg671">
<source xml:space="preserve">(no message)</source>
- <context-group purpose="location"><context context-type="linenumber">82</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
- <trans-unit id="_msg649">
+ <trans-unit id="_msg672">
<source xml:space="preserve">(no amount requested)</source>
- <context-group purpose="location"><context context-type="linenumber">90</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">87</context></context-group>
</trans-unit>
- <trans-unit id="_msg650">
+ <trans-unit id="_msg673">
<source xml:space="preserve">Requested</source>
- <context-group purpose="location"><context context-type="linenumber">133</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">130</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/sendcoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsDialog">
- <trans-unit id="_msg651">
+ <trans-unit id="_msg674">
<source xml:space="preserve">Send Coins</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
- <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">752</context></context-group>
+ <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">759</context></context-group>
</trans-unit>
- <trans-unit id="_msg652">
+ <trans-unit id="_msg675">
<source xml:space="preserve">Coin Control Features</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg653">
+ <trans-unit id="_msg676">
<source xml:space="preserve">automatically selected</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg654">
+ <trans-unit id="_msg677">
<source xml:space="preserve">Insufficient funds!</source>
<context-group purpose="location"><context context-type="linenumber">139</context></context-group>
</trans-unit>
- <trans-unit id="_msg655">
+ <trans-unit id="_msg678">
<source xml:space="preserve">Quantity:</source>
<context-group purpose="location"><context context-type="linenumber">228</context></context-group>
</trans-unit>
- <trans-unit id="_msg656">
+ <trans-unit id="_msg679">
<source xml:space="preserve">Bytes:</source>
<context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg657">
+ <trans-unit id="_msg680">
<source xml:space="preserve">Amount:</source>
<context-group purpose="location"><context context-type="linenumber">311</context></context-group>
</trans-unit>
- <trans-unit id="_msg658">
+ <trans-unit id="_msg681">
<source xml:space="preserve">Fee:</source>
<context-group purpose="location"><context context-type="linenumber">391</context></context-group>
</trans-unit>
- <trans-unit id="_msg659">
+ <trans-unit id="_msg682">
<source xml:space="preserve">After Fee:</source>
<context-group purpose="location"><context context-type="linenumber">442</context></context-group>
</trans-unit>
- <trans-unit id="_msg660">
+ <trans-unit id="_msg683">
<source xml:space="preserve">Change:</source>
<context-group purpose="location"><context context-type="linenumber">474</context></context-group>
</trans-unit>
- <trans-unit id="_msg661">
+ <trans-unit id="_msg684">
<source xml:space="preserve">If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
<context-group purpose="location"><context context-type="linenumber">518</context></context-group>
</trans-unit>
- <trans-unit id="_msg662">
+ <trans-unit id="_msg685">
<source xml:space="preserve">Custom change address</source>
<context-group purpose="location"><context context-type="linenumber">521</context></context-group>
</trans-unit>
- <trans-unit id="_msg663">
+ <trans-unit id="_msg686">
<source xml:space="preserve">Transaction Fee:</source>
<context-group purpose="location"><context context-type="linenumber">727</context></context-group>
</trans-unit>
- <trans-unit id="_msg664">
+ <trans-unit id="_msg687">
<source xml:space="preserve">Using the fallbackfee can result in sending a transaction that will take several hours or days (or never) to confirm. Consider choosing your fee manually or wait until you have validated the complete chain.</source>
<context-group purpose="location"><context context-type="linenumber">765</context></context-group>
</trans-unit>
- <trans-unit id="_msg665">
+ <trans-unit id="_msg688">
<source xml:space="preserve">Warning: Fee estimation is currently not possible.</source>
<context-group purpose="location"><context context-type="linenumber">774</context></context-group>
</trans-unit>
- <trans-unit id="_msg666">
+ <trans-unit id="_msg689">
<source xml:space="preserve">per kilobyte</source>
<context-group purpose="location"><context context-type="linenumber">856</context></context-group>
</trans-unit>
- <trans-unit id="_msg667">
+ <trans-unit id="_msg690">
<source xml:space="preserve">Hide</source>
<context-group purpose="location"><context context-type="linenumber">803</context></context-group>
</trans-unit>
- <trans-unit id="_msg668">
+ <trans-unit id="_msg691">
<source xml:space="preserve">Recommended:</source>
<context-group purpose="location"><context context-type="linenumber">915</context></context-group>
</trans-unit>
- <trans-unit id="_msg669">
+ <trans-unit id="_msg692">
<source xml:space="preserve">Custom:</source>
<context-group purpose="location"><context context-type="linenumber">945</context></context-group>
</trans-unit>
- <trans-unit id="_msg670">
+ <trans-unit id="_msg693">
<source xml:space="preserve">Send to multiple recipients at once</source>
<context-group purpose="location"><context context-type="linenumber">1160</context></context-group>
</trans-unit>
- <trans-unit id="_msg671">
+ <trans-unit id="_msg694">
<source xml:space="preserve">Add &amp;Recipient</source>
<context-group purpose="location"><context context-type="linenumber">1163</context></context-group>
</trans-unit>
- <trans-unit id="_msg672">
+ <trans-unit id="_msg695">
<source xml:space="preserve">Clear all fields of the form.</source>
<context-group purpose="location"><context context-type="linenumber">1143</context></context-group>
</trans-unit>
- <trans-unit id="_msg673">
+ <trans-unit id="_msg696">
<source xml:space="preserve">Inputs…</source>
<context-group purpose="location"><context context-type="linenumber">110</context></context-group>
</trans-unit>
- <trans-unit id="_msg674">
+ <trans-unit id="_msg697">
<source xml:space="preserve">Dust:</source>
<context-group purpose="location"><context context-type="linenumber">343</context></context-group>
</trans-unit>
- <trans-unit id="_msg675">
+ <trans-unit id="_msg698">
<source xml:space="preserve">Choose…</source>
<context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
- <trans-unit id="_msg676">
+ <trans-unit id="_msg699">
<source xml:space="preserve">Hide transaction fee settings</source>
<context-group purpose="location"><context context-type="linenumber">800</context></context-group>
</trans-unit>
- <trans-unit id="_msg677">
+ <trans-unit id="_msg700">
<source xml:space="preserve">Specify a custom fee per kB (1,000 bytes) of the transaction&apos;s virtual size.
Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100 satoshis per kvB&quot; for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source>
<context-group purpose="location"><context context-type="linenumber">851</context></context-group>
</trans-unit>
- <trans-unit id="_msg678">
+ <trans-unit id="_msg701">
<source xml:space="preserve">When there is less transaction volume than space in the blocks, miners as well as relaying nodes may enforce a minimum fee. Paying only this minimum fee is just fine, but be aware that this can result in a never confirming transaction once there is more demand for bitcoin transactions than the network can process.</source>
<context-group purpose="location"><context context-type="linenumber">886</context></context-group>
</trans-unit>
- <trans-unit id="_msg679">
+ <trans-unit id="_msg702">
<source xml:space="preserve">A too low fee might result in a never confirming transaction (read the tooltip)</source>
<context-group purpose="location"><context context-type="linenumber">889</context></context-group>
</trans-unit>
- <trans-unit id="_msg680">
+ <trans-unit id="_msg703">
<source xml:space="preserve">(Smart fee not initialized yet. This usually takes a few blocks…)</source>
<context-group purpose="location"><context context-type="linenumber">994</context></context-group>
</trans-unit>
- <trans-unit id="_msg681">
+ <trans-unit id="_msg704">
<source xml:space="preserve">Confirmation time target:</source>
<context-group purpose="location"><context context-type="linenumber">1020</context></context-group>
</trans-unit>
- <trans-unit id="_msg682">
+ <trans-unit id="_msg705">
<source xml:space="preserve">Enable Replace-By-Fee</source>
<context-group purpose="location"><context context-type="linenumber">1078</context></context-group>
</trans-unit>
- <trans-unit id="_msg683">
+ <trans-unit id="_msg706">
<source xml:space="preserve">With Replace-By-Fee (BIP-125) you can increase a transaction&apos;s fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source>
<context-group purpose="location"><context context-type="linenumber">1081</context></context-group>
</trans-unit>
- <trans-unit id="_msg684">
+ <trans-unit id="_msg707">
<source xml:space="preserve">Clear &amp;All</source>
<context-group purpose="location"><context context-type="linenumber">1146</context></context-group>
</trans-unit>
- <trans-unit id="_msg685">
+ <trans-unit id="_msg708">
<source xml:space="preserve">Balance:</source>
<context-group purpose="location"><context context-type="linenumber">1201</context></context-group>
</trans-unit>
- <trans-unit id="_msg686">
+ <trans-unit id="_msg709">
<source xml:space="preserve">Confirm the send action</source>
<context-group purpose="location"><context context-type="linenumber">1117</context></context-group>
</trans-unit>
- <trans-unit id="_msg687">
+ <trans-unit id="_msg710">
<source xml:space="preserve">S&amp;end</source>
<context-group purpose="location"><context context-type="linenumber">1120</context></context-group>
</trans-unit>
@@ -3138,422 +3274,396 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../sendcoinsdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsDialog">
- <trans-unit id="_msg688">
+ <trans-unit id="_msg711">
<source xml:space="preserve">Copy quantity</source>
<context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg689">
+ <trans-unit id="_msg712">
<source xml:space="preserve">Copy amount</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
</trans-unit>
- <trans-unit id="_msg690">
+ <trans-unit id="_msg713">
<source xml:space="preserve">Copy fee</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg691">
+ <trans-unit id="_msg714">
<source xml:space="preserve">Copy after fee</source>
<context-group purpose="location"><context context-type="linenumber">102</context></context-group>
</trans-unit>
- <trans-unit id="_msg692">
+ <trans-unit id="_msg715">
<source xml:space="preserve">Copy bytes</source>
<context-group purpose="location"><context context-type="linenumber">103</context></context-group>
</trans-unit>
- <trans-unit id="_msg693">
+ <trans-unit id="_msg716">
<source xml:space="preserve">Copy dust</source>
<context-group purpose="location"><context context-type="linenumber">104</context></context-group>
</trans-unit>
- <trans-unit id="_msg694">
+ <trans-unit id="_msg717">
<source xml:space="preserve">Copy change</source>
<context-group purpose="location"><context context-type="linenumber">105</context></context-group>
</trans-unit>
- <trans-unit id="_msg695">
+ <trans-unit id="_msg718">
<source xml:space="preserve">%1 (%2 blocks)</source>
<context-group purpose="location"><context context-type="linenumber">181</context></context-group>
</trans-unit>
- <trans-unit id="_msg696">
+ <trans-unit id="_msg719">
<source xml:space="preserve">Sign on device</source>
<context-group purpose="location"><context context-type="linenumber">211</context></context-group>
<note annotates="source" from="developer">&quot;device&quot; usually means a hardware wallet.</note>
</trans-unit>
- <trans-unit id="_msg697">
+ <trans-unit id="_msg720">
<source xml:space="preserve">Connect your hardware wallet first.</source>
<context-group purpose="location"><context context-type="linenumber">214</context></context-group>
</trans-unit>
- <trans-unit id="_msg698">
+ <trans-unit id="_msg721">
<source xml:space="preserve">Set external signer script path in Options -&gt; Wallet</source>
<context-group purpose="location"><context context-type="linenumber">218</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg699">
+ <trans-unit id="_msg722">
<source xml:space="preserve">Cr&amp;eate Unsigned</source>
<context-group purpose="location"><context context-type="linenumber">221</context></context-group>
</trans-unit>
- <trans-unit id="_msg700">
+ <trans-unit id="_msg723">
<source xml:space="preserve">Creates a Partially Signed Bitcoin Transaction (PSBT) for use with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<context-group purpose="location"><context context-type="linenumber">222</context></context-group>
</trans-unit>
- <trans-unit id="_msg701">
+ <trans-unit id="_msg724">
<source xml:space="preserve"> from wallet &apos;%1&apos;</source>
<context-group purpose="location"><context context-type="linenumber">312</context></context-group>
</trans-unit>
- <trans-unit id="_msg702">
+ <trans-unit id="_msg725">
<source xml:space="preserve">%1 to &apos;%2&apos;</source>
<context-group purpose="location"><context context-type="linenumber">323</context></context-group>
</trans-unit>
- <trans-unit id="_msg703">
+ <trans-unit id="_msg726">
<source xml:space="preserve">%1 to %2</source>
<context-group purpose="location"><context context-type="linenumber">328</context></context-group>
</trans-unit>
- <trans-unit id="_msg704">
+ <trans-unit id="_msg727">
<source xml:space="preserve">To review recipient list click &quot;Show Details…&quot;</source>
- <context-group purpose="location"><context context-type="linenumber">395</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">394</context></context-group>
</trans-unit>
- <trans-unit id="_msg705">
+ <trans-unit id="_msg728">
<source xml:space="preserve">Sign failed</source>
- <context-group purpose="location"><context context-type="linenumber">439</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">454</context></context-group>
</trans-unit>
- <trans-unit id="_msg706">
+ <trans-unit id="_msg729">
<source xml:space="preserve">External signer not found</source>
- <context-group purpose="location"><context context-type="linenumber">445</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">459</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg707">
+ <trans-unit id="_msg730">
<source xml:space="preserve">External signer failure</source>
- <context-group purpose="location"><context context-type="linenumber">451</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">464</context></context-group>
<note annotates="source" from="developer">&quot;External signer&quot; means using devices such as hardware wallets.</note>
</trans-unit>
- <trans-unit id="_msg708">
+ <trans-unit id="_msg731">
<source xml:space="preserve">Save Transaction Data</source>
- <context-group purpose="location"><context context-type="linenumber">509</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">430</context></context-group>
</trans-unit>
- <trans-unit id="_msg709">
+ <trans-unit id="_msg732">
<source xml:space="preserve">Partially Signed Transaction (Binary)</source>
- <context-group purpose="location"><context context-type="linenumber">511</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">432</context></context-group>
<note annotates="source" from="developer">Expanded name of the binary PSBT file format. See: BIP 174.</note>
</trans-unit>
- <trans-unit id="_msg710">
+ <trans-unit id="_msg733">
<source xml:space="preserve">PSBT saved</source>
- <context-group purpose="location"><context context-type="linenumber">518</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">439</context></context-group>
</trans-unit>
- <trans-unit id="_msg711">
+ <trans-unit id="_msg734">
<source xml:space="preserve">External balance:</source>
- <context-group purpose="location"><context context-type="linenumber">694</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">705</context></context-group>
</trans-unit>
- <trans-unit id="_msg712">
+ <trans-unit id="_msg735">
<source xml:space="preserve">or</source>
- <context-group purpose="location"><context context-type="linenumber">391</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">390</context></context-group>
</trans-unit>
- <trans-unit id="_msg713">
+ <trans-unit id="_msg736">
<source xml:space="preserve">You can increase the fee later (signals Replace-By-Fee, BIP-125).</source>
<context-group purpose="location"><context context-type="linenumber">372</context></context-group>
</trans-unit>
- <trans-unit id="_msg714">
+ <trans-unit id="_msg737">
<source xml:space="preserve">Please, review your transaction proposal. This will produce a Partially Signed Bitcoin Transaction (PSBT) which you can save or copy and then sign with e.g. an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<context-group purpose="location"><context context-type="linenumber">342</context></context-group>
<note annotates="source" from="developer">Text to inform a user attempting to create a transaction of their current options. At this stage, a user can only create a PSBT. This string is displayed when private keys are disabled and an external signer is not available.</note>
</trans-unit>
- <trans-unit id="_msg715">
+ <trans-unit id="_msg738">
<source xml:space="preserve">Do you want to create this transaction?</source>
<context-group purpose="location"><context context-type="linenumber">336</context></context-group>
<note annotates="source" from="developer">Message displayed when attempting to create a transaction. Cautionary text to prompt the user to verify that the displayed transaction details represent the transaction the user intends to create.</note>
</trans-unit>
- <trans-unit id="_msg716">
+ <trans-unit id="_msg739">
<source xml:space="preserve">Please, review your transaction. You can create and send this transaction or create a Partially Signed Bitcoin Transaction (PSBT), which you can save or copy and then sign with, e.g., an offline %1 wallet, or a PSBT-compatible hardware wallet.</source>
<context-group purpose="location"><context context-type="linenumber">347</context></context-group>
<note annotates="source" from="developer">Text to inform a user attempting to create a transaction of their current options. At this stage, a user can send their transaction or create a PSBT. This string is displayed when both private keys and PSBT controls are enabled.</note>
</trans-unit>
- <trans-unit id="_msg717">
+ <trans-unit id="_msg740">
<source xml:space="preserve">Please, review your transaction.</source>
<context-group purpose="location"><context context-type="linenumber">350</context></context-group>
<note annotates="source" from="developer">Text to prompt a user to review the details of the transaction they are attempting to send.</note>
</trans-unit>
- <trans-unit id="_msg718">
+ <trans-unit id="_msg741">
<source xml:space="preserve">Transaction fee</source>
<context-group purpose="location"><context context-type="linenumber">358</context></context-group>
</trans-unit>
- <trans-unit id="_msg719">
+ <trans-unit id="_msg742">
<source xml:space="preserve">Not signalling Replace-By-Fee, BIP-125.</source>
<context-group purpose="location"><context context-type="linenumber">374</context></context-group>
</trans-unit>
- <trans-unit id="_msg720">
+ <trans-unit id="_msg743">
<source xml:space="preserve">Total Amount</source>
- <context-group purpose="location"><context context-type="linenumber">388</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">387</context></context-group>
</trans-unit>
- <trans-unit id="_msg721">
+ <trans-unit id="_msg744">
<source xml:space="preserve">Confirm send coins</source>
- <context-group purpose="location"><context context-type="linenumber">413</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">486</context></context-group>
</trans-unit>
- <trans-unit id="_msg722">
+ <trans-unit id="_msg745">
<source xml:space="preserve">Watch-only balance:</source>
- <context-group purpose="location"><context context-type="linenumber">697</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">708</context></context-group>
</trans-unit>
- <trans-unit id="_msg723">
+ <trans-unit id="_msg746">
<source xml:space="preserve">The recipient address is not valid. Please recheck.</source>
- <context-group purpose="location"><context context-type="linenumber">721</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">732</context></context-group>
</trans-unit>
- <trans-unit id="_msg724">
+ <trans-unit id="_msg747">
<source xml:space="preserve">The amount to pay must be larger than 0.</source>
- <context-group purpose="location"><context context-type="linenumber">724</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">735</context></context-group>
</trans-unit>
- <trans-unit id="_msg725">
+ <trans-unit id="_msg748">
<source xml:space="preserve">The amount exceeds your balance.</source>
- <context-group purpose="location"><context context-type="linenumber">727</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">738</context></context-group>
</trans-unit>
- <trans-unit id="_msg726">
+ <trans-unit id="_msg749">
<source xml:space="preserve">The total exceeds your balance when the %1 transaction fee is included.</source>
- <context-group purpose="location"><context context-type="linenumber">730</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">741</context></context-group>
</trans-unit>
- <trans-unit id="_msg727">
+ <trans-unit id="_msg750">
<source xml:space="preserve">Duplicate address found: addresses should only be used once each.</source>
- <context-group purpose="location"><context context-type="linenumber">733</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">744</context></context-group>
</trans-unit>
- <trans-unit id="_msg728">
+ <trans-unit id="_msg751">
<source xml:space="preserve">Transaction creation failed!</source>
- <context-group purpose="location"><context context-type="linenumber">736</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">747</context></context-group>
</trans-unit>
- <trans-unit id="_msg729">
+ <trans-unit id="_msg752">
<source xml:space="preserve">A fee higher than %1 is considered an absurdly high fee.</source>
- <context-group purpose="location"><context context-type="linenumber">740</context></context-group>
- </trans-unit>
- <trans-unit id="_msg730">
- <source xml:space="preserve">Payment request expired.</source>
- <context-group purpose="location"><context context-type="linenumber">743</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">751</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">867</context></context-group>
- <trans-unit id="_msg731[0]">
+ <context-group purpose="location"><context context-type="linenumber">874</context></context-group>
+ <trans-unit id="_msg753[0]">
<source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source>
</trans-unit>
- <trans-unit id="_msg731[1]">
+ <trans-unit id="_msg753[1]">
<source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source>
</trans-unit>
</group>
- <trans-unit id="_msg732">
+ <trans-unit id="_msg754">
<source xml:space="preserve">Warning: Invalid Bitcoin address</source>
- <context-group purpose="location"><context context-type="linenumber">968</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">975</context></context-group>
</trans-unit>
- <trans-unit id="_msg733">
+ <trans-unit id="_msg755">
<source xml:space="preserve">Warning: Unknown change address</source>
- <context-group purpose="location"><context context-type="linenumber">973</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">980</context></context-group>
</trans-unit>
- <trans-unit id="_msg734">
+ <trans-unit id="_msg756">
<source xml:space="preserve">Confirm custom change address</source>
- <context-group purpose="location"><context context-type="linenumber">976</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">983</context></context-group>
</trans-unit>
- <trans-unit id="_msg735">
+ <trans-unit id="_msg757">
<source xml:space="preserve">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>
- <context-group purpose="location"><context context-type="linenumber">976</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">983</context></context-group>
</trans-unit>
- <trans-unit id="_msg736">
+ <trans-unit id="_msg758">
<source xml:space="preserve">(no label)</source>
- <context-group purpose="location"><context context-type="linenumber">997</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">1004</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/sendcoinsentry.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendCoinsEntry">
- <trans-unit id="_msg737">
+ <trans-unit id="_msg759">
<source xml:space="preserve">A&amp;mount:</source>
- <context-group purpose="location"><context context-type="linenumber">155</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">705</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">1238</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">151</context></context-group>
</trans-unit>
- <trans-unit id="_msg738">
+ <trans-unit id="_msg760">
<source xml:space="preserve">Pay &amp;To:</source>
- <context-group purpose="location"><context context-type="linenumber">39</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">35</context></context-group>
</trans-unit>
- <trans-unit id="_msg739">
+ <trans-unit id="_msg761">
<source xml:space="preserve">&amp;Label:</source>
- <context-group purpose="location"><context context-type="linenumber">132</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">128</context></context-group>
</trans-unit>
- <trans-unit id="_msg740">
+ <trans-unit id="_msg762">
<source xml:space="preserve">Choose previously used address</source>
- <context-group purpose="location"><context context-type="linenumber">64</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">60</context></context-group>
</trans-unit>
- <trans-unit id="_msg741">
+ <trans-unit id="_msg763">
<source xml:space="preserve">The Bitcoin address to send the payment to</source>
- <context-group purpose="location"><context context-type="linenumber">57</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg742">
+ <trans-unit id="_msg764">
<source xml:space="preserve">Alt+A</source>
- <context-group purpose="location"><context context-type="linenumber">80</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg743">
+ <trans-unit id="_msg765">
<source xml:space="preserve">Paste address from clipboard</source>
- <context-group purpose="location"><context context-type="linenumber">87</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">83</context></context-group>
</trans-unit>
- <trans-unit id="_msg744">
+ <trans-unit id="_msg766">
<source xml:space="preserve">Alt+P</source>
- <context-group purpose="location"><context context-type="linenumber">103</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
</trans-unit>
- <trans-unit id="_msg745">
+ <trans-unit id="_msg767">
<source xml:space="preserve">Remove this entry</source>
- <context-group purpose="location"><context context-type="linenumber">110</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">672</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">1205</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">106</context></context-group>
</trans-unit>
- <trans-unit id="_msg746">
+ <trans-unit id="_msg768">
<source xml:space="preserve">The amount to send in the selected unit</source>
- <context-group purpose="location"><context context-type="linenumber">170</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">166</context></context-group>
</trans-unit>
- <trans-unit id="_msg747">
+ <trans-unit id="_msg769">
<source xml:space="preserve">The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
- <context-group purpose="location"><context context-type="linenumber">177</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
- <trans-unit id="_msg748">
+ <trans-unit id="_msg770">
<source xml:space="preserve">S&amp;ubtract fee from amount</source>
- <context-group purpose="location"><context context-type="linenumber">180</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">176</context></context-group>
</trans-unit>
- <trans-unit id="_msg749">
+ <trans-unit id="_msg771">
<source xml:space="preserve">Use available balance</source>
- <context-group purpose="location"><context context-type="linenumber">187</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">183</context></context-group>
</trans-unit>
- <trans-unit id="_msg750">
+ <trans-unit id="_msg772">
<source xml:space="preserve">Message:</source>
- <context-group purpose="location"><context context-type="linenumber">196</context></context-group>
- </trans-unit>
- <trans-unit id="_msg751">
- <source xml:space="preserve">This is an unauthenticated payment request.</source>
- <context-group purpose="location"><context context-type="linenumber">639</context></context-group>
- </trans-unit>
- <trans-unit id="_msg752">
- <source xml:space="preserve">This is an authenticated payment request.</source>
- <context-group purpose="location"><context context-type="linenumber">1168</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">192</context></context-group>
</trans-unit>
- <trans-unit id="_msg753">
+ <trans-unit id="_msg773">
<source xml:space="preserve">Enter a label for this address to add it to the list of used addresses</source>
- <context-group purpose="location"><context context-type="linenumber">145</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">148</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">141</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg754">
+ <trans-unit id="_msg774">
<source xml:space="preserve">A message that was attached to the bitcoin: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Bitcoin network.</source>
- <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
- </trans-unit>
- <trans-unit id="_msg755">
- <source xml:space="preserve">Pay To:</source>
- <context-group purpose="location"><context context-type="linenumber">654</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">1183</context></context-group>
- </trans-unit>
- <trans-unit id="_msg756">
- <source xml:space="preserve">Memo:</source>
- <context-group purpose="location"><context context-type="linenumber">688</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">1221</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">202</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../sendcoinsdialog.h" datatype="c" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SendConfirmationDialog">
- <trans-unit id="_msg757">
+ <trans-unit id="_msg775">
<source xml:space="preserve">Send</source>
- <context-group purpose="location"><context context-type="linenumber">131</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg758">
+ <trans-unit id="_msg776">
<source xml:space="preserve">Create Unsigned</source>
- <context-group purpose="location"><context context-type="linenumber">133</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/signverifymessagedialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog">
- <trans-unit id="_msg759">
+ <trans-unit id="_msg777">
<source xml:space="preserve">Signatures - Sign / Verify a Message</source>
<context-group purpose="location"><context context-type="linenumber">14</context></context-group>
</trans-unit>
- <trans-unit id="_msg760">
+ <trans-unit id="_msg778">
<source xml:space="preserve">&amp;Sign Message</source>
<context-group purpose="location"><context context-type="linenumber">27</context></context-group>
</trans-unit>
- <trans-unit id="_msg761">
+ <trans-unit id="_msg779">
<source xml:space="preserve">You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source>
<context-group purpose="location"><context context-type="linenumber">33</context></context-group>
</trans-unit>
- <trans-unit id="_msg762">
+ <trans-unit id="_msg780">
<source xml:space="preserve">The Bitcoin address to sign the message with</source>
<context-group purpose="location"><context context-type="linenumber">51</context></context-group>
</trans-unit>
- <trans-unit id="_msg763">
+ <trans-unit id="_msg781">
<source xml:space="preserve">Choose previously used address</source>
<context-group purpose="location"><context context-type="linenumber">58</context></context-group>
<context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg764">
+ <trans-unit id="_msg782">
<source xml:space="preserve">Alt+A</source>
<context-group purpose="location"><context context-type="linenumber">68</context></context-group>
<context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg765">
+ <trans-unit id="_msg783">
<source xml:space="preserve">Paste address from clipboard</source>
<context-group purpose="location"><context context-type="linenumber">78</context></context-group>
</trans-unit>
- <trans-unit id="_msg766">
+ <trans-unit id="_msg784">
<source xml:space="preserve">Alt+P</source>
<context-group purpose="location"><context context-type="linenumber">88</context></context-group>
</trans-unit>
- <trans-unit id="_msg767">
+ <trans-unit id="_msg785">
<source xml:space="preserve">Enter the message you want to sign here</source>
<context-group purpose="location"><context context-type="linenumber">100</context></context-group>
<context-group purpose="location"><context context-type="linenumber">103</context></context-group>
</trans-unit>
- <trans-unit id="_msg768">
+ <trans-unit id="_msg786">
<source xml:space="preserve">Signature</source>
<context-group purpose="location"><context context-type="linenumber">110</context></context-group>
</trans-unit>
- <trans-unit id="_msg769">
+ <trans-unit id="_msg787">
<source xml:space="preserve">Copy the current signature to the system clipboard</source>
<context-group purpose="location"><context context-type="linenumber">140</context></context-group>
</trans-unit>
- <trans-unit id="_msg770">
+ <trans-unit id="_msg788">
<source xml:space="preserve">Sign the message to prove you own this Bitcoin address</source>
<context-group purpose="location"><context context-type="linenumber">161</context></context-group>
</trans-unit>
- <trans-unit id="_msg771">
+ <trans-unit id="_msg789">
<source xml:space="preserve">Sign &amp;Message</source>
<context-group purpose="location"><context context-type="linenumber">164</context></context-group>
</trans-unit>
- <trans-unit id="_msg772">
+ <trans-unit id="_msg790">
<source xml:space="preserve">Reset all sign message fields</source>
<context-group purpose="location"><context context-type="linenumber">178</context></context-group>
</trans-unit>
- <trans-unit id="_msg773">
+ <trans-unit id="_msg791">
<source xml:space="preserve">Clear &amp;All</source>
<context-group purpose="location"><context context-type="linenumber">181</context></context-group>
<context-group purpose="location"><context context-type="linenumber">338</context></context-group>
</trans-unit>
- <trans-unit id="_msg774">
+ <trans-unit id="_msg792">
<source xml:space="preserve">&amp;Verify Message</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg775">
+ <trans-unit id="_msg793">
<source xml:space="preserve">Enter the receiver&apos;s address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
<context-group purpose="location"><context context-type="linenumber">246</context></context-group>
</trans-unit>
- <trans-unit id="_msg776">
+ <trans-unit id="_msg794">
<source xml:space="preserve">The Bitcoin address the message was signed with</source>
<context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg777">
+ <trans-unit id="_msg795">
<source xml:space="preserve">The signed message to verify</source>
<context-group purpose="location"><context context-type="linenumber">296</context></context-group>
<context-group purpose="location"><context context-type="linenumber">299</context></context-group>
</trans-unit>
- <trans-unit id="_msg778">
+ <trans-unit id="_msg796">
<source xml:space="preserve">The signature given when the message was signed</source>
<context-group purpose="location"><context context-type="linenumber">306</context></context-group>
<context-group purpose="location"><context context-type="linenumber">309</context></context-group>
</trans-unit>
- <trans-unit id="_msg779">
+ <trans-unit id="_msg797">
<source xml:space="preserve">Verify the message to ensure it was signed with the specified Bitcoin address</source>
<context-group purpose="location"><context context-type="linenumber">318</context></context-group>
</trans-unit>
- <trans-unit id="_msg780">
+ <trans-unit id="_msg798">
<source xml:space="preserve">Verify &amp;Message</source>
<context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg781">
+ <trans-unit id="_msg799">
<source xml:space="preserve">Reset all verify message fields</source>
<context-group purpose="location"><context context-type="linenumber">335</context></context-group>
</trans-unit>
- <trans-unit id="_msg782">
+ <trans-unit id="_msg800">
<source xml:space="preserve">Click &quot;Sign Message&quot; to generate signature</source>
<context-group purpose="location"><context context-type="linenumber">125</context></context-group>
</trans-unit>
@@ -3561,61 +3671,61 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../signverifymessagedialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog">
- <trans-unit id="_msg783">
+ <trans-unit id="_msg801">
<source xml:space="preserve">The entered address is invalid.</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
<context-group purpose="location"><context context-type="linenumber">219</context></context-group>
</trans-unit>
- <trans-unit id="_msg784">
+ <trans-unit id="_msg802">
<source xml:space="preserve">Please check the address and try again.</source>
<context-group purpose="location"><context context-type="linenumber">120</context></context-group>
<context-group purpose="location"><context context-type="linenumber">127</context></context-group>
<context-group purpose="location"><context context-type="linenumber">220</context></context-group>
<context-group purpose="location"><context context-type="linenumber">227</context></context-group>
</trans-unit>
- <trans-unit id="_msg785">
+ <trans-unit id="_msg803">
<source xml:space="preserve">The entered address does not refer to a key.</source>
<context-group purpose="location"><context context-type="linenumber">127</context></context-group>
<context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg786">
+ <trans-unit id="_msg804">
<source xml:space="preserve">Wallet unlock was cancelled.</source>
<context-group purpose="location"><context context-type="linenumber">135</context></context-group>
</trans-unit>
- <trans-unit id="_msg787">
+ <trans-unit id="_msg805">
<source xml:space="preserve">No error</source>
<context-group purpose="location"><context context-type="linenumber">146</context></context-group>
</trans-unit>
- <trans-unit id="_msg788">
+ <trans-unit id="_msg806">
<source xml:space="preserve">Private key for the entered address is not available.</source>
<context-group purpose="location"><context context-type="linenumber">149</context></context-group>
</trans-unit>
- <trans-unit id="_msg789">
+ <trans-unit id="_msg807">
<source xml:space="preserve">Message signing failed.</source>
<context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg790">
+ <trans-unit id="_msg808">
<source xml:space="preserve">Message signed.</source>
<context-group purpose="location"><context context-type="linenumber">164</context></context-group>
</trans-unit>
- <trans-unit id="_msg791">
+ <trans-unit id="_msg809">
<source xml:space="preserve">The signature could not be decoded.</source>
<context-group purpose="location"><context context-type="linenumber">233</context></context-group>
</trans-unit>
- <trans-unit id="_msg792">
+ <trans-unit id="_msg810">
<source xml:space="preserve">Please check the signature and try again.</source>
<context-group purpose="location"><context context-type="linenumber">234</context></context-group>
<context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg793">
+ <trans-unit id="_msg811">
<source xml:space="preserve">The signature did not match the message digest.</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg794">
+ <trans-unit id="_msg812">
<source xml:space="preserve">Message verification failed.</source>
<context-group purpose="location"><context context-type="linenumber">246</context></context-group>
</trans-unit>
- <trans-unit id="_msg795">
+ <trans-unit id="_msg813">
<source xml:space="preserve">Message verified.</source>
<context-group purpose="location"><context context-type="linenumber">214</context></context-group>
</trans-unit>
@@ -3623,11 +3733,11 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../splashscreen.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="SplashScreen">
- <trans-unit id="_msg796">
+ <trans-unit id="_msg814">
<source xml:space="preserve">(press q to shutdown and continue later)</source>
<context-group purpose="location"><context context-type="linenumber">187</context></context-group>
</trans-unit>
- <trans-unit id="_msg797">
+ <trans-unit id="_msg815">
<source xml:space="preserve">press q to shutdown</source>
<context-group purpose="location"><context context-type="linenumber">188</context></context-group>
</trans-unit>
@@ -3635,7 +3745,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../trafficgraphwidget.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TrafficGraphWidget">
- <trans-unit id="_msg798">
+ <trans-unit id="_msg816">
<source xml:space="preserve">kB/s</source>
<context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
@@ -3643,190 +3753,192 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiondesc.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDesc">
- <trans-unit id="_msg799">
+ <trans-unit id="_msg817">
<source xml:space="preserve">conflicted with a transaction with %1 confirmations</source>
- <context-group purpose="location"><context context-type="linenumber">40</context></context-group>
- </trans-unit>
- <trans-unit id="_msg800">
- <source xml:space="preserve">0/unconfirmed, %1</source>
<context-group purpose="location"><context context-type="linenumber">43</context></context-group>
+ <note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that conflicts with a confirmed transaction.</note>
</trans-unit>
- <trans-unit id="_msg801">
- <source xml:space="preserve">in memory pool</source>
- <context-group purpose="location"><context context-type="linenumber">43</context></context-group>
+ <trans-unit id="_msg818">
+ <source xml:space="preserve">0/unconfirmed, in memory pool</source>
+ <context-group purpose="location"><context context-type="linenumber">50</context></context-group>
+ <note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is in the memory pool.</note>
</trans-unit>
- <trans-unit id="_msg802">
- <source xml:space="preserve">not in memory pool</source>
- <context-group purpose="location"><context context-type="linenumber">43</context></context-group>
+ <trans-unit id="_msg819">
+ <source xml:space="preserve">0/unconfirmed, not in memory pool</source>
+ <context-group purpose="location"><context context-type="linenumber">55</context></context-group>
+ <note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an unconfirmed transaction that is not in the memory pool.</note>
</trans-unit>
- <trans-unit id="_msg803">
+ <trans-unit id="_msg820">
<source xml:space="preserve">abandoned</source>
- <context-group purpose="location"><context context-type="linenumber">42</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">61</context></context-group>
+ <note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents an abandoned transaction.</note>
</trans-unit>
- <trans-unit id="_msg804">
+ <trans-unit id="_msg821">
<source xml:space="preserve">%1/unconfirmed</source>
- <context-group purpose="location"><context context-type="linenumber">45</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">69</context></context-group>
+ <note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in at least one block, but less than 6 blocks.</note>
</trans-unit>
- <trans-unit id="_msg805">
+ <trans-unit id="_msg822">
<source xml:space="preserve">%1 confirmations</source>
- <context-group purpose="location"><context context-type="linenumber">47</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">74</context></context-group>
+ <note annotates="source" from="developer">Text explaining the current status of a transaction, shown in the status field of the details window for this transaction. This status represents a transaction confirmed in 6 or more blocks.</note>
</trans-unit>
- <trans-unit id="_msg806">
+ <trans-unit id="_msg823">
<source xml:space="preserve">Status</source>
- <context-group purpose="location"><context context-type="linenumber">98</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">124</context></context-group>
</trans-unit>
- <trans-unit id="_msg807">
+ <trans-unit id="_msg824">
<source xml:space="preserve">Date</source>
- <context-group purpose="location"><context context-type="linenumber">101</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">127</context></context-group>
</trans-unit>
- <trans-unit id="_msg808">
+ <trans-unit id="_msg825">
<source xml:space="preserve">Source</source>
- <context-group purpose="location"><context context-type="linenumber">108</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg809">
+ <trans-unit id="_msg826">
<source xml:space="preserve">Generated</source>
- <context-group purpose="location"><context context-type="linenumber">108</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg810">
+ <trans-unit id="_msg827">
<source xml:space="preserve">From</source>
- <context-group purpose="location"><context context-type="linenumber">113</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">127</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">199</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">139</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">153</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg811">
+ <trans-unit id="_msg828">
<source xml:space="preserve">unknown</source>
- <context-group purpose="location"><context context-type="linenumber">127</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">153</context></context-group>
</trans-unit>
- <trans-unit id="_msg812">
+ <trans-unit id="_msg829">
<source xml:space="preserve">To</source>
- <context-group purpose="location"><context context-type="linenumber">128</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">148</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">154</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">174</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">244</context></context-group>
</trans-unit>
- <trans-unit id="_msg813">
+ <trans-unit id="_msg830">
<source xml:space="preserve">own address</source>
- <context-group purpose="location"><context context-type="linenumber">130</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">156</context></context-group>
</trans-unit>
- <trans-unit id="_msg814">
+ <trans-unit id="_msg831">
<source xml:space="preserve">watch-only</source>
- <context-group purpose="location"><context context-type="linenumber">130</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">199</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">156</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg815">
+ <trans-unit id="_msg832">
<source xml:space="preserve">label</source>
- <context-group purpose="location"><context context-type="linenumber">132</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">158</context></context-group>
</trans-unit>
- <trans-unit id="_msg816">
+ <trans-unit id="_msg833">
<source xml:space="preserve">Credit</source>
- <context-group purpose="location"><context context-type="linenumber">168</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">180</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">234</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">264</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">194</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">290</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">350</context></context-group>
</trans-unit>
<group restype="x-gettext-plurals">
- <context-group purpose="location"><context context-type="linenumber">170</context></context-group>
- <trans-unit id="_msg817[0]">
+ <context-group purpose="location"><context context-type="linenumber">196</context></context-group>
+ <trans-unit id="_msg834[0]">
<source xml:space="preserve">matures in %n more block(s)</source>
</trans-unit>
- <trans-unit id="_msg817[1]">
+ <trans-unit id="_msg834[1]">
<source xml:space="preserve">matures in %n more block(s)</source>
</trans-unit>
</group>
- <trans-unit id="_msg818">
+ <trans-unit id="_msg835">
<source xml:space="preserve">not accepted</source>
- <context-group purpose="location"><context context-type="linenumber">172</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">198</context></context-group>
</trans-unit>
- <trans-unit id="_msg819">
+ <trans-unit id="_msg836">
<source xml:space="preserve">Debit</source>
- <context-group purpose="location"><context context-type="linenumber">232</context></context-group>
<context-group purpose="location"><context context-type="linenumber">258</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">284</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">347</context></context-group>
</trans-unit>
- <trans-unit id="_msg820">
+ <trans-unit id="_msg837">
<source xml:space="preserve">Total debit</source>
- <context-group purpose="location"><context context-type="linenumber">242</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg821">
+ <trans-unit id="_msg838">
<source xml:space="preserve">Total credit</source>
- <context-group purpose="location"><context context-type="linenumber">243</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg822">
+ <trans-unit id="_msg839">
<source xml:space="preserve">Transaction fee</source>
- <context-group purpose="location"><context context-type="linenumber">248</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg823">
+ <trans-unit id="_msg840">
<source xml:space="preserve">Net amount</source>
- <context-group purpose="location"><context context-type="linenumber">270</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">296</context></context-group>
</trans-unit>
- <trans-unit id="_msg824">
+ <trans-unit id="_msg841">
<source xml:space="preserve">Message</source>
- <context-group purpose="location"><context context-type="linenumber">276</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">302</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">314</context></context-group>
</trans-unit>
- <trans-unit id="_msg825">
+ <trans-unit id="_msg842">
<source xml:space="preserve">Comment</source>
- <context-group purpose="location"><context context-type="linenumber">278</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">304</context></context-group>
</trans-unit>
- <trans-unit id="_msg826">
+ <trans-unit id="_msg843">
<source xml:space="preserve">Transaction ID</source>
- <context-group purpose="location"><context context-type="linenumber">280</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">306</context></context-group>
</trans-unit>
- <trans-unit id="_msg827">
+ <trans-unit id="_msg844">
<source xml:space="preserve">Transaction total size</source>
- <context-group purpose="location"><context context-type="linenumber">281</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">307</context></context-group>
</trans-unit>
- <trans-unit id="_msg828">
+ <trans-unit id="_msg845">
<source xml:space="preserve">Transaction virtual size</source>
- <context-group purpose="location"><context context-type="linenumber">282</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">308</context></context-group>
</trans-unit>
- <trans-unit id="_msg829">
+ <trans-unit id="_msg846">
<source xml:space="preserve">Output index</source>
- <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">309</context></context-group>
</trans-unit>
- <trans-unit id="_msg830">
+ <trans-unit id="_msg847">
<source xml:space="preserve"> (Certificate was not verified)</source>
- <context-group purpose="location"><context context-type="linenumber">299</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">325</context></context-group>
</trans-unit>
- <trans-unit id="_msg831">
+ <trans-unit id="_msg848">
<source xml:space="preserve">Merchant</source>
- <context-group purpose="location"><context context-type="linenumber">302</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">328</context></context-group>
</trans-unit>
- <trans-unit id="_msg832">
+ <trans-unit id="_msg849">
<source xml:space="preserve">Generated coins must mature %1 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to &quot;not accepted&quot; and it won&apos;t be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source>
- <context-group purpose="location"><context context-type="linenumber">310</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">336</context></context-group>
</trans-unit>
- <trans-unit id="_msg833">
+ <trans-unit id="_msg850">
<source xml:space="preserve">Debug information</source>
- <context-group purpose="location"><context context-type="linenumber">318</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">344</context></context-group>
</trans-unit>
- <trans-unit id="_msg834">
+ <trans-unit id="_msg851">
<source xml:space="preserve">Transaction</source>
- <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">352</context></context-group>
</trans-unit>
- <trans-unit id="_msg835">
+ <trans-unit id="_msg852">
<source xml:space="preserve">Inputs</source>
- <context-group purpose="location"><context context-type="linenumber">329</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">355</context></context-group>
</trans-unit>
- <trans-unit id="_msg836">
+ <trans-unit id="_msg853">
<source xml:space="preserve">Amount</source>
- <context-group purpose="location"><context context-type="linenumber">350</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg837">
+ <trans-unit id="_msg854">
<source xml:space="preserve">true</source>
- <context-group purpose="location"><context context-type="linenumber">351</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">352</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">377</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">378</context></context-group>
</trans-unit>
- <trans-unit id="_msg838">
+ <trans-unit id="_msg855">
<source xml:space="preserve">false</source>
- <context-group purpose="location"><context context-type="linenumber">351</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">352</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">377</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">378</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../forms/transactiondescdialog.ui" datatype="x-trolltech-designer-ui" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDescDialog">
- <trans-unit id="_msg839">
+ <trans-unit id="_msg856">
<source xml:space="preserve">This pane shows a detailed description of the transaction</source>
<context-group purpose="location"><context context-type="linenumber">20</context></context-group>
</trans-unit>
@@ -3834,7 +3946,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiondescdialog.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionDescDialog">
- <trans-unit id="_msg840">
+ <trans-unit id="_msg857">
<source xml:space="preserve">Details for %1</source>
<context-group purpose="location"><context context-type="linenumber">18</context></context-group>
</trans-unit>
@@ -3842,266 +3954,266 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../transactiontablemodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionTableModel">
- <trans-unit id="_msg841">
+ <trans-unit id="_msg858">
<source xml:space="preserve">Date</source>
- <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg842">
+ <trans-unit id="_msg859">
<source xml:space="preserve">Type</source>
- <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg843">
+ <trans-unit id="_msg860">
<source xml:space="preserve">Label</source>
- <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg844">
+ <trans-unit id="_msg861">
<source xml:space="preserve">Unconfirmed</source>
- <context-group purpose="location"><context context-type="linenumber">320</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">321</context></context-group>
</trans-unit>
- <trans-unit id="_msg845">
+ <trans-unit id="_msg862">
<source xml:space="preserve">Abandoned</source>
- <context-group purpose="location"><context context-type="linenumber">323</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">324</context></context-group>
</trans-unit>
- <trans-unit id="_msg846">
+ <trans-unit id="_msg863">
<source xml:space="preserve">Confirming (%1 of %2 recommended confirmations)</source>
- <context-group purpose="location"><context context-type="linenumber">326</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">327</context></context-group>
</trans-unit>
- <trans-unit id="_msg847">
+ <trans-unit id="_msg864">
<source xml:space="preserve">Confirmed (%1 confirmations)</source>
- <context-group purpose="location"><context context-type="linenumber">329</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">330</context></context-group>
</trans-unit>
- <trans-unit id="_msg848">
+ <trans-unit id="_msg865">
<source xml:space="preserve">Conflicted</source>
- <context-group purpose="location"><context context-type="linenumber">332</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">333</context></context-group>
</trans-unit>
- <trans-unit id="_msg849">
+ <trans-unit id="_msg866">
<source xml:space="preserve">Immature (%1 confirmations, will be available after %2)</source>
- <context-group purpose="location"><context context-type="linenumber">335</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">336</context></context-group>
</trans-unit>
- <trans-unit id="_msg850">
+ <trans-unit id="_msg867">
<source xml:space="preserve">Generated but not accepted</source>
- <context-group purpose="location"><context context-type="linenumber">338</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">339</context></context-group>
</trans-unit>
- <trans-unit id="_msg851">
+ <trans-unit id="_msg868">
<source xml:space="preserve">Received with</source>
- <context-group purpose="location"><context context-type="linenumber">377</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">378</context></context-group>
</trans-unit>
- <trans-unit id="_msg852">
+ <trans-unit id="_msg869">
<source xml:space="preserve">Received from</source>
- <context-group purpose="location"><context context-type="linenumber">379</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">380</context></context-group>
</trans-unit>
- <trans-unit id="_msg853">
+ <trans-unit id="_msg870">
<source xml:space="preserve">Sent to</source>
- <context-group purpose="location"><context context-type="linenumber">382</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">383</context></context-group>
</trans-unit>
- <trans-unit id="_msg854">
+ <trans-unit id="_msg871">
<source xml:space="preserve">Payment to yourself</source>
- <context-group purpose="location"><context context-type="linenumber">384</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">385</context></context-group>
</trans-unit>
- <trans-unit id="_msg855">
+ <trans-unit id="_msg872">
<source xml:space="preserve">Mined</source>
- <context-group purpose="location"><context context-type="linenumber">386</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">387</context></context-group>
</trans-unit>
- <trans-unit id="_msg856">
+ <trans-unit id="_msg873">
<source xml:space="preserve">watch-only</source>
- <context-group purpose="location"><context context-type="linenumber">414</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">415</context></context-group>
</trans-unit>
- <trans-unit id="_msg857">
+ <trans-unit id="_msg874">
<source xml:space="preserve">(n/a)</source>
- <context-group purpose="location"><context context-type="linenumber">430</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">431</context></context-group>
</trans-unit>
- <trans-unit id="_msg858">
+ <trans-unit id="_msg875">
<source xml:space="preserve">(no label)</source>
- <context-group purpose="location"><context context-type="linenumber">637</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">638</context></context-group>
</trans-unit>
- <trans-unit id="_msg859">
+ <trans-unit id="_msg876">
<source xml:space="preserve">Transaction status. Hover over this field to show number of confirmations.</source>
- <context-group purpose="location"><context context-type="linenumber">676</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">677</context></context-group>
</trans-unit>
- <trans-unit id="_msg860">
+ <trans-unit id="_msg877">
<source xml:space="preserve">Date and time that the transaction was received.</source>
- <context-group purpose="location"><context context-type="linenumber">678</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">679</context></context-group>
</trans-unit>
- <trans-unit id="_msg861">
+ <trans-unit id="_msg878">
<source xml:space="preserve">Type of transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">680</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">681</context></context-group>
</trans-unit>
- <trans-unit id="_msg862">
+ <trans-unit id="_msg879">
<source xml:space="preserve">Whether or not a watch-only address is involved in this transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">682</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">683</context></context-group>
</trans-unit>
- <trans-unit id="_msg863">
+ <trans-unit id="_msg880">
<source xml:space="preserve">User-defined intent/purpose of the transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">684</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">685</context></context-group>
</trans-unit>
- <trans-unit id="_msg864">
+ <trans-unit id="_msg881">
<source xml:space="preserve">Amount removed from or added to balance.</source>
- <context-group purpose="location"><context context-type="linenumber">686</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">687</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../transactionview.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="TransactionView">
- <trans-unit id="_msg865">
+ <trans-unit id="_msg882">
<source xml:space="preserve">All</source>
<context-group purpose="location"><context context-type="linenumber">73</context></context-group>
<context-group purpose="location"><context context-type="linenumber">89</context></context-group>
</trans-unit>
- <trans-unit id="_msg866">
+ <trans-unit id="_msg883">
<source xml:space="preserve">Today</source>
<context-group purpose="location"><context context-type="linenumber">74</context></context-group>
</trans-unit>
- <trans-unit id="_msg867">
+ <trans-unit id="_msg884">
<source xml:space="preserve">This week</source>
<context-group purpose="location"><context context-type="linenumber">75</context></context-group>
</trans-unit>
- <trans-unit id="_msg868">
+ <trans-unit id="_msg885">
<source xml:space="preserve">This month</source>
<context-group purpose="location"><context context-type="linenumber">76</context></context-group>
</trans-unit>
- <trans-unit id="_msg869">
+ <trans-unit id="_msg886">
<source xml:space="preserve">Last month</source>
<context-group purpose="location"><context context-type="linenumber">77</context></context-group>
</trans-unit>
- <trans-unit id="_msg870">
+ <trans-unit id="_msg887">
<source xml:space="preserve">This year</source>
<context-group purpose="location"><context context-type="linenumber">78</context></context-group>
</trans-unit>
- <trans-unit id="_msg871">
+ <trans-unit id="_msg888">
<source xml:space="preserve">Received with</source>
<context-group purpose="location"><context context-type="linenumber">90</context></context-group>
</trans-unit>
- <trans-unit id="_msg872">
+ <trans-unit id="_msg889">
<source xml:space="preserve">Sent to</source>
<context-group purpose="location"><context context-type="linenumber">92</context></context-group>
</trans-unit>
- <trans-unit id="_msg873">
+ <trans-unit id="_msg890">
<source xml:space="preserve">To yourself</source>
<context-group purpose="location"><context context-type="linenumber">94</context></context-group>
</trans-unit>
- <trans-unit id="_msg874">
+ <trans-unit id="_msg891">
<source xml:space="preserve">Mined</source>
<context-group purpose="location"><context context-type="linenumber">95</context></context-group>
</trans-unit>
- <trans-unit id="_msg875">
+ <trans-unit id="_msg892">
<source xml:space="preserve">Other</source>
<context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg876">
+ <trans-unit id="_msg893">
<source xml:space="preserve">Enter address, transaction id, or label to search</source>
<context-group purpose="location"><context context-type="linenumber">101</context></context-group>
</trans-unit>
- <trans-unit id="_msg877">
+ <trans-unit id="_msg894">
<source xml:space="preserve">Min amount</source>
<context-group purpose="location"><context context-type="linenumber">105</context></context-group>
</trans-unit>
- <trans-unit id="_msg878">
+ <trans-unit id="_msg895">
<source xml:space="preserve">Range…</source>
<context-group purpose="location"><context context-type="linenumber">79</context></context-group>
</trans-unit>
- <trans-unit id="_msg879">
+ <trans-unit id="_msg896">
<source xml:space="preserve">&amp;Copy address</source>
<context-group purpose="location"><context context-type="linenumber">169</context></context-group>
</trans-unit>
- <trans-unit id="_msg880">
+ <trans-unit id="_msg897">
<source xml:space="preserve">Copy &amp;label</source>
<context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg881">
+ <trans-unit id="_msg898">
<source xml:space="preserve">Copy &amp;amount</source>
<context-group purpose="location"><context context-type="linenumber">171</context></context-group>
</trans-unit>
- <trans-unit id="_msg882">
+ <trans-unit id="_msg899">
<source xml:space="preserve">Copy transaction &amp;ID</source>
<context-group purpose="location"><context context-type="linenumber">172</context></context-group>
</trans-unit>
- <trans-unit id="_msg883">
+ <trans-unit id="_msg900">
<source xml:space="preserve">Copy &amp;raw transaction</source>
<context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
- <trans-unit id="_msg884">
+ <trans-unit id="_msg901">
<source xml:space="preserve">Copy full transaction &amp;details</source>
<context-group purpose="location"><context context-type="linenumber">174</context></context-group>
</trans-unit>
- <trans-unit id="_msg885">
+ <trans-unit id="_msg902">
<source xml:space="preserve">&amp;Show transaction details</source>
<context-group purpose="location"><context context-type="linenumber">175</context></context-group>
</trans-unit>
- <trans-unit id="_msg886">
+ <trans-unit id="_msg903">
<source xml:space="preserve">Increase transaction &amp;fee</source>
<context-group purpose="location"><context context-type="linenumber">177</context></context-group>
</trans-unit>
- <trans-unit id="_msg887">
+ <trans-unit id="_msg904">
<source xml:space="preserve">A&amp;bandon transaction</source>
<context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
- <trans-unit id="_msg888">
+ <trans-unit id="_msg905">
<source xml:space="preserve">&amp;Edit address label</source>
<context-group purpose="location"><context context-type="linenumber">181</context></context-group>
</trans-unit>
- <trans-unit id="_msg889">
+ <trans-unit id="_msg906">
<source xml:space="preserve">Show in %1</source>
<context-group purpose="location"><context context-type="linenumber">240</context></context-group>
<note annotates="source" from="developer">Transactions table context menu action to show the selected transaction in a third-party block explorer. %1 is a stand-in argument for the URL of the explorer.</note>
</trans-unit>
- <trans-unit id="_msg890">
+ <trans-unit id="_msg907">
<source xml:space="preserve">Export Transaction History</source>
<context-group purpose="location"><context context-type="linenumber">359</context></context-group>
</trans-unit>
- <trans-unit id="_msg891">
+ <trans-unit id="_msg908">
<source xml:space="preserve">Comma separated file</source>
<context-group purpose="location"><context context-type="linenumber">362</context></context-group>
<note annotates="source" from="developer">Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</note>
</trans-unit>
- <trans-unit id="_msg892">
+ <trans-unit id="_msg909">
<source xml:space="preserve">Confirmed</source>
<context-group purpose="location"><context context-type="linenumber">371</context></context-group>
</trans-unit>
- <trans-unit id="_msg893">
+ <trans-unit id="_msg910">
<source xml:space="preserve">Watch-only</source>
<context-group purpose="location"><context context-type="linenumber">373</context></context-group>
</trans-unit>
- <trans-unit id="_msg894">
+ <trans-unit id="_msg911">
<source xml:space="preserve">Date</source>
<context-group purpose="location"><context context-type="linenumber">374</context></context-group>
</trans-unit>
- <trans-unit id="_msg895">
+ <trans-unit id="_msg912">
<source xml:space="preserve">Type</source>
<context-group purpose="location"><context context-type="linenumber">375</context></context-group>
</trans-unit>
- <trans-unit id="_msg896">
+ <trans-unit id="_msg913">
<source xml:space="preserve">Label</source>
<context-group purpose="location"><context context-type="linenumber">376</context></context-group>
</trans-unit>
- <trans-unit id="_msg897">
+ <trans-unit id="_msg914">
<source xml:space="preserve">Address</source>
<context-group purpose="location"><context context-type="linenumber">377</context></context-group>
</trans-unit>
- <trans-unit id="_msg898">
+ <trans-unit id="_msg915">
<source xml:space="preserve">ID</source>
<context-group purpose="location"><context context-type="linenumber">379</context></context-group>
</trans-unit>
- <trans-unit id="_msg899">
+ <trans-unit id="_msg916">
<source xml:space="preserve">Exporting Failed</source>
<context-group purpose="location"><context context-type="linenumber">382</context></context-group>
</trans-unit>
- <trans-unit id="_msg900">
+ <trans-unit id="_msg917">
<source xml:space="preserve">There was an error trying to save the transaction history to %1.</source>
<context-group purpose="location"><context context-type="linenumber">382</context></context-group>
</trans-unit>
- <trans-unit id="_msg901">
+ <trans-unit id="_msg918">
<source xml:space="preserve">Exporting Successful</source>
<context-group purpose="location"><context context-type="linenumber">386</context></context-group>
</trans-unit>
- <trans-unit id="_msg902">
+ <trans-unit id="_msg919">
<source xml:space="preserve">The transaction history was successfully saved to %1.</source>
<context-group purpose="location"><context context-type="linenumber">386</context></context-group>
</trans-unit>
- <trans-unit id="_msg903">
+ <trans-unit id="_msg920">
<source xml:space="preserve">Range:</source>
<context-group purpose="location"><context context-type="linenumber">558</context></context-group>
</trans-unit>
- <trans-unit id="_msg904">
+ <trans-unit id="_msg921">
<source xml:space="preserve">to</source>
<context-group purpose="location"><context context-type="linenumber">566</context></context-group>
</trans-unit>
@@ -4109,810 +4221,838 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of &quot;100
</body></file>
<file original="../walletframe.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletFrame">
- <trans-unit id="_msg905">
+ <trans-unit id="_msg922">
<source xml:space="preserve">No wallet has been loaded.
Go to File &gt; Open Wallet to load a wallet.
- OR -</source>
<context-group purpose="location"><context context-type="linenumber">45</context></context-group>
</trans-unit>
- <trans-unit id="_msg906">
+ <trans-unit id="_msg923">
<source xml:space="preserve">Create a new wallet</source>
<context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg907">
+ <trans-unit id="_msg924">
<source xml:space="preserve">Error</source>
- <context-group purpose="location"><context context-type="linenumber">204</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">223</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">201</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">211</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">229</context></context-group>
</trans-unit>
- <trans-unit id="_msg908">
+ <trans-unit id="_msg925">
<source xml:space="preserve">Unable to decode PSBT from clipboard (invalid base64)</source>
- <context-group purpose="location"><context context-type="linenumber">204</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">201</context></context-group>
</trans-unit>
- <trans-unit id="_msg909">
+ <trans-unit id="_msg926">
<source xml:space="preserve">Load Transaction Data</source>
- <context-group purpose="location"><context context-type="linenumber">209</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">207</context></context-group>
</trans-unit>
- <trans-unit id="_msg910">
+ <trans-unit id="_msg927">
<source xml:space="preserve">Partially Signed Transaction (*.psbt)</source>
- <context-group purpose="location"><context context-type="linenumber">210</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg911">
+ <trans-unit id="_msg928">
<source xml:space="preserve">PSBT file must be smaller than 100 MiB</source>
- <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">211</context></context-group>
</trans-unit>
- <trans-unit id="_msg912">
+ <trans-unit id="_msg929">
<source xml:space="preserve">Unable to decode PSBT</source>
- <context-group purpose="location"><context context-type="linenumber">223</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">229</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../walletmodel.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletModel">
- <trans-unit id="_msg913">
+ <trans-unit id="_msg930">
<source xml:space="preserve">Send Coins</source>
<context-group purpose="location"><context context-type="linenumber">221</context></context-group>
</trans-unit>
- <trans-unit id="_msg914">
+ <trans-unit id="_msg931">
<source xml:space="preserve">Fee bump error</source>
- <context-group purpose="location"><context context-type="linenumber">481</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">533</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">548</context></context-group>
- <context-group purpose="location"><context context-type="linenumber">553</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">484</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">536</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">551</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">556</context></context-group>
</trans-unit>
- <trans-unit id="_msg915">
+ <trans-unit id="_msg932">
<source xml:space="preserve">Increasing transaction fee failed</source>
- <context-group purpose="location"><context context-type="linenumber">481</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">484</context></context-group>
</trans-unit>
- <trans-unit id="_msg916">
+ <trans-unit id="_msg933">
<source xml:space="preserve">Do you want to increase the fee?</source>
- <context-group purpose="location"><context context-type="linenumber">488</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">491</context></context-group>
<note annotates="source" from="developer">Asks a user if they would like to manually increase the fee of a transaction that has already been created.</note>
</trans-unit>
- <trans-unit id="_msg917">
+ <trans-unit id="_msg934">
<source xml:space="preserve">Current fee:</source>
- <context-group purpose="location"><context context-type="linenumber">492</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">495</context></context-group>
</trans-unit>
- <trans-unit id="_msg918">
+ <trans-unit id="_msg935">
<source xml:space="preserve">Increase:</source>
- <context-group purpose="location"><context context-type="linenumber">496</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">499</context></context-group>
</trans-unit>
- <trans-unit id="_msg919">
+ <trans-unit id="_msg936">
<source xml:space="preserve">New fee:</source>
- <context-group purpose="location"><context context-type="linenumber">500</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">503</context></context-group>
</trans-unit>
- <trans-unit id="_msg920">
+ <trans-unit id="_msg937">
<source xml:space="preserve">Warning: This may pay the additional fee by reducing change outputs or adding inputs, when necessary. It may add a new change output if one does not already exist. These changes may potentially leak privacy.</source>
- <context-group purpose="location"><context context-type="linenumber">508</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">511</context></context-group>
</trans-unit>
- <trans-unit id="_msg921">
+ <trans-unit id="_msg938">
<source xml:space="preserve">Confirm fee bump</source>
- <context-group purpose="location"><context context-type="linenumber">511</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">514</context></context-group>
</trans-unit>
- <trans-unit id="_msg922">
+ <trans-unit id="_msg939">
<source xml:space="preserve">Can&apos;t draft transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">533</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">536</context></context-group>
</trans-unit>
- <trans-unit id="_msg923">
+ <trans-unit id="_msg940">
<source xml:space="preserve">PSBT copied</source>
- <context-group purpose="location"><context context-type="linenumber">540</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">543</context></context-group>
</trans-unit>
- <trans-unit id="_msg924">
+ <trans-unit id="_msg941">
<source xml:space="preserve">Can&apos;t sign transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">548</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">551</context></context-group>
</trans-unit>
- <trans-unit id="_msg925">
+ <trans-unit id="_msg942">
<source xml:space="preserve">Could not commit transaction</source>
- <context-group purpose="location"><context context-type="linenumber">553</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">556</context></context-group>
</trans-unit>
- <trans-unit id="_msg926">
+ <trans-unit id="_msg943">
<source xml:space="preserve">Can&apos;t display address</source>
- <context-group purpose="location"><context context-type="linenumber">567</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">570</context></context-group>
</trans-unit>
- <trans-unit id="_msg927">
+ <trans-unit id="_msg944">
<source xml:space="preserve">default wallet</source>
- <context-group purpose="location"><context context-type="linenumber">585</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">588</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../walletview.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="WalletView">
- <trans-unit id="_msg928">
+ <trans-unit id="_msg945">
<source xml:space="preserve">&amp;Export</source>
- <context-group purpose="location"><context context-type="linenumber">52</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">51</context></context-group>
</trans-unit>
- <trans-unit id="_msg929">
+ <trans-unit id="_msg946">
<source xml:space="preserve">Export the data in the current tab to a file</source>
- <context-group purpose="location"><context context-type="linenumber">53</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">52</context></context-group>
</trans-unit>
- <trans-unit id="_msg930">
+ <trans-unit id="_msg947">
<source xml:space="preserve">Backup Wallet</source>
- <context-group purpose="location"><context context-type="linenumber">217</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
</trans-unit>
- <trans-unit id="_msg931">
+ <trans-unit id="_msg948">
<source xml:space="preserve">Wallet Data</source>
- <context-group purpose="location"><context context-type="linenumber">219</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
<note annotates="source" from="developer">Name of the wallet data file format.</note>
</trans-unit>
- <trans-unit id="_msg932">
+ <trans-unit id="_msg949">
<source xml:space="preserve">Backup Failed</source>
- <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
</trans-unit>
- <trans-unit id="_msg933">
+ <trans-unit id="_msg950">
<source xml:space="preserve">There was an error trying to save the wallet data to %1.</source>
- <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
</trans-unit>
- <trans-unit id="_msg934">
+ <trans-unit id="_msg951">
<source xml:space="preserve">Backup Successful</source>
- <context-group purpose="location"><context context-type="linenumber">229</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg935">
+ <trans-unit id="_msg952">
<source xml:space="preserve">The wallet data was successfully saved to %1.</source>
- <context-group purpose="location"><context context-type="linenumber">229</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg936">
+ <trans-unit id="_msg953">
<source xml:space="preserve">Cancel</source>
- <context-group purpose="location"><context context-type="linenumber">266</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
</group>
</body></file>
<file original="../bitcoinstrings.cpp" datatype="cpp" source-language="en"><body>
<group restype="x-trolltech-linguist-context" resname="bitcoin-core">
- <trans-unit id="_msg937">
+ <trans-unit id="_msg954">
<source xml:space="preserve">The %s developers</source>
<context-group purpose="location"><context context-type="linenumber">12</context></context-group>
</trans-unit>
- <trans-unit id="_msg938">
+ <trans-unit id="_msg955">
<source xml:space="preserve">%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source>
<context-group purpose="location"><context context-type="linenumber">13</context></context-group>
</trans-unit>
- <trans-unit id="_msg939">
+ <trans-unit id="_msg956">
<source xml:space="preserve">-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">16</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">20</context></context-group>
</trans-unit>
- <trans-unit id="_msg940">
+ <trans-unit id="_msg957">
<source xml:space="preserve">Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source>
- <context-group purpose="location"><context context-type="linenumber">19</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">38</context></context-group>
</trans-unit>
- <trans-unit id="_msg941">
+ <trans-unit id="_msg958">
<source xml:space="preserve">Cannot obtain a lock on data directory %s. %s is probably already running.</source>
- <context-group purpose="location"><context context-type="linenumber">22</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">41</context></context-group>
</trans-unit>
- <trans-unit id="_msg942">
+ <trans-unit id="_msg959">
<source xml:space="preserve">Cannot upgrade a non HD split wallet from version %i to version %i without upgrading to support pre-split keypool. Please use version %i or no version specified.</source>
- <context-group purpose="location"><context context-type="linenumber">27</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">46</context></context-group>
</trans-unit>
- <trans-unit id="_msg943">
+ <trans-unit id="_msg960">
<source xml:space="preserve">Distributed under the MIT software license, see the accompanying file %s or %s</source>
- <context-group purpose="location"><context context-type="linenumber">31</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">50</context></context-group>
</trans-unit>
- <trans-unit id="_msg944">
+ <trans-unit id="_msg961">
<source xml:space="preserve">Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source>
- <context-group purpose="location"><context context-type="linenumber">37</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">56</context></context-group>
</trans-unit>
- <trans-unit id="_msg945">
+ <trans-unit id="_msg962">
<source xml:space="preserve">Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source>
- <context-group purpose="location"><context context-type="linenumber">40</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">59</context></context-group>
</trans-unit>
- <trans-unit id="_msg946">
+ <trans-unit id="_msg963">
<source xml:space="preserve">Error: Dumpfile format record is incorrect. Got &quot;%s&quot;, expected &quot;format&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">43</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">62</context></context-group>
</trans-unit>
- <trans-unit id="_msg947">
+ <trans-unit id="_msg964">
<source xml:space="preserve">Error: Dumpfile identifier record is incorrect. Got &quot;%s&quot;, expected &quot;%s&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">45</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">64</context></context-group>
</trans-unit>
- <trans-unit id="_msg948">
+ <trans-unit id="_msg965">
<source xml:space="preserve">Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source>
- <context-group purpose="location"><context context-type="linenumber">47</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">66</context></context-group>
</trans-unit>
- <trans-unit id="_msg949">
+ <trans-unit id="_msg966">
<source xml:space="preserve">Error: Legacy wallets only support the &quot;legacy&quot;, &quot;p2sh-segwit&quot;, and &quot;bech32&quot; address types</source>
- <context-group purpose="location"><context context-type="linenumber">50</context></context-group>
- </trans-unit>
- <trans-unit id="_msg950">
- <source xml:space="preserve">Error: Listening for incoming connections failed (listen returned error %s)</source>
- <context-group purpose="location"><context context-type="linenumber">53</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">69</context></context-group>
</trans-unit>
- <trans-unit id="_msg951">
+ <trans-unit id="_msg967">
<source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source>
- <context-group purpose="location"><context context-type="linenumber">55</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">75</context></context-group>
</trans-unit>
- <trans-unit id="_msg952">
+ <trans-unit id="_msg968">
<source xml:space="preserve">File %s already exists. If you are sure this is what you want, move it out of the way first.</source>
- <context-group purpose="location"><context context-type="linenumber">58</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">78</context></context-group>
</trans-unit>
- <trans-unit id="_msg953">
+ <trans-unit id="_msg969">
<source xml:space="preserve">Invalid amount for -maxtxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least the minrelay fee of %s to prevent stuck transactions)</source>
- <context-group purpose="location"><context context-type="linenumber">61</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">81</context></context-group>
</trans-unit>
- <trans-unit id="_msg954">
+ <trans-unit id="_msg970">
<source xml:space="preserve">Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source>
- <context-group purpose="location"><context context-type="linenumber">64</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">84</context></context-group>
</trans-unit>
- <trans-unit id="_msg955">
+ <trans-unit id="_msg971">
<source xml:space="preserve">More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source>
- <context-group purpose="location"><context context-type="linenumber">68</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">88</context></context-group>
</trans-unit>
- <trans-unit id="_msg956">
+ <trans-unit id="_msg972">
<source xml:space="preserve">No dump file provided. To use createfromdump, -dumpfile=&lt;filename&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">71</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">91</context></context-group>
</trans-unit>
- <trans-unit id="_msg957">
+ <trans-unit id="_msg973">
<source xml:space="preserve">No dump file provided. To use dump, -dumpfile=&lt;filename&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">74</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">94</context></context-group>
</trans-unit>
- <trans-unit id="_msg958">
+ <trans-unit id="_msg974">
<source xml:space="preserve">No wallet file format provided. To use createfromdump, -format=&lt;format&gt; must be provided.</source>
- <context-group purpose="location"><context context-type="linenumber">76</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
</trans-unit>
- <trans-unit id="_msg959">
+ <trans-unit id="_msg975">
+ <source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided (no -proxy= and no -onion= given) or it is explicitly forbidden (-onion=0)</source>
+ <context-group purpose="location"><context context-type="linenumber">99</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg976">
<source xml:space="preserve">Please check that your computer&apos;s date and time are correct! If your clock is wrong, %s will not work properly.</source>
- <context-group purpose="location"><context context-type="linenumber">79</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">103</context></context-group>
</trans-unit>
- <trans-unit id="_msg960">
+ <trans-unit id="_msg977">
<source xml:space="preserve">Please contribute if you find %s useful. Visit %s for further information about the software.</source>
- <context-group purpose="location"><context context-type="linenumber">82</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">106</context></context-group>
</trans-unit>
- <trans-unit id="_msg961">
+ <trans-unit id="_msg978">
<source xml:space="preserve">Prune configured below the minimum of %d MiB. Please use a higher number.</source>
- <context-group purpose="location"><context context-type="linenumber">85</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">109</context></context-group>
</trans-unit>
- <trans-unit id="_msg962">
+ <trans-unit id="_msg979">
+ <source xml:space="preserve">Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source>
+ <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg980">
<source xml:space="preserve">Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source>
- <context-group purpose="location"><context context-type="linenumber">87</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">114</context></context-group>
</trans-unit>
- <trans-unit id="_msg963">
+ <trans-unit id="_msg981">
<source xml:space="preserve">SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source>
- <context-group purpose="location"><context context-type="linenumber">90</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">117</context></context-group>
</trans-unit>
- <trans-unit id="_msg964">
+ <trans-unit id="_msg982">
<source xml:space="preserve">The block database contains a block which appears to be from the future. This may be due to your computer&apos;s date and time being set incorrectly. Only rebuild the block database if you are sure that your computer&apos;s date and time are correct</source>
- <context-group purpose="location"><context context-type="linenumber">96</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">123</context></context-group>
</trans-unit>
- <trans-unit id="_msg965">
+ <trans-unit id="_msg983">
<source xml:space="preserve">The block index db contains a legacy &apos;txindex&apos;. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source>
- <context-group purpose="location"><context context-type="linenumber">101</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">128</context></context-group>
</trans-unit>
- <trans-unit id="_msg966">
+ <trans-unit id="_msg984">
<source xml:space="preserve">The transaction amount is too small to send after the fee has been deducted</source>
- <context-group purpose="location"><context context-type="linenumber">105</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">132</context></context-group>
</trans-unit>
- <trans-unit id="_msg967">
+ <trans-unit id="_msg985">
<source xml:space="preserve">This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source>
- <context-group purpose="location"><context context-type="linenumber">107</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">134</context></context-group>
</trans-unit>
- <trans-unit id="_msg968">
+ <trans-unit id="_msg986">
<source xml:space="preserve">This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source>
- <context-group purpose="location"><context context-type="linenumber">111</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">138</context></context-group>
</trans-unit>
- <trans-unit id="_msg969">
+ <trans-unit id="_msg987">
<source xml:space="preserve">This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source>
- <context-group purpose="location"><context context-type="linenumber">114</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">141</context></context-group>
</trans-unit>
- <trans-unit id="_msg970">
+ <trans-unit id="_msg988">
<source xml:space="preserve">This is the transaction fee you may discard if change is smaller than dust at this level</source>
- <context-group purpose="location"><context context-type="linenumber">117</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">144</context></context-group>
</trans-unit>
- <trans-unit id="_msg971">
+ <trans-unit id="_msg989">
<source xml:space="preserve">This is the transaction fee you may pay when fee estimates are not available.</source>
- <context-group purpose="location"><context context-type="linenumber">120</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">147</context></context-group>
</trans-unit>
- <trans-unit id="_msg972">
+ <trans-unit id="_msg990">
<source xml:space="preserve">Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source>
- <context-group purpose="location"><context context-type="linenumber">122</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">149</context></context-group>
</trans-unit>
- <trans-unit id="_msg973">
+ <trans-unit id="_msg991">
<source xml:space="preserve">Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source>
- <context-group purpose="location"><context context-type="linenumber">125</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
</trans-unit>
- <trans-unit id="_msg974">
+ <trans-unit id="_msg992">
<source xml:space="preserve">Unknown wallet file format &quot;%s&quot; provided. Please provide one of &quot;bdb&quot; or &quot;sqlite&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">128</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">155</context></context-group>
</trans-unit>
- <trans-unit id="_msg975">
+ <trans-unit id="_msg993">
+ <source xml:space="preserve">Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source>
+ <context-group purpose="location"><context context-type="linenumber">158</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg994">
+ <source xml:space="preserve">Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source>
+ <context-group purpose="location"><context context-type="linenumber">161</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg995">
<source xml:space="preserve">Warning: Dumpfile wallet format &quot;%s&quot; does not match command line specified format &quot;%s&quot;.</source>
- <context-group purpose="location"><context context-type="linenumber">131</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">165</context></context-group>
</trans-unit>
- <trans-unit id="_msg976">
+ <trans-unit id="_msg996">
<source xml:space="preserve">Warning: Private keys detected in wallet {%s} with disabled private keys</source>
- <context-group purpose="location"><context context-type="linenumber">134</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">168</context></context-group>
</trans-unit>
- <trans-unit id="_msg977">
+ <trans-unit id="_msg997">
<source xml:space="preserve">Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source>
- <context-group purpose="location"><context context-type="linenumber">136</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">170</context></context-group>
</trans-unit>
- <trans-unit id="_msg978">
+ <trans-unit id="_msg998">
<source xml:space="preserve">Witness data for blocks after height %d requires validation. Please restart with -reindex.</source>
- <context-group purpose="location"><context context-type="linenumber">139</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">173</context></context-group>
</trans-unit>
- <trans-unit id="_msg979">
+ <trans-unit id="_msg999">
<source xml:space="preserve">You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
- <context-group purpose="location"><context context-type="linenumber">142</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">176</context></context-group>
</trans-unit>
- <trans-unit id="_msg980">
+ <trans-unit id="_msg1000">
<source xml:space="preserve">%s is set very high!</source>
- <context-group purpose="location"><context context-type="linenumber">145</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">179</context></context-group>
</trans-unit>
- <trans-unit id="_msg981">
+ <trans-unit id="_msg1001">
<source xml:space="preserve">-maxmempool must be at least %d MB</source>
- <context-group purpose="location"><context context-type="linenumber">146</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">180</context></context-group>
</trans-unit>
- <trans-unit id="_msg982">
+ <trans-unit id="_msg1002">
<source xml:space="preserve">A fatal internal error occurred, see debug.log for details</source>
- <context-group purpose="location"><context context-type="linenumber">147</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">181</context></context-group>
</trans-unit>
- <trans-unit id="_msg983">
+ <trans-unit id="_msg1003">
<source xml:space="preserve">Cannot resolve -%s address: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">148</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">182</context></context-group>
</trans-unit>
- <trans-unit id="_msg984">
+ <trans-unit id="_msg1004">
<source xml:space="preserve">Cannot set -forcednsseed to true when setting -dnsseed to false.</source>
- <context-group purpose="location"><context context-type="linenumber">149</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">183</context></context-group>
</trans-unit>
- <trans-unit id="_msg985">
+ <trans-unit id="_msg1005">
<source xml:space="preserve">Cannot set -peerblockfilters without -blockfilterindex.</source>
- <context-group purpose="location"><context context-type="linenumber">150</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">184</context></context-group>
</trans-unit>
- <trans-unit id="_msg986">
+ <trans-unit id="_msg1006">
<source xml:space="preserve">Cannot write to data directory &apos;%s&apos;; check permissions.</source>
- <context-group purpose="location"><context context-type="linenumber">151</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">185</context></context-group>
</trans-unit>
- <trans-unit id="_msg987">
+ <trans-unit id="_msg1007">
<source xml:space="preserve">The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source>
- <context-group purpose="location"><context context-type="linenumber">93</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">120</context></context-group>
</trans-unit>
- <trans-unit id="_msg988">
+ <trans-unit id="_msg1008">
+ <source xml:space="preserve">%s request to listen on port %u. This port is considered &quot;bad&quot; and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source>
+ <context-group purpose="location"><context context-type="linenumber">16</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1009">
+ <source xml:space="preserve">-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <context-group purpose="location"><context context-type="linenumber">23</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1010">
+ <source xml:space="preserve">-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <context-group purpose="location"><context context-type="linenumber">27</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1011">
+ <source xml:space="preserve">-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source>
+ <context-group purpose="location"><context context-type="linenumber">31</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1012">
+ <source xml:space="preserve">Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source>
+ <context-group purpose="location"><context context-type="linenumber">35</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1013">
<source xml:space="preserve">Cannot provide specific connections and have addrman find outgoing connections at the same time.</source>
- <context-group purpose="location"><context context-type="linenumber">24</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">43</context></context-group>
</trans-unit>
- <trans-unit id="_msg989">
+ <trans-unit id="_msg1014">
<source xml:space="preserve">Error loading %s: External signer wallet being loaded without external signer support compiled</source>
- <context-group purpose="location"><context context-type="linenumber">34</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">53</context></context-group>
</trans-unit>
- <trans-unit id="_msg990">
+ <trans-unit id="_msg1015">
+ <source xml:space="preserve">Failed to rename invalid peers.dat file. Please move or delete it and try again.</source>
+ <context-group purpose="location"><context context-type="linenumber">72</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1016">
<source xml:space="preserve">Config setting for %s only applied on %s network when in [%s] section.</source>
- <context-group purpose="location"><context context-type="linenumber">152</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">186</context></context-group>
</trans-unit>
- <trans-unit id="_msg991">
+ <trans-unit id="_msg1017">
<source xml:space="preserve">Copyright (C) %i-%i</source>
- <context-group purpose="location"><context context-type="linenumber">153</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">187</context></context-group>
</trans-unit>
- <trans-unit id="_msg992">
+ <trans-unit id="_msg1018">
<source xml:space="preserve">Corrupted block database detected</source>
- <context-group purpose="location"><context context-type="linenumber">154</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">188</context></context-group>
</trans-unit>
- <trans-unit id="_msg993">
+ <trans-unit id="_msg1019">
<source xml:space="preserve">Could not find asmap file %s</source>
- <context-group purpose="location"><context context-type="linenumber">155</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">189</context></context-group>
</trans-unit>
- <trans-unit id="_msg994">
+ <trans-unit id="_msg1020">
<source xml:space="preserve">Could not parse asmap file %s</source>
- <context-group purpose="location"><context context-type="linenumber">156</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">190</context></context-group>
</trans-unit>
- <trans-unit id="_msg995">
+ <trans-unit id="_msg1021">
<source xml:space="preserve">Disk space is too low!</source>
- <context-group purpose="location"><context context-type="linenumber">157</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">191</context></context-group>
</trans-unit>
- <trans-unit id="_msg996">
+ <trans-unit id="_msg1022">
<source xml:space="preserve">Do you want to rebuild the block database now?</source>
- <context-group purpose="location"><context context-type="linenumber">158</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">192</context></context-group>
</trans-unit>
- <trans-unit id="_msg997">
+ <trans-unit id="_msg1023">
<source xml:space="preserve">Done loading</source>
- <context-group purpose="location"><context context-type="linenumber">159</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">193</context></context-group>
</trans-unit>
- <trans-unit id="_msg998">
+ <trans-unit id="_msg1024">
<source xml:space="preserve">Dump file %s does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">160</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">194</context></context-group>
</trans-unit>
- <trans-unit id="_msg999">
+ <trans-unit id="_msg1025">
<source xml:space="preserve">Error creating %s</source>
- <context-group purpose="location"><context context-type="linenumber">161</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">195</context></context-group>
</trans-unit>
- <trans-unit id="_msg1000">
+ <trans-unit id="_msg1026">
<source xml:space="preserve">Error initializing block database</source>
- <context-group purpose="location"><context context-type="linenumber">162</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">196</context></context-group>
</trans-unit>
- <trans-unit id="_msg1001">
+ <trans-unit id="_msg1027">
<source xml:space="preserve">Error initializing wallet database environment %s!</source>
- <context-group purpose="location"><context context-type="linenumber">163</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">197</context></context-group>
</trans-unit>
- <trans-unit id="_msg1002">
+ <trans-unit id="_msg1028">
<source xml:space="preserve">Error loading %s</source>
- <context-group purpose="location"><context context-type="linenumber">164</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">198</context></context-group>
</trans-unit>
- <trans-unit id="_msg1003">
+ <trans-unit id="_msg1029">
<source xml:space="preserve">Error loading %s: Private keys can only be disabled during creation</source>
- <context-group purpose="location"><context context-type="linenumber">165</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">199</context></context-group>
</trans-unit>
- <trans-unit id="_msg1004">
+ <trans-unit id="_msg1030">
<source xml:space="preserve">Error loading %s: Wallet corrupted</source>
- <context-group purpose="location"><context context-type="linenumber">166</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">200</context></context-group>
</trans-unit>
- <trans-unit id="_msg1005">
+ <trans-unit id="_msg1031">
<source xml:space="preserve">Error loading %s: Wallet requires newer version of %s</source>
- <context-group purpose="location"><context context-type="linenumber">167</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">201</context></context-group>
</trans-unit>
- <trans-unit id="_msg1006">
+ <trans-unit id="_msg1032">
<source xml:space="preserve">Error loading block database</source>
- <context-group purpose="location"><context context-type="linenumber">168</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">202</context></context-group>
</trans-unit>
- <trans-unit id="_msg1007">
+ <trans-unit id="_msg1033">
<source xml:space="preserve">Error opening block database</source>
- <context-group purpose="location"><context context-type="linenumber">169</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">203</context></context-group>
</trans-unit>
- <trans-unit id="_msg1008">
+ <trans-unit id="_msg1034">
<source xml:space="preserve">Error reading from database, shutting down.</source>
- <context-group purpose="location"><context context-type="linenumber">170</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">204</context></context-group>
</trans-unit>
- <trans-unit id="_msg1009">
+ <trans-unit id="_msg1035">
<source xml:space="preserve">Error reading next record from wallet database</source>
- <context-group purpose="location"><context context-type="linenumber">171</context></context-group>
- </trans-unit>
- <trans-unit id="_msg1010">
- <source xml:space="preserve">Error upgrading chainstate database</source>
- <context-group purpose="location"><context context-type="linenumber">172</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">205</context></context-group>
</trans-unit>
- <trans-unit id="_msg1011">
+ <trans-unit id="_msg1036">
<source xml:space="preserve">Error: Couldn&apos;t create cursor into database</source>
- <context-group purpose="location"><context context-type="linenumber">173</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
</trans-unit>
- <trans-unit id="_msg1012">
+ <trans-unit id="_msg1037">
<source xml:space="preserve">Error: Disk space is low for %s</source>
- <context-group purpose="location"><context context-type="linenumber">174</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">207</context></context-group>
</trans-unit>
- <trans-unit id="_msg1013">
+ <trans-unit id="_msg1038">
<source xml:space="preserve">Error: Dumpfile checksum does not match. Computed %s, expected %s</source>
- <context-group purpose="location"><context context-type="linenumber">175</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">208</context></context-group>
</trans-unit>
- <trans-unit id="_msg1014">
+ <trans-unit id="_msg1039">
<source xml:space="preserve">Error: Got key that was not hex: %s</source>
- <context-group purpose="location"><context context-type="linenumber">176</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">209</context></context-group>
</trans-unit>
- <trans-unit id="_msg1015">
+ <trans-unit id="_msg1040">
<source xml:space="preserve">Error: Got value that was not hex: %s</source>
- <context-group purpose="location"><context context-type="linenumber">177</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">210</context></context-group>
</trans-unit>
- <trans-unit id="_msg1016">
+ <trans-unit id="_msg1041">
<source xml:space="preserve">Error: Keypool ran out, please call keypoolrefill first</source>
- <context-group purpose="location"><context context-type="linenumber">178</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">211</context></context-group>
</trans-unit>
- <trans-unit id="_msg1017">
+ <trans-unit id="_msg1042">
<source xml:space="preserve">Error: Missing checksum</source>
- <context-group purpose="location"><context context-type="linenumber">179</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">212</context></context-group>
</trans-unit>
- <trans-unit id="_msg1018">
+ <trans-unit id="_msg1043">
<source xml:space="preserve">Error: No %s addresses available.</source>
- <context-group purpose="location"><context context-type="linenumber">180</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
</trans-unit>
- <trans-unit id="_msg1019">
+ <trans-unit id="_msg1044">
<source xml:space="preserve">Error: Unable to parse version %u as a uint32_t</source>
- <context-group purpose="location"><context context-type="linenumber">181</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
</trans-unit>
- <trans-unit id="_msg1020">
+ <trans-unit id="_msg1045">
<source xml:space="preserve">Error: Unable to write record to new wallet</source>
- <context-group purpose="location"><context context-type="linenumber">182</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
</trans-unit>
- <trans-unit id="_msg1021">
+ <trans-unit id="_msg1046">
<source xml:space="preserve">Failed to listen on any port. Use -listen=0 if you want this.</source>
- <context-group purpose="location"><context context-type="linenumber">183</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
</trans-unit>
- <trans-unit id="_msg1022">
+ <trans-unit id="_msg1047">
<source xml:space="preserve">Failed to rescan the wallet during initialization</source>
- <context-group purpose="location"><context context-type="linenumber">184</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">217</context></context-group>
</trans-unit>
- <trans-unit id="_msg1023">
+ <trans-unit id="_msg1048">
<source xml:space="preserve">Failed to verify database</source>
- <context-group purpose="location"><context context-type="linenumber">185</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
</trans-unit>
- <trans-unit id="_msg1024">
+ <trans-unit id="_msg1049">
<source xml:space="preserve">Fee rate (%s) is lower than the minimum fee rate setting (%s)</source>
- <context-group purpose="location"><context context-type="linenumber">186</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">219</context></context-group>
</trans-unit>
- <trans-unit id="_msg1025">
+ <trans-unit id="_msg1050">
<source xml:space="preserve">Ignoring duplicate -wallet %s.</source>
- <context-group purpose="location"><context context-type="linenumber">187</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">220</context></context-group>
</trans-unit>
- <trans-unit id="_msg1026">
+ <trans-unit id="_msg1051">
<source xml:space="preserve">Importing…</source>
- <context-group purpose="location"><context context-type="linenumber">188</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
</trans-unit>
- <trans-unit id="_msg1027">
+ <trans-unit id="_msg1052">
<source xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</source>
- <context-group purpose="location"><context context-type="linenumber">189</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
</trans-unit>
- <trans-unit id="_msg1028">
+ <trans-unit id="_msg1053">
<source xml:space="preserve">Initialization sanity check failed. %s is shutting down.</source>
- <context-group purpose="location"><context context-type="linenumber">190</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">223</context></context-group>
</trans-unit>
- <trans-unit id="_msg1029">
+ <trans-unit id="_msg1054">
<source xml:space="preserve">Input not found or already spent</source>
- <context-group purpose="location"><context context-type="linenumber">191</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">224</context></context-group>
</trans-unit>
- <trans-unit id="_msg1030">
+ <trans-unit id="_msg1055">
<source xml:space="preserve">Insufficient funds</source>
- <context-group purpose="location"><context context-type="linenumber">192</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
</trans-unit>
- <trans-unit id="_msg1031">
+ <trans-unit id="_msg1056">
<source xml:space="preserve">Invalid -i2psam address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">193</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
</trans-unit>
- <trans-unit id="_msg1032">
+ <trans-unit id="_msg1057">
<source xml:space="preserve">Invalid -onion address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">194</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">227</context></context-group>
</trans-unit>
- <trans-unit id="_msg1033">
+ <trans-unit id="_msg1058">
<source xml:space="preserve">Invalid -proxy address or hostname: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">195</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">228</context></context-group>
</trans-unit>
- <trans-unit id="_msg1034">
+ <trans-unit id="_msg1059">
<source xml:space="preserve">Invalid P2P permission: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">196</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">229</context></context-group>
</trans-unit>
- <trans-unit id="_msg1035">
+ <trans-unit id="_msg1060">
<source xml:space="preserve">Invalid amount for -%s=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">197</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">230</context></context-group>
</trans-unit>
- <trans-unit id="_msg1036">
+ <trans-unit id="_msg1061">
<source xml:space="preserve">Invalid amount for -discardfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">198</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">231</context></context-group>
</trans-unit>
- <trans-unit id="_msg1037">
+ <trans-unit id="_msg1062">
<source xml:space="preserve">Invalid amount for -fallbackfee=&lt;amount&gt;: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">199</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">232</context></context-group>
</trans-unit>
- <trans-unit id="_msg1038">
+ <trans-unit id="_msg1063">
<source xml:space="preserve">Invalid amount for -paytxfee=&lt;amount&gt;: &apos;%s&apos; (must be at least %s)</source>
- <context-group purpose="location"><context context-type="linenumber">200</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">233</context></context-group>
</trans-unit>
- <trans-unit id="_msg1039">
+ <trans-unit id="_msg1064">
<source xml:space="preserve">Invalid netmask specified in -whitelist: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">201</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">234</context></context-group>
</trans-unit>
- <trans-unit id="_msg1040">
+ <trans-unit id="_msg1065">
+ <source xml:space="preserve">Listening for incoming connections failed (listen returned error %s)</source>
+ <context-group purpose="location"><context context-type="linenumber">235</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1066">
<source xml:space="preserve">Loading P2P addresses…</source>
- <context-group purpose="location"><context context-type="linenumber">202</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">236</context></context-group>
</trans-unit>
- <trans-unit id="_msg1041">
+ <trans-unit id="_msg1067">
<source xml:space="preserve">Loading banlist…</source>
- <context-group purpose="location"><context context-type="linenumber">203</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">237</context></context-group>
</trans-unit>
- <trans-unit id="_msg1042">
+ <trans-unit id="_msg1068">
<source xml:space="preserve">Loading block index…</source>
- <context-group purpose="location"><context context-type="linenumber">204</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">238</context></context-group>
</trans-unit>
- <trans-unit id="_msg1043">
+ <trans-unit id="_msg1069">
<source xml:space="preserve">Loading wallet…</source>
- <context-group purpose="location"><context context-type="linenumber">205</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">239</context></context-group>
</trans-unit>
- <trans-unit id="_msg1044">
+ <trans-unit id="_msg1070">
<source xml:space="preserve">Missing amount</source>
- <context-group purpose="location"><context context-type="linenumber">206</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
</trans-unit>
- <trans-unit id="_msg1045">
+ <trans-unit id="_msg1071">
<source xml:space="preserve">Missing solving data for estimating transaction size</source>
- <context-group purpose="location"><context context-type="linenumber">207</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">241</context></context-group>
</trans-unit>
- <trans-unit id="_msg1046">
+ <trans-unit id="_msg1072">
<source xml:space="preserve">Need to specify a port with -whitebind: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">208</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">242</context></context-group>
</trans-unit>
- <trans-unit id="_msg1047">
+ <trans-unit id="_msg1073">
<source xml:space="preserve">No addresses available</source>
- <context-group purpose="location"><context context-type="linenumber">209</context></context-group>
- </trans-unit>
- <trans-unit id="_msg1048">
- <source xml:space="preserve">No proxy server specified. Use -proxy=&lt;ip&gt; or -proxy=&lt;ip:port&gt;.</source>
- <context-group purpose="location"><context context-type="linenumber">210</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">243</context></context-group>
</trans-unit>
- <trans-unit id="_msg1049">
+ <trans-unit id="_msg1074">
<source xml:space="preserve">Not enough file descriptors available.</source>
- <context-group purpose="location"><context context-type="linenumber">211</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">244</context></context-group>
</trans-unit>
- <trans-unit id="_msg1050">
+ <trans-unit id="_msg1075">
<source xml:space="preserve">Prune cannot be configured with a negative value.</source>
- <context-group purpose="location"><context context-type="linenumber">212</context></context-group>
- </trans-unit>
- <trans-unit id="_msg1051">
- <source xml:space="preserve">Prune mode is incompatible with -coinstatsindex.</source>
- <context-group purpose="location"><context context-type="linenumber">213</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">245</context></context-group>
</trans-unit>
- <trans-unit id="_msg1052">
+ <trans-unit id="_msg1076">
<source xml:space="preserve">Prune mode is incompatible with -txindex.</source>
- <context-group purpose="location"><context context-type="linenumber">214</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">246</context></context-group>
</trans-unit>
- <trans-unit id="_msg1053">
+ <trans-unit id="_msg1077">
<source xml:space="preserve">Pruning blockstore…</source>
- <context-group purpose="location"><context context-type="linenumber">215</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">247</context></context-group>
</trans-unit>
- <trans-unit id="_msg1054">
+ <trans-unit id="_msg1078">
<source xml:space="preserve">Reducing -maxconnections from %d to %d, because of system limitations.</source>
- <context-group purpose="location"><context context-type="linenumber">216</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">248</context></context-group>
</trans-unit>
- <trans-unit id="_msg1055">
+ <trans-unit id="_msg1079">
<source xml:space="preserve">Replaying blocks…</source>
- <context-group purpose="location"><context context-type="linenumber">217</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">249</context></context-group>
</trans-unit>
- <trans-unit id="_msg1056">
+ <trans-unit id="_msg1080">
<source xml:space="preserve">Rescanning…</source>
- <context-group purpose="location"><context context-type="linenumber">218</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">250</context></context-group>
</trans-unit>
- <trans-unit id="_msg1057">
+ <trans-unit id="_msg1081">
<source xml:space="preserve">SQLiteDatabase: Failed to execute statement to verify database: %s</source>
- <context-group purpose="location"><context context-type="linenumber">219</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">251</context></context-group>
</trans-unit>
- <trans-unit id="_msg1058">
+ <trans-unit id="_msg1082">
<source xml:space="preserve">SQLiteDatabase: Failed to prepare statement to verify database: %s</source>
- <context-group purpose="location"><context context-type="linenumber">220</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">252</context></context-group>
</trans-unit>
- <trans-unit id="_msg1059">
+ <trans-unit id="_msg1083">
<source xml:space="preserve">SQLiteDatabase: Failed to read database verification error: %s</source>
- <context-group purpose="location"><context context-type="linenumber">221</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
</trans-unit>
- <trans-unit id="_msg1060">
+ <trans-unit id="_msg1084">
<source xml:space="preserve">SQLiteDatabase: Unexpected application id. Expected %u, got %u</source>
- <context-group purpose="location"><context context-type="linenumber">222</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">254</context></context-group>
</trans-unit>
- <trans-unit id="_msg1061">
+ <trans-unit id="_msg1085">
<source xml:space="preserve">Section [%s] is not recognized.</source>
- <context-group purpose="location"><context context-type="linenumber">223</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">255</context></context-group>
</trans-unit>
- <trans-unit id="_msg1062">
+ <trans-unit id="_msg1086">
<source xml:space="preserve">Signing transaction failed</source>
- <context-group purpose="location"><context context-type="linenumber">224</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">256</context></context-group>
</trans-unit>
- <trans-unit id="_msg1063">
+ <trans-unit id="_msg1087">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; does not exist</source>
- <context-group purpose="location"><context context-type="linenumber">225</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
</trans-unit>
- <trans-unit id="_msg1064">
+ <trans-unit id="_msg1088">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; is a relative path</source>
- <context-group purpose="location"><context context-type="linenumber">226</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">258</context></context-group>
</trans-unit>
- <trans-unit id="_msg1065">
+ <trans-unit id="_msg1089">
<source xml:space="preserve">Specified -walletdir &quot;%s&quot; is not a directory</source>
- <context-group purpose="location"><context context-type="linenumber">227</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">259</context></context-group>
</trans-unit>
- <trans-unit id="_msg1066">
+ <trans-unit id="_msg1090">
<source xml:space="preserve">Specified blocks directory &quot;%s&quot; does not exist.</source>
- <context-group purpose="location"><context context-type="linenumber">228</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
</trans-unit>
- <trans-unit id="_msg1067">
+ <trans-unit id="_msg1091">
<source xml:space="preserve">Starting network threads…</source>
- <context-group purpose="location"><context context-type="linenumber">229</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
</trans-unit>
- <trans-unit id="_msg1068">
+ <trans-unit id="_msg1092">
<source xml:space="preserve">The source code is available from %s.</source>
- <context-group purpose="location"><context context-type="linenumber">230</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
</trans-unit>
- <trans-unit id="_msg1069">
+ <trans-unit id="_msg1093">
<source xml:space="preserve">The specified config file %s does not exist</source>
- <context-group purpose="location"><context context-type="linenumber">231</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">263</context></context-group>
</trans-unit>
- <trans-unit id="_msg1070">
+ <trans-unit id="_msg1094">
<source xml:space="preserve">The transaction amount is too small to pay the fee</source>
- <context-group purpose="location"><context context-type="linenumber">232</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">264</context></context-group>
</trans-unit>
- <trans-unit id="_msg1071">
+ <trans-unit id="_msg1095">
<source xml:space="preserve">The wallet will avoid paying less than the minimum relay fee.</source>
- <context-group purpose="location"><context context-type="linenumber">233</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">265</context></context-group>
</trans-unit>
- <trans-unit id="_msg1072">
+ <trans-unit id="_msg1096">
<source xml:space="preserve">This is experimental software.</source>
- <context-group purpose="location"><context context-type="linenumber">234</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">266</context></context-group>
</trans-unit>
- <trans-unit id="_msg1073">
+ <trans-unit id="_msg1097">
<source xml:space="preserve">This is the minimum transaction fee you pay on every transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">235</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">267</context></context-group>
</trans-unit>
- <trans-unit id="_msg1074">
+ <trans-unit id="_msg1098">
<source xml:space="preserve">This is the transaction fee you will pay if you send a transaction.</source>
- <context-group purpose="location"><context context-type="linenumber">236</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">268</context></context-group>
</trans-unit>
- <trans-unit id="_msg1075">
+ <trans-unit id="_msg1099">
<source xml:space="preserve">Transaction amount too small</source>
- <context-group purpose="location"><context context-type="linenumber">237</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">269</context></context-group>
</trans-unit>
- <trans-unit id="_msg1076">
+ <trans-unit id="_msg1100">
<source xml:space="preserve">Transaction amounts must not be negative</source>
- <context-group purpose="location"><context context-type="linenumber">238</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">270</context></context-group>
</trans-unit>
- <trans-unit id="_msg1077">
+ <trans-unit id="_msg1101">
<source xml:space="preserve">Transaction change output index out of range</source>
- <context-group purpose="location"><context context-type="linenumber">239</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">271</context></context-group>
</trans-unit>
- <trans-unit id="_msg1078">
+ <trans-unit id="_msg1102">
<source xml:space="preserve">Transaction has too long of a mempool chain</source>
- <context-group purpose="location"><context context-type="linenumber">240</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">272</context></context-group>
</trans-unit>
- <trans-unit id="_msg1079">
+ <trans-unit id="_msg1103">
<source xml:space="preserve">Transaction must have at least one recipient</source>
- <context-group purpose="location"><context context-type="linenumber">241</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">273</context></context-group>
</trans-unit>
- <trans-unit id="_msg1080">
+ <trans-unit id="_msg1104">
<source xml:space="preserve">Transaction needs a change address, but we can&apos;t generate it.</source>
- <context-group purpose="location"><context context-type="linenumber">242</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">274</context></context-group>
</trans-unit>
- <trans-unit id="_msg1081">
+ <trans-unit id="_msg1105">
<source xml:space="preserve">Transaction too large</source>
- <context-group purpose="location"><context context-type="linenumber">243</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">275</context></context-group>
</trans-unit>
- <trans-unit id="_msg1082">
+ <trans-unit id="_msg1106">
+ <source xml:space="preserve">Unable to allocate memory for -maxsigcachesize: &apos;%s&apos; MiB</source>
+ <context-group purpose="location"><context context-type="linenumber">276</context></context-group>
+ </trans-unit>
+ <trans-unit id="_msg1107">
<source xml:space="preserve">Unable to bind to %s on this computer (bind returned error %s)</source>
- <context-group purpose="location"><context context-type="linenumber">244</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">277</context></context-group>
</trans-unit>
- <trans-unit id="_msg1083">
+ <trans-unit id="_msg1108">
<source xml:space="preserve">Unable to bind to %s on this computer. %s is probably already running.</source>
- <context-group purpose="location"><context context-type="linenumber">245</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">278</context></context-group>
</trans-unit>
- <trans-unit id="_msg1084">
+ <trans-unit id="_msg1109">
<source xml:space="preserve">Unable to create the PID file &apos;%s&apos;: %s</source>
- <context-group purpose="location"><context context-type="linenumber">246</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">279</context></context-group>
</trans-unit>
- <trans-unit id="_msg1085">
+ <trans-unit id="_msg1110">
<source xml:space="preserve">Unable to generate initial keys</source>
- <context-group purpose="location"><context context-type="linenumber">247</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">280</context></context-group>
</trans-unit>
- <trans-unit id="_msg1086">
+ <trans-unit id="_msg1111">
<source xml:space="preserve">Unable to generate keys</source>
- <context-group purpose="location"><context context-type="linenumber">248</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">281</context></context-group>
</trans-unit>
- <trans-unit id="_msg1087">
+ <trans-unit id="_msg1112">
<source xml:space="preserve">Unable to open %s for writing</source>
- <context-group purpose="location"><context context-type="linenumber">249</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">282</context></context-group>
</trans-unit>
- <trans-unit id="_msg1088">
+ <trans-unit id="_msg1113">
<source xml:space="preserve">Unable to parse -maxuploadtarget: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">250</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">283</context></context-group>
</trans-unit>
- <trans-unit id="_msg1089">
+ <trans-unit id="_msg1114">
<source xml:space="preserve">Unable to start HTTP server. See debug log for details.</source>
- <context-group purpose="location"><context context-type="linenumber">251</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">284</context></context-group>
</trans-unit>
- <trans-unit id="_msg1090">
+ <trans-unit id="_msg1115">
<source xml:space="preserve">Unknown -blockfilterindex value %s.</source>
- <context-group purpose="location"><context context-type="linenumber">252</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">285</context></context-group>
</trans-unit>
- <trans-unit id="_msg1091">
+ <trans-unit id="_msg1116">
<source xml:space="preserve">Unknown address type &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">253</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">286</context></context-group>
</trans-unit>
- <trans-unit id="_msg1092">
+ <trans-unit id="_msg1117">
<source xml:space="preserve">Unknown change type &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">254</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">287</context></context-group>
</trans-unit>
- <trans-unit id="_msg1093">
+ <trans-unit id="_msg1118">
<source xml:space="preserve">Unknown network specified in -onlynet: &apos;%s&apos;</source>
- <context-group purpose="location"><context context-type="linenumber">255</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">288</context></context-group>
</trans-unit>
- <trans-unit id="_msg1094">
+ <trans-unit id="_msg1119">
<source xml:space="preserve">Unknown new rules activated (versionbit %i)</source>
- <context-group purpose="location"><context context-type="linenumber">256</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">289</context></context-group>
</trans-unit>
- <trans-unit id="_msg1095">
+ <trans-unit id="_msg1120">
<source xml:space="preserve">Unsupported logging category %s=%s.</source>
- <context-group purpose="location"><context context-type="linenumber">257</context></context-group>
- </trans-unit>
- <trans-unit id="_msg1096">
- <source xml:space="preserve">Upgrading UTXO database</source>
- <context-group purpose="location"><context context-type="linenumber">258</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">290</context></context-group>
</trans-unit>
- <trans-unit id="_msg1097">
+ <trans-unit id="_msg1121">
<source xml:space="preserve">User Agent comment (%s) contains unsafe characters.</source>
- <context-group purpose="location"><context context-type="linenumber">259</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">291</context></context-group>
</trans-unit>
- <trans-unit id="_msg1098">
+ <trans-unit id="_msg1122">
<source xml:space="preserve">Verifying blocks…</source>
- <context-group purpose="location"><context context-type="linenumber">260</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">292</context></context-group>
</trans-unit>
- <trans-unit id="_msg1099">
+ <trans-unit id="_msg1123">
<source xml:space="preserve">Verifying wallet(s)…</source>
- <context-group purpose="location"><context context-type="linenumber">261</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">293</context></context-group>
</trans-unit>
- <trans-unit id="_msg1100">
+ <trans-unit id="_msg1124">
<source xml:space="preserve">Wallet needed to be rewritten: restart %s to complete</source>
- <context-group purpose="location"><context context-type="linenumber">262</context></context-group>
+ <context-group purpose="location"><context context-type="linenumber">294</context></context-group>
</trans-unit>
</group>
</body></file>
diff --git a/src/qt/main.cpp b/src/qt/main.cpp
index 38b0ac71a3..e8f39584ad 100644
--- a/src/qt/main.cpp
+++ b/src/qt/main.cpp
@@ -4,7 +4,7 @@
#include <qt/bitcoin.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <util/translation.h>
#include <util/url.h>
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 42c8b07763..2b6711ca40 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -19,6 +19,7 @@
#include <validation.h> // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
#include <netbase.h>
#include <txdb.h> // for -dbcache defaults
+#include <util/system.h>
#include <chrono>
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index a8133f481e..85a3c36f39 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -147,8 +147,6 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
{
ui->setupUi(this);
- m_balances.balance = -1;
-
// use a SingleColorIcon for the "out of sync warning" icon
QIcon icon = m_platform_style->SingleColorIcon(QStringLiteral(":/icons/warning"));
ui->labelTransactionsStatus->setIcon(icon);
@@ -177,8 +175,9 @@ void OverviewPage::handleTransactionClicked(const QModelIndex &index)
void OverviewPage::setPrivacy(bool privacy)
{
m_privacy = privacy;
- if (m_balances.balance != -1) {
- setBalance(m_balances);
+ const auto& balances = walletModel->getCachedBalance();
+ if (balances.balance != -1) {
+ setBalance(balances);
}
ui->listTransactions->setVisible(!m_privacy);
@@ -197,7 +196,6 @@ OverviewPage::~OverviewPage()
void OverviewPage::setBalance(const interfaces::WalletBalances& balances)
{
BitcoinUnit unit = walletModel->getOptionsModel()->getDisplayUnit();
- m_balances = balances;
if (walletModel->wallet().isLegacy()) {
if (walletModel->wallet().privateKeysDisabled()) {
ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.watch_only_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy));
@@ -276,14 +274,13 @@ void OverviewPage::setWalletModel(WalletModel *model)
ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress);
// Keep up to date with wallet
- interfaces::Wallet& wallet = model->wallet();
- interfaces::WalletBalances balances = wallet.getBalances();
- setBalance(balances);
+ setBalance(model->getCachedBalance());
connect(model, &WalletModel::balanceChanged, this, &OverviewPage::setBalance);
connect(model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &OverviewPage::updateDisplayUnit);
- updateWatchOnlyLabels(wallet.haveWatchOnly() && !model->wallet().privateKeysDisabled());
+ interfaces::Wallet& wallet = model->wallet();
+ updateWatchOnlyLabels(wallet.haveWatchOnly() && !wallet.privateKeysDisabled());
connect(model, &WalletModel::notifyWatchonlyChanged, [this](bool showWatchOnly) {
updateWatchOnlyLabels(showWatchOnly && !walletModel->wallet().privateKeysDisabled());
});
@@ -306,10 +303,10 @@ void OverviewPage::changeEvent(QEvent* e)
void OverviewPage::updateDisplayUnit()
{
- if(walletModel && walletModel->getOptionsModel())
- {
- if (m_balances.balance != -1) {
- setBalance(m_balances);
+ if (walletModel && walletModel->getOptionsModel()) {
+ const auto& balances = walletModel->getCachedBalance();
+ if (balances.balance != -1) {
+ setBalance(balances);
}
// Update txdelegate->unit with the current unit
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 058df1a8c5..56f45907db 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -52,7 +52,6 @@ private:
Ui::OverviewPage *ui;
ClientModel *clientModel;
WalletModel *walletModel;
- interfaces::WalletBalances m_balances;
bool m_privacy{false};
const PlatformStyle* m_platform_style;
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index b791fd30c4..70fccdef1c 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -1162,7 +1162,6 @@ void RPCConsole::updateDetailWidget()
if (!stats->nodeStats.addrLocal.empty())
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
ui->peerHeading->setText(peerAddrDetails);
- ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStats.nServices));
QString bip152_hb_settings;
if (stats->nodeStats.m_bip152_highbandwidth_to) bip152_hb_settings = ts.to;
if (stats->nodeStats.m_bip152_highbandwidth_from) bip152_hb_settings += (bip152_hb_settings.isEmpty() ? ts.from : QLatin1Char('/') + ts.from);
@@ -1197,6 +1196,7 @@ void RPCConsole::updateDetailWidget()
// This check fails for example if the lock was busy and
// nodeStateStats couldn't be fetched.
if (stats->fNodeStateStatsAvailable) {
+ ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStateStats.their_services));
// Sync height is init to -1
if (stats->nodeStateStats.nSyncHeight > -1) {
ui->peerSyncHeight->setText(QString("%1").arg(stats->nodeStateStats.nSyncHeight));
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index bd44d12781..a75c1098a5 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -164,11 +164,9 @@ void SendCoinsDialog::setModel(WalletModel *_model)
}
}
- interfaces::WalletBalances balances = _model->wallet().getBalances();
- setBalance(balances);
connect(_model, &WalletModel::balanceChanged, this, &SendCoinsDialog::setBalance);
- connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::updateDisplayUnit);
- updateDisplayUnit();
+ connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::refreshBalance);
+ refreshBalance();
// Coin Control
connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
@@ -711,9 +709,9 @@ void SendCoinsDialog::setBalance(const interfaces::WalletBalances& balances)
}
}
-void SendCoinsDialog::updateDisplayUnit()
+void SendCoinsDialog::refreshBalance()
{
- setBalance(model->wallet().getBalances());
+ setBalance(model->getCachedBalance());
ui->customFee->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
updateSmartFeeLabel();
}
@@ -786,7 +784,7 @@ void SendCoinsDialog::useAvailableBalance(SendCoinsEntry* entry)
m_coin_control->fAllowWatchOnly = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner();
// Calculate available amount to send.
- CAmount amount = model->wallet().getAvailableBalance(*m_coin_control);
+ CAmount amount = model->getAvailableBalance(m_coin_control.get());
for (int i = 0; i < ui->entries->count(); ++i) {
SendCoinsEntry* e = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
if (e && !e->isHidden() && e != entry) {
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index 400503d0c0..b58d4690a0 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -97,7 +97,7 @@ private Q_SLOTS:
void on_buttonMinimizeFee_clicked();
void removeEntry(SendCoinsEntry* entry);
void useAvailableBalance(SendCoinsEntry* entry);
- void updateDisplayUnit();
+ void refreshBalance();
void coinControlFeatureChanged(bool);
void coinControlButtonClicked();
void coinControlChangeChecked(int);
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index de23f51c92..846fa519ee 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -43,8 +43,6 @@ Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin)
#endif
#endif
-using node::NodeContext;
-
const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{};
diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp
index b8ae62ecab..7e39829038 100644
--- a/src/qt/test/wallettests.cpp
+++ b/src/qt/test/wallettests.cpp
@@ -129,6 +129,13 @@ void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, st
QVERIFY(text.indexOf(QString::fromStdString(expectError)) != -1);
}
+void CompareBalance(WalletModel& walletModel, CAmount expected_balance, QLabel* balance_label_to_check)
+{
+ BitcoinUnit unit = walletModel.getOptionsModel()->getDisplayUnit();
+ QString balanceComparison = BitcoinUnits::formatWithUnit(unit, expected_balance, false, BitcoinUnits::SeparatorStyle::ALWAYS);
+ QCOMPARE(balance_label_to_check->text().trimmed(), balanceComparison);
+}
+
//! Simple qt wallet tests.
//
// Test widgets can be debugged interactively calling show() on them and
@@ -195,15 +202,10 @@ void TestGUI(interfaces::Node& node)
sendCoinsDialog.setModel(&walletModel);
transactionView.setModel(&walletModel);
- {
- // Check balance in send dialog
- QLabel* balanceLabel = sendCoinsDialog.findChild<QLabel*>("labelBalance");
- QString balanceText = balanceLabel->text();
- BitcoinUnit unit = walletModel.getOptionsModel()->getDisplayUnit();
- CAmount balance = walletModel.wallet().getBalance();
- QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::SeparatorStyle::ALWAYS);
- QCOMPARE(balanceText, balanceComparison);
- }
+ // Update walletModel cached balance which will trigger an update for the 'labelBalance' QLabel.
+ walletModel.pollBalanceChanged();
+ // Check balance in send dialog
+ CompareBalance(walletModel, walletModel.wallet().getBalance(), sendCoinsDialog.findChild<QLabel*>("labelBalance"));
// Send two transactions, and verify they are added to transaction list.
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
@@ -223,12 +225,8 @@ void TestGUI(interfaces::Node& node)
// Check current balance on OverviewPage
OverviewPage overviewPage(platformStyle.get());
overviewPage.setWalletModel(&walletModel);
- QLabel* balanceLabel = overviewPage.findChild<QLabel*>("labelBalance");
- QString balanceText = balanceLabel->text().trimmed();
- BitcoinUnit unit = walletModel.getOptionsModel()->getDisplayUnit();
- CAmount balance = walletModel.wallet().getBalance();
- QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::SeparatorStyle::ALWAYS);
- QCOMPARE(balanceText, balanceComparison);
+ walletModel.pollBalanceChanged(); // Manual balance polling update
+ CompareBalance(walletModel, walletModel.wallet().getBalance(), overviewPage.findChild<QLabel*>("labelBalance"));
// Check Request Payment button
ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get());
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index 01d84624e8..8762ba9ab3 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -262,9 +262,13 @@ void CreateWalletActivity::createWallet()
}
QTimer::singleShot(500ms, worker(), [this, name, flags] {
- std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().createWallet(name, m_passphrase, flags, m_error_message, m_warning_message);
+ auto wallet{node().walletLoader().createWallet(name, m_passphrase, flags, m_warning_message)};
- if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
+ if (wallet) {
+ m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet));
+ } else {
+ m_error_message = util::ErrorString(wallet);
+ }
QTimer::singleShot(500ms, this, &CreateWalletActivity::finish);
});
@@ -293,6 +297,10 @@ void CreateWalletActivity::create()
} catch (const std::runtime_error& e) {
QMessageBox::critical(nullptr, tr("Can't list signers"), e.what());
}
+ if (signers.size() > 1) {
+ QMessageBox::critical(nullptr, tr("Too many external signers found"), QString::fromStdString("More than one external signer found. Please connect only one at a time."));
+ signers.clear();
+ }
m_create_wallet_dialog->setSigners(signers);
m_create_wallet_dialog->setWindowModality(Qt::ApplicationModal);
@@ -343,9 +351,13 @@ void OpenWalletActivity::open(const std::string& path)
tr("Opening Wallet <b>%1</b>…").arg(name.toHtmlEscaped()));
QTimer::singleShot(0, worker(), [this, path] {
- std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().loadWallet(path, m_error_message, m_warning_message);
+ auto wallet{node().walletLoader().loadWallet(path, m_warning_message)};
- if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
+ if (wallet) {
+ m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet));
+ } else {
+ m_error_message = util::ErrorString(wallet);
+ }
QTimer::singleShot(0, this, &OpenWalletActivity::finish);
});
@@ -393,8 +405,11 @@ void RestoreWalletActivity::restore(const fs::path& backup_file, const std::stri
QTimer::singleShot(0, worker(), [this, backup_file, wallet_name] {
auto wallet{node().walletLoader().restoreWallet(backup_file, wallet_name, m_warning_message)};
- m_error_message = wallet ? bilingual_str{} : wallet.GetError();
- if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(wallet.ReleaseObj());
+ if (wallet) {
+ m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet));
+ } else {
+ m_error_message = util::ErrorString(wallet);
+ }
QTimer::singleShot(0, this, &RestoreWalletActivity::finish);
});
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 6b38e207d3..8dc97e66a2 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -213,6 +213,14 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard)
}
std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary};
data.assign(std::istream_iterator<unsigned char>{in}, {});
+
+ // Some psbt files may be base64 strings in the file rather than binary data
+ std::string b64_str{data.begin(), data.end()};
+ b64_str.erase(b64_str.find_last_not_of(" \t\n\r\f\v") + 1); // Trim trailing whitespace
+ auto b64_dec = DecodeBase64(b64_str);
+ if (b64_dec.has_value()) {
+ data = b64_dec.value();
+ }
}
std::string error;
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index bb6079afee..c6f3f5b00c 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -67,6 +67,10 @@ WalletModel::~WalletModel()
void WalletModel::startPollBalance()
{
+ // Update the cached balance right away, so every view can make use of it,
+ // so them don't need to waste resources recalculating it.
+ pollBalanceChanged();
+
// This timer will be fired repeatedly to update the balance
// Since the QTimer::timeout is a private signal, it cannot be used
// in the GUIUtil::ExceptionSafeConnect directly.
@@ -120,12 +124,17 @@ void WalletModel::pollBalanceChanged()
void WalletModel::checkBalanceChanged(const interfaces::WalletBalances& new_balances)
{
- if(new_balances.balanceChanged(m_cached_balances)) {
+ if (new_balances.balanceChanged(m_cached_balances)) {
m_cached_balances = new_balances;
Q_EMIT balanceChanged(new_balances);
}
}
+interfaces::WalletBalances WalletModel::getCachedBalance() const
+{
+ return m_cached_balances;
+}
+
void WalletModel::updateTransaction()
{
// Balance and number of transactions might have changed
@@ -194,7 +203,9 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
return DuplicateAddress;
}
- CAmount nBalance = m_wallet->getAvailableBalance(coinControl);
+ // If no coin was manually selected, use the cached balance
+ // Future: can merge this call with 'createTransaction'.
+ CAmount nBalance = getAvailableBalance(&coinControl);
if(total > nBalance)
{
@@ -207,7 +218,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
auto& newTx = transaction.getWtx();
const auto& res = m_wallet->createTransaction(vecSend, coinControl, !wallet().privateKeysDisabled() /* sign */, nChangePosRet, nFeeRequired);
- newTx = res ? res.GetObj() : nullptr;
+ newTx = res ? *res : nullptr;
transaction.setTransactionFee(nFeeRequired);
if (fSubtractFeeFromAmount && newTx)
transaction.reassignAmounts(nChangePosRet);
@@ -218,7 +229,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
{
return SendCoinsReturn(AmountWithFeeExceedsBalance);
}
- Q_EMIT message(tr("Send Coins"), QString::fromStdString(res.GetError().translated),
+ Q_EMIT message(tr("Send Coins"), QString::fromStdString(util::ErrorString(res).translated),
CClientUIInterface::MSG_ERROR);
return TransactionCreationFailed;
}
@@ -306,6 +317,11 @@ WalletModel::EncryptionStatus WalletModel::getEncryptionStatus() const
{
if(!m_wallet->isCrypted())
{
+ // A previous bug allowed for watchonly wallets to be encrypted (encryption keys set, but nothing is actually encrypted).
+ // To avoid misrepresenting the encryption status of such wallets, we only return NoKeys for watchonly wallets that are unencrypted.
+ if (m_wallet->privateKeysDisabled()) {
+ return NoKeys;
+ }
return Unencrypted;
}
else if(m_wallet->isLocked())
@@ -597,3 +613,8 @@ uint256 WalletModel::getLastBlockProcessed() const
{
return m_client_model ? m_client_model->getBestBlockHash() : uint256{};
}
+
+CAmount WalletModel::getAvailableBalance(const CCoinControl* control)
+{
+ return control && control->HasSelected() ? wallet().getAvailableBalance(*control) : getCachedBalance().balance;
+}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index a52290dee8..73dfe0386a 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -71,6 +71,7 @@ public:
enum EncryptionStatus
{
+ NoKeys, // wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)
Unencrypted, // !wallet->IsCrypted()
Locked, // wallet->IsCrypted() && wallet->IsLocked()
Unlocked // wallet->IsCrypted() && !wallet->IsLocked()
@@ -154,6 +155,13 @@ public:
uint256 getLastBlockProcessed() const;
+ // Retrieve the cached wallet balance
+ interfaces::WalletBalances getCachedBalance() const;
+
+ // If coin control has selected outputs, searches the total amount inside the wallet.
+ // Otherwise, uses the wallet's cached available balance.
+ CAmount getAvailableBalance(const wallet::CCoinControl* control);
+
private:
std::unique_ptr<interfaces::Wallet> m_wallet;
std::unique_ptr<interfaces::Handler> m_handler_unload;
diff --git a/src/random.cpp b/src/random.cpp
index fca4b5041a..f92e679a00 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -10,7 +10,7 @@
#include <crypto/sha512.h>
#include <support/cleanse.h>
#ifdef WIN32
-#include <compat.h> // for Windows API
+#include <compat/compat.h>
#include <wincrypt.h>
#endif
#include <logging.h>
diff --git a/src/random.h b/src/random.h
index b92c29f0be..5fe20c5f76 100644
--- a/src/random.h
+++ b/src/random.h
@@ -11,6 +11,7 @@
#include <span.h>
#include <uint256.h>
+#include <cassert>
#include <chrono>
#include <cstdint>
#include <limits>
@@ -236,13 +237,19 @@ public:
template <typename Tp>
Tp rand_uniform_delay(const Tp& time, typename Tp::duration range)
{
- using Dur = typename Tp::duration;
- Dur dur{range.count() > 0 ? /* interval [0..range) */ Dur{randrange(range.count())} :
- range.count() < 0 ? /* interval (range..0] */ -Dur{randrange(-range.count())} :
- /* interval [0..0] */ Dur{0}};
- return time + dur;
+ return time + rand_uniform_duration<Tp>(range);
}
+ /** Generate a uniform random duration in the range from 0 (inclusive) to range (exclusive). */
+ template <typename Chrono>
+ typename Chrono::duration rand_uniform_duration(typename Chrono::duration range) noexcept
+ {
+ using Dur = typename Chrono::duration;
+ return range.count() > 0 ? /* interval [0..range) */ Dur{randrange(range.count())} :
+ range.count() < 0 ? /* interval (range..0] */ -Dur{randrange(-range.count())} :
+ /* interval [0..0] */ Dur{0};
+ };
+
// Compatibility with the C++11 UniformRandomBitGenerator concept
typedef uint64_t result_type;
static constexpr uint64_t min() { return 0; }
diff --git a/src/randomenv.cpp b/src/randomenv.cpp
index c5dca346d6..9e58180b7a 100644
--- a/src/randomenv.cpp
+++ b/src/randomenv.cpp
@@ -15,7 +15,7 @@
#include <support/cleanse.h>
#include <util/time.h> // for GetTime()
#ifdef WIN32
-#include <compat.h> // for Windows API
+#include <compat/compat.h>
#endif
#include <algorithm>
diff --git a/src/rest.cpp b/src/rest.cpp
index 43c248b03b..85815a9c8b 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -590,45 +590,31 @@ static bool rest_chaininfo(const std::any& context, HTTPRequest* req, const std:
}
}
-static bool rest_mempool_info(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
+static bool rest_mempool(const std::any& context, HTTPRequest* req, const std::string& str_uri_part)
{
if (!CheckWarmup(req))
return false;
- const CTxMemPool* mempool = GetMemPool(context, req);
- if (!mempool) return false;
- std::string param;
- const RESTResponseFormat rf = ParseDataFormat(param, strURIPart);
-
- switch (rf) {
- case RESTResponseFormat::JSON: {
- UniValue mempoolInfoObject = MempoolInfoToJSON(*mempool);
- std::string strJSON = mempoolInfoObject.write() + "\n";
- req->WriteHeader("Content-Type", "application/json");
- req->WriteReply(HTTP_OK, strJSON);
- return true;
- }
- default: {
- return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
- }
+ std::string param;
+ const RESTResponseFormat rf = ParseDataFormat(param, str_uri_part);
+ if (param != "contents" && param != "info") {
+ return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/mempool/<info|contents>.json");
}
-}
-static bool rest_mempool_contents(const std::any& context, HTTPRequest* req, const std::string& strURIPart)
-{
- if (!CheckWarmup(req)) return false;
const CTxMemPool* mempool = GetMemPool(context, req);
if (!mempool) return false;
- std::string param;
- const RESTResponseFormat rf = ParseDataFormat(param, strURIPart);
switch (rf) {
case RESTResponseFormat::JSON: {
- UniValue mempoolObject = MempoolToJSON(*mempool, true);
+ std::string str_json;
+ if (param == "contents") {
+ str_json = MempoolToJSON(*mempool, true).write() + "\n";
+ } else {
+ str_json = MempoolInfoToJSON(*mempool).write() + "\n";
+ }
- std::string strJSON = mempoolObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
- req->WriteReply(HTTP_OK, strJSON);
+ req->WriteReply(HTTP_OK, str_json);
return true;
}
default: {
@@ -946,8 +932,7 @@ static const struct {
{"/rest/blockfilter/", rest_block_filter},
{"/rest/blockfilterheaders/", rest_filter_header},
{"/rest/chaininfo", rest_chaininfo},
- {"/rest/mempool/info", rest_mempool_info},
- {"/rest/mempool/contents", rest_mempool_contents},
+ {"/rest/mempool/", rest_mempool},
{"/rest/headers/", rest_headers},
{"/rest/getutxos", rest_getutxos},
{"/rest/blockhashbyheight/", rest_blockhash_by_height},
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index b80cdce3f0..8f116a05ef 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -39,6 +39,7 @@
#include <univalue.h>
#include <util/check.h>
#include <util/strencodings.h>
+#include <util/system.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
@@ -396,7 +397,7 @@ static RPCHelpMan syncwithvalidationinterfacequeue()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
SyncWithValidationInterfaceQueue();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -613,11 +614,12 @@ const RPCResult getblock_vin{
{
{RPCResult::Type::BOOL, "generated", "Coinbase or not"},
{RPCResult::Type::NUM, "height", "The height of the prevout"},
- {RPCResult::Type::NUM, "value", "The value in " + CURRENCY_UNIT},
+ {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT},
{RPCResult::Type::OBJ, "scriptPubKey", "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
+ {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
{RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
{RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
}},
@@ -1014,9 +1016,9 @@ static RPCHelpMan gettxout()
{RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
{RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
{RPCResult::Type::OBJ, "scriptPubKey", "", {
- {RPCResult::Type::STR, "asm", ""},
+ {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
{RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
- {RPCResult::Type::STR_HEX, "hex", ""},
+ {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
{RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
}},
@@ -1054,11 +1056,11 @@ static RPCHelpMan gettxout()
LOCK(mempool.cs);
CCoinsViewMemPool view(coins_view, mempool);
if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
- return NullUniValue;
+ return UniValue::VNULL;
}
} else {
if (!coins_view->GetCoin(out, coin)) {
- return NullUniValue;
+ return UniValue::VNULL;
}
}
@@ -1496,7 +1498,7 @@ static RPCHelpMan preciousblock()
throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -1537,7 +1539,7 @@ static RPCHelpMan invalidateblock()
throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -1577,7 +1579,7 @@ static RPCHelpMan reconsiderblock()
throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -2096,7 +2098,7 @@ static RPCHelpMan scantxoutset()
CoinsViewScanReserver reserver;
if (reserver.reserve()) {
// no scan in progress
- return NullUniValue;
+ return UniValue::VNULL;
}
result.pushKV("progress", g_scan_progress.load());
return result;
@@ -2306,7 +2308,7 @@ static RPCHelpMan dumptxoutset()
}
FILE* file{fsbridge::fopen(temppath, "wb")};
- CAutoFile afile{file, SER_DISK, CLIENT_VERSION};
+ AutoFile afile{file};
if (afile.IsNull()) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
@@ -2327,7 +2329,7 @@ static RPCHelpMan dumptxoutset()
UniValue CreateUTXOSnapshot(
NodeContext& node,
CChainState& chainstate,
- CAutoFile& afile,
+ AutoFile& afile,
const fs::path& path,
const fs::path& temppath)
{
diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h
index 5fbd9d5fd3..a332fd4892 100644
--- a/src/rpc/blockchain.h
+++ b/src/rpc/blockchain.h
@@ -55,7 +55,7 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES],
UniValue CreateUTXOSnapshot(
node::NodeContext& node,
CChainState& chainstate,
- CAutoFile& afile,
+ AutoFile& afile,
const fs::path& path,
const fs::path& tmppath);
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp
index fcc19649af..612dbbdacf 100644
--- a/src/rpc/client.cpp
+++ b/src/rpc/client.cpp
@@ -148,6 +148,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "sendall", 1, "conf_target" },
{ "sendall", 3, "fee_rate"},
{ "sendall", 4, "options" },
+ { "simulaterawtransaction", 0, "rawtxs" },
+ { "simulaterawtransaction", 1, "options" },
{ "importprivkey", 2, "rescan" },
{ "importaddress", 2, "rescan" },
{ "importaddress", 3, "p2sh" },
diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp
index dd1a6441a0..aa047bdea8 100644
--- a/src/rpc/fees.cpp
+++ b/src/rpc/fees.cpp
@@ -6,8 +6,6 @@
#include <core_io.h>
#include <policy/feerate.h>
#include <policy/fees.h>
-#include <policy/policy.h>
-#include <policy/settings.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <rpc/server.h>
@@ -16,7 +14,6 @@
#include <txmempool.h>
#include <univalue.h>
#include <util/fees.h>
-#include <util/system.h>
#include <algorithm>
#include <array>
@@ -90,7 +87,7 @@ static RPCHelpMan estimatesmartfee()
CFeeRate feeRate{fee_estimator.estimateSmartFee(conf_target, &feeCalc, conservative)};
if (feeRate != CFeeRate(0)) {
CFeeRate min_mempool_feerate{mempool.GetMinFee()};
- CFeeRate min_relay_feerate{::minRelayTxFee};
+ CFeeRate min_relay_feerate{mempool.m_min_relay_feerate};
feeRate = std::max({feeRate, min_mempool_feerate, min_relay_feerate});
result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
} else {
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index 84d43e7818..02b51ce0a0 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -5,9 +5,12 @@
#include <rpc/blockchain.h>
+#include <kernel/mempool_persist.h>
+
#include <chainparams.h>
#include <core_io.h>
#include <fs.h>
+#include <node/mempool_persist_args.h>
#include <policy/rbf.h>
#include <policy/settings.h>
#include <primitives/transaction.h>
@@ -17,8 +20,12 @@
#include <txmempool.h>
#include <univalue.h>
#include <util/moneystr.h>
+#include <util/time.h>
+
+using kernel::DumpMempool;
using node::DEFAULT_MAX_RAW_TX_FEE_RATE;
+using node::MempoolPath;
using node::NodeContext;
static RPCHelpMan sendrawtransaction()
@@ -653,15 +660,15 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool)
// Make sure this call is atomic in the pool.
LOCK(pool.cs);
UniValue ret(UniValue::VOBJ);
- ret.pushKV("loaded", pool.IsLoaded());
+ ret.pushKV("loaded", pool.GetLoadTried());
ret.pushKV("size", (int64_t)pool.size());
ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
ret.pushKV("maxmempool", pool.m_max_size_bytes);
- ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), ::minRelayTxFee).GetFeePerK()));
- ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
- ret.pushKV("incrementalrelayfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK()));
+ ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), pool.m_min_relay_feerate).GetFeePerK()));
+ ret.pushKV("minrelaytxfee", ValueFromAmount(pool.m_min_relay_feerate.GetFeePerK()));
+ ret.pushKV("incrementalrelayfee", ValueFromAmount(pool.m_incremental_relay_feerate.GetFeePerK()));
ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
ret.pushKV("fullrbf", pool.m_full_rbf);
return ret;
@@ -717,16 +724,18 @@ static RPCHelpMan savemempool()
const ArgsManager& args{EnsureAnyArgsman(request.context)};
const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
- if (!mempool.IsLoaded()) {
+ if (!mempool.GetLoadTried()) {
throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
}
- if (!DumpMempool(mempool)) {
+ const fs::path& dump_path = MempoolPath(args);
+
+ if (!DumpMempool(mempool, dump_path)) {
throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
}
UniValue ret(UniValue::VOBJ);
- ret.pushKV("filename", fs::path((args.GetDataDirNet() / "mempool.dat")).u8string());
+ ret.pushKV("filename", dump_path.u8string());
return ret;
},
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index ea6db1e9a0..2902b35865 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -476,7 +476,7 @@ static RPCHelpMan prioritisetransaction()
static UniValue BIP22ValidationResult(const BlockValidationState& state)
{
if (state.IsValid())
- return NullUniValue;
+ return UniValue::VNULL;
if (state.IsError())
throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
@@ -1040,7 +1040,7 @@ static RPCHelpMan submitheader()
BlockValidationState state;
chainman.ProcessNewBlockHeaders({h}, state);
- if (state.IsValid()) return NullUniValue;
+ if (state.IsValid()) return UniValue::VNULL;
if (state.IsError()) {
throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
}
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index fad92629c5..3b234bc317 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -23,6 +23,7 @@
#include <timedata.h>
#include <util/strencodings.h>
#include <util/string.h>
+#include <util/time.h>
#include <util/translation.h>
#include <validation.h>
#include <version.h>
@@ -60,7 +61,7 @@ static RPCHelpMan getconnectioncount()
NodeContext& node = EnsureAnyNodeContext(request.context);
const CConnman& connman = EnsureConnman(node);
- return (int)connman.GetNodeCount(ConnectionDirection::Both);
+ return connman.GetNodeCount(ConnectionDirection::Both);
},
};
}
@@ -84,7 +85,7 @@ static RPCHelpMan ping()
// Request that each node send a ping during next message processing pass
peerman.SendPings();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -195,8 +196,9 @@ static RPCHelpMan getpeerinfo()
if (stats.m_mapped_as != 0) {
obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as));
}
- obj.pushKV("services", strprintf("%016x", stats.nServices));
- obj.pushKV("servicesnames", GetServicesNames(stats.nServices));
+ ServiceFlags services{fStateStats ? statestats.their_services : ServiceFlags::NODE_NONE};
+ obj.pushKV("services", strprintf("%016x", services));
+ obj.pushKV("servicesnames", GetServicesNames(services));
obj.pushKV("lastsend", count_seconds(stats.m_last_send));
obj.pushKV("lastrecv", count_seconds(stats.m_last_recv));
obj.pushKV("last_transaction", count_seconds(stats.m_last_tx_time));
@@ -303,7 +305,7 @@ static RPCHelpMan addnode()
{
CAddress addr;
connman.OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL);
- return NullUniValue;
+ return UniValue::VNULL;
}
if (strCommand == "add")
@@ -319,7 +321,7 @@ static RPCHelpMan addnode()
}
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -422,7 +424,7 @@ static RPCHelpMan disconnectnode()
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -639,13 +641,16 @@ static RPCHelpMan getnetworkinfo()
obj.pushKV("timeoffset", GetTimeOffset());
if (node.connman) {
obj.pushKV("networkactive", node.connman->GetNetworkActive());
- obj.pushKV("connections", (int)node.connman->GetNodeCount(ConnectionDirection::Both));
- obj.pushKV("connections_in", (int)node.connman->GetNodeCount(ConnectionDirection::In));
- obj.pushKV("connections_out", (int)node.connman->GetNodeCount(ConnectionDirection::Out));
+ obj.pushKV("connections", node.connman->GetNodeCount(ConnectionDirection::Both));
+ obj.pushKV("connections_in", node.connman->GetNodeCount(ConnectionDirection::In));
+ obj.pushKV("connections_out", node.connman->GetNodeCount(ConnectionDirection::Out));
}
obj.pushKV("networks", GetNetworksInfo());
- obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
- obj.pushKV("incrementalfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK()));
+ if (node.mempool) {
+ // Those fields can be deprecated, to be replaced by the getmempoolinfo fields
+ obj.pushKV("relayfee", ValueFromAmount(node.mempool->m_min_relay_feerate.GetFeePerK()));
+ obj.pushKV("incrementalfee", ValueFromAmount(node.mempool->m_incremental_relay_feerate.GetFeePerK()));
+ }
UniValue localAddresses(UniValue::VARR);
{
LOCK(g_maplocalhost_mutex);
@@ -744,7 +749,7 @@ static RPCHelpMan setban()
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously manually banned.");
}
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -818,7 +823,7 @@ static RPCHelpMan clearbanned()
node.banman->ClearBanned();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -893,7 +898,7 @@ static RPCHelpMan getnodeaddresses()
for (const CAddress& addr : vAddr) {
UniValue obj(UniValue::VOBJ);
- obj.pushKV("time", (int)addr.nTime);
+ obj.pushKV("time", int64_t{TicksSinceEpoch<std::chrono::seconds>(addr.nTime)});
obj.pushKV("services", (uint64_t)addr.nServices);
obj.pushKV("address", addr.ToStringIP());
obj.pushKV("port", addr.GetPort());
@@ -941,7 +946,7 @@ static RPCHelpMan addpeeraddress()
if (LookupHost(addr_string, net_addr, false)) {
CAddress address{{net_addr, port}, ServiceFlags{NODE_NETWORK | NODE_WITNESS}};
- address.nTime = GetAdjustedTime();
+ address.nTime = Now<NodeSeconds>();
// The source address is set equal to the address. This is equivalent to the peer
// announcing itself.
if (node.addrman->Add({address}, address)) {
diff --git a/src/rpc/node.cpp b/src/rpc/node.cpp
index 5475662b82..605ebc15a7 100644
--- a/src/rpc/node.cpp
+++ b/src/rpc/node.cpp
@@ -65,7 +65,7 @@ static RPCHelpMan setmocktime()
}
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -85,7 +85,7 @@ static RPCHelpMan invokedisallowedsyscall()
throw std::runtime_error("invokedisallowedsyscall is used for testing only.");
}
TestDisallowedSandboxCall();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -118,7 +118,7 @@ static RPCHelpMan mockscheduler()
CHECK_NONFATAL(node_context->scheduler);
node_context->scheduler->MockForward(std::chrono::seconds(delta_seconds));
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
diff --git a/src/rpc/output_script.cpp b/src/rpc/output_script.cpp
index f4bb76f50f..744f809814 100644
--- a/src/rpc/output_script.cpp
+++ b/src/rpc/output_script.cpp
@@ -26,11 +26,6 @@
#include <tuple>
#include <vector>
-namespace node {
-struct NodeContext;
-}
-using node::NodeContext;
-
static RPCHelpMan validateaddress()
{
return RPCHelpMan{
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 5ca921ae2f..7ffb499330 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -46,12 +46,10 @@
#include <univalue.h>
using node::AnalyzePSBT;
-using node::BroadcastTransaction;
using node::FindCoins;
using node::GetTransaction;
using node::NodeContext;
using node::PSBTAnalysis;
-using node::ReadBlockFromDisk;
static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, CChainState& active_chainstate)
{
@@ -98,8 +96,8 @@ static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
{RPCResult::Type::NUM, "vout", /*optional=*/true, "The output number (if not coinbase transaction)"},
{RPCResult::Type::OBJ, "scriptSig", /*optional=*/true, "The script (if not coinbase transaction)",
{
- {RPCResult::Type::STR, "asm", "asm"},
- {RPCResult::Type::STR_HEX, "hex", "hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the signature script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw signature script bytes, hex-encoded"},
}},
{RPCResult::Type::ARR, "txinwitness", /*optional=*/true, "",
{
@@ -116,9 +114,9 @@ static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
{RPCResult::Type::NUM, "n", "index"},
{RPCResult::Type::OBJ, "scriptPubKey", "",
{
- {RPCResult::Type::STR, "asm", "the asm"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
{RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
- {RPCResult::Type::STR_HEX, "hex", "the hex"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
{RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
}},
@@ -159,7 +157,7 @@ static std::vector<RPCArg> CreateTxDoc()
},
},
{"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
- {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{false}, "Marks this transaction as BIP125-replaceable.\n"
+ {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Marks this transaction as BIP125-replaceable.\n"
"Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
};
}
@@ -304,7 +302,7 @@ static RPCHelpMan createrawtransaction()
}, true
);
- bool rbf = false;
+ std::optional<bool> rbf;
if (!request.params[3].isNull()) {
rbf = request.params[3].isTrue();
}
@@ -694,9 +692,9 @@ const RPCResult decodepsbt_inputs{
{RPCResult::Type::NUM, "amount", "The value in " + CURRENCY_UNIT},
{RPCResult::Type::OBJ, "scriptPubKey", "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
{RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
{RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
}},
@@ -708,14 +706,14 @@ const RPCResult decodepsbt_inputs{
{RPCResult::Type::STR, "sighash", /*optional=*/true, "The sighash type to be used"},
{RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the redeem script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw redeem script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
{RPCResult::Type::OBJ, "witness_script", /*optional=*/true, "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the witness script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw witness script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
{RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "",
@@ -729,8 +727,8 @@ const RPCResult decodepsbt_inputs{
}},
{RPCResult::Type::OBJ, "final_scriptSig", /*optional=*/true, "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the final signature script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw final signature script bytes, hex-encoded"},
}},
{RPCResult::Type::ARR, "final_scriptwitness", /*optional=*/true, "",
{
@@ -814,14 +812,14 @@ const RPCResult decodepsbt_outputs{
{
{RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the redeem script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw redeem script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
{RPCResult::Type::OBJ, "witness_script", /*optional=*/true, "",
{
- {RPCResult::Type::STR, "asm", "The asm"},
- {RPCResult::Type::STR_HEX, "hex", "The hex"},
+ {RPCResult::Type::STR, "asm", "Disassembly of the witness script"},
+ {RPCResult::Type::STR_HEX, "hex", "The raw witness script bytes, hex-encoded"},
{RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
}},
{RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "",
@@ -1453,7 +1451,7 @@ static RPCHelpMan createpsbt()
}, true
);
- bool rbf = false;
+ std::optional<bool> rbf;
if (!request.params[3].isNull()) {
rbf = request.params[3].isTrue();
}
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index 86b5b7e960..b06e9f6e4b 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -21,7 +21,7 @@
#include <util/strencodings.h>
#include <util/translation.h>
-CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf)
+CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, std::optional<bool> rbf)
{
if (outputs_in.isNull()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
@@ -60,7 +60,8 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
uint32_t nSequence;
- if (rbf) {
+
+ if (rbf.value_or(true)) {
nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */
} else if (rawTx.nLockTime) {
nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; /* CTxIn::SEQUENCE_FINAL - 1 */
@@ -132,7 +133,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
}
}
- if (rbf && rawTx.vin.size() > 0 && !SignalsOptInRBF(CTransaction(rawTx))) {
+ if (rbf.has_value() && rbf.value() && rawTx.vin.size() > 0 && !SignalsOptInRBF(CTransaction(rawTx))) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
}
diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h
index c3eb1417f8..9b5c9f08d4 100644
--- a/src/rpc/rawtransaction_util.h
+++ b/src/rpc/rawtransaction_util.h
@@ -7,6 +7,7 @@
#include <map>
#include <string>
+#include <optional>
struct bilingual_str;
class FillableSigningProvider;
@@ -38,6 +39,6 @@ void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const
void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins);
/** Create a transaction from univalue parameters */
-CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf);
+CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, std::optional<bool> rbf);
#endif // BITCOIN_RPC_RAWTRANSACTION_UTIL_H
diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp
index 304c265b31..8595fa78bb 100644
--- a/src/rpc/request.cpp
+++ b/src/rpc/request.cpp
@@ -66,16 +66,16 @@ UniValue JSONRPCError(int code, const std::string& message)
*/
static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
-static const std::string COOKIEAUTH_FILE = ".cookie";
+static const char* const COOKIEAUTH_FILE = ".cookie";
/** Get name of RPC authentication cookie file */
static fs::path GetAuthCookieFile(bool temp=false)
{
- std::string arg = gArgs.GetArg("-rpccookiefile", COOKIEAUTH_FILE);
+ fs::path arg = gArgs.GetPathArg("-rpccookiefile", COOKIEAUTH_FILE);
if (temp) {
arg += ".tmp";
}
- return AbsPathForConfigVal(fs::PathFromString(arg));
+ return AbsPathForConfigVal(arg);
}
bool GenerateAuthCookie(std::string *cookie_out)
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 34a4da74f8..9bcbe1ceef 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -328,7 +328,7 @@ class BIP32PubkeyProvider final : public PubkeyProvider
{
if (!GetExtKey(arg, xprv)) return false;
for (auto entry : m_path) {
- xprv.Derive(xprv, entry);
+ if (!xprv.Derive(xprv, entry)) return false;
if (entry >> 31) {
last_hardened = xprv;
}
@@ -388,14 +388,13 @@ public:
}
} else {
for (auto entry : m_path) {
- der = parent_extkey.Derive(parent_extkey, entry);
- assert(der);
+ if (!parent_extkey.Derive(parent_extkey, entry)) return false;
}
final_extkey = parent_extkey;
if (m_derive == DeriveType::UNHARDENED) der = parent_extkey.Derive(final_extkey, pos);
assert(m_derive != DeriveType::HARDENED);
}
- assert(der);
+ if (!der) return false;
final_info_out = final_info_out_tmp;
key_out = final_extkey.pubkey;
@@ -498,8 +497,8 @@ public:
CExtKey extkey;
CExtKey dummy;
if (!GetDerivedExtKey(arg, extkey, dummy)) return false;
- if (m_derive == DeriveType::UNHARDENED) extkey.Derive(extkey, pos);
- if (m_derive == DeriveType::HARDENED) extkey.Derive(extkey, pos | 0x80000000UL);
+ if (m_derive == DeriveType::UNHARDENED && !extkey.Derive(extkey, pos)) return false;
+ if (m_derive == DeriveType::HARDENED && !extkey.Derive(extkey, pos | 0x80000000UL)) return false;
key = extkey.key;
return true;
}
@@ -1015,6 +1014,24 @@ public:
bool IsSingleType() const final { return true; }
};
+/** A parsed rawtr(...) descriptor. */
+class RawTRDescriptor final : public DescriptorImpl
+{
+protected:
+ std::vector<CScript> MakeScripts(const std::vector<CPubKey>& keys, Span<const CScript> scripts, FlatSigningProvider& out) const override
+ {
+ assert(keys.size() == 1);
+ XOnlyPubKey xpk(keys[0]);
+ if (!xpk.IsFullyValid()) return {};
+ WitnessV1Taproot output{xpk};
+ return Vector(GetScriptForDestination(output));
+ }
+public:
+ RawTRDescriptor(std::unique_ptr<PubkeyProvider> output_key) : DescriptorImpl(Vector(std::move(output_key)), "rawtr") {}
+ std::optional<OutputType> GetOutputType() const override { return OutputType::BECH32M; }
+ bool IsSingleType() const final { return true; }
+};
+
////////////////////////////////////////////////////////////////////////////
// Parser //
////////////////////////////////////////////////////////////////////////////
@@ -1453,6 +1470,16 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const
error = "Can only have tr at top level";
return nullptr;
}
+ if (ctx == ParseScriptContext::TOP && Func("rawtr", expr)) {
+ auto arg = Expr(expr);
+ auto output_key = ParsePubkey(key_exp_index, arg, ParseScriptContext::P2TR, out, error);
+ if (!output_key) return nullptr;
+ ++key_exp_index;
+ return std::make_unique<RawTRDescriptor>(std::move(output_key));
+ } else if (Func("rawtr", expr)) {
+ error = "Can only have rawtr at top level";
+ return nullptr;
+ }
if (ctx == ParseScriptContext::TOP && Func("raw", expr)) {
std::string str(expr.begin(), expr.end());
if (!IsHex(str)) {
@@ -1626,6 +1653,13 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
}
}
}
+ // If the above doesn't work, construct a rawtr() descriptor with just the encoded x-only pubkey.
+ if (pubkey.IsFullyValid()) {
+ auto key = InferXOnlyPubkey(pubkey, ParseScriptContext::P2TR, provider);
+ if (key) {
+ return std::make_unique<RawTRDescriptor>(std::move(key));
+ }
+ }
}
if (ctx == ParseScriptContext::P2WSH) {
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 9f56301377..38bb11aad4 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1342,7 +1342,7 @@ public:
template <class T>
uint256 GetPrevoutsSHA256(const T& txTo)
{
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
for (const auto& txin : txTo.vin) {
ss << txin.prevout;
}
@@ -1353,7 +1353,7 @@ uint256 GetPrevoutsSHA256(const T& txTo)
template <class T>
uint256 GetSequencesSHA256(const T& txTo)
{
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
for (const auto& txin : txTo.vin) {
ss << txin.nSequence;
}
@@ -1364,7 +1364,7 @@ uint256 GetSequencesSHA256(const T& txTo)
template <class T>
uint256 GetOutputsSHA256(const T& txTo)
{
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
for (const auto& txout : txTo.vout) {
ss << txout;
}
@@ -1374,7 +1374,7 @@ uint256 GetOutputsSHA256(const T& txTo)
/** Compute the (single) SHA256 of the concatenation of all amounts spent by a tx. */
uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
{
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
for (const auto& txout : outputs_spent) {
ss << txout.nValue;
}
@@ -1384,7 +1384,7 @@ uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
/** Compute the (single) SHA256 of the concatenation of all scriptPubKeys spent by a tx. */
uint256 GetSpentScriptsSHA256(const std::vector<CTxOut>& outputs_spent)
{
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
for (const auto& txout : outputs_spent) {
ss << txout.scriptPubKey;
}
@@ -1458,9 +1458,9 @@ template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo,
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
-const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash");
-const CHashWriter HASHER_TAPLEAF = TaggedHash("TapLeaf");
-const CHashWriter HASHER_TAPBRANCH = TaggedHash("TapBranch");
+const HashWriter HASHER_TAPSIGHASH{TaggedHash("TapSighash")};
+const HashWriter HASHER_TAPLEAF{TaggedHash("TapLeaf")};
+const HashWriter HASHER_TAPBRANCH{TaggedHash("TapBranch")};
static bool HandleMissingData(MissingDataBehavior mdb)
{
@@ -1499,7 +1499,7 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons
return HandleMissingData(mdb);
}
- CHashWriter ss = HASHER_TAPSIGHASH;
+ HashWriter ss{HASHER_TAPSIGHASH};
// Epoch
static constexpr uint8_t EPOCH = 0;
@@ -1544,7 +1544,7 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons
if (output_type == SIGHASH_SINGLE) {
if (in_pos >= tx_to.vout.size()) return false;
if (!execdata.m_output_hash) {
- CHashWriter sha_single_output(SER_GETHASH, 0);
+ HashWriter sha_single_output{};
sha_single_output << tx_to.vout[in_pos];
execdata.m_output_hash = sha_single_output.GetSHA256();
}
@@ -1587,12 +1587,12 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
hashOutputs = cacheready ? cache->hashOutputs : SHA256Uint256(GetOutputsSHA256(txTo));
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
ss << txTo.vout[nIn];
hashOutputs = ss.GetHash();
}
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
// Version
ss << txTo.nVersion;
// Input prevouts/nSequence (none/all, depending on flags)
@@ -1627,7 +1627,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType);
// Serialize and hash
- CHashWriter ss(SER_GETHASH, 0);
+ HashWriter ss{};
ss << txTmp << nHashType;
return ss.GetHash();
}
@@ -1827,7 +1827,7 @@ static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CS
uint256 ComputeTapleafHash(uint8_t leaf_version, const CScript& script)
{
- return (CHashWriter(HASHER_TAPLEAF) << leaf_version << script).GetSHA256();
+ return (HashWriter{HASHER_TAPLEAF} << leaf_version << script).GetSHA256();
}
uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint256& tapleaf_hash)
@@ -1839,7 +1839,7 @@ uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint25
const int path_len = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
uint256 k = tapleaf_hash;
for (int i = 0; i < path_len; ++i) {
- CHashWriter ss_branch{HASHER_TAPBRANCH};
+ HashWriter ss_branch{HASHER_TAPBRANCH};
Span node{Span{control}.subspan(TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE)};
if (std::lexicographical_compare(k.begin(), k.end(), node.begin(), node.end())) {
ss_branch << k << node;
@@ -1902,7 +1902,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
// Drop annex (this is non-standard; see IsWitnessStandard)
const valtype& annex = SpanPopBack(stack);
- execdata.m_annex_hash = (CHashWriter(SER_GETHASH, 0) << annex).GetSHA256();
+ execdata.m_annex_hash = (HashWriter{} << annex).GetSHA256();
execdata.m_annex_present = true;
} else {
execdata.m_annex_present = false;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index adf454aa15..f91578d684 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -233,9 +233,9 @@ static constexpr size_t TAPROOT_CONTROL_NODE_SIZE = 32;
static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128;
static constexpr size_t TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT;
-extern const CHashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre-fed to it.
-extern const CHashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
-extern const CHashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
+extern const HashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre-fed to it.
+extern const HashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
+extern const HashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
template <class T>
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
diff --git a/src/script/script.h b/src/script/script.h
index 3b799ad637..1e5f694d52 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -588,7 +588,6 @@ CScript BuildScript(Ts&&... inputs)
int cnt{0};
([&ret, &cnt] (Ts&& input) {
- cnt++;
if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<Ts>>, CScript>) {
// If it is a CScript, extend ret with it. Move or copy the first element instead.
if (cnt == 0) {
@@ -600,6 +599,7 @@ CScript BuildScript(Ts&&... inputs)
// Otherwise invoke CScript::operator<<.
ret << input;
}
+ cnt++;
} (std::forward<Ts>(inputs)), ...);
return ret;
diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp
index 4e2acc463a..e507ec7528 100644
--- a/src/script/sigcache.cpp
+++ b/src/script/sigcache.cpp
@@ -14,6 +14,7 @@
#include <algorithm>
#include <mutex>
+#include <optional>
#include <shared_mutex>
#include <vector>
@@ -75,7 +76,7 @@ public:
std::unique_lock<std::shared_mutex> lock(cs_sigcache);
setValid.insert(entry);
}
- uint32_t setup_bytes(size_t n)
+ std::optional<std::pair<uint32_t, size_t>> setup_bytes(size_t n)
{
return setValid.setup_bytes(n);
}
@@ -92,14 +93,15 @@ static CSignatureCache signatureCache;
// To be called once in AppInitMain/BasicTestingSetup to initialize the
// signatureCache.
-void InitSignatureCache()
+bool InitSignatureCache(size_t max_size_bytes)
{
- // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
- // setup_bytes creates the minimum possible cache (2 elements).
- size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetIntArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
- size_t nElems = signatureCache.setup_bytes(nMaxCacheSize);
- LogPrintf("Using %zu MiB out of %zu/2 requested for signature cache, able to store %zu elements\n",
- (nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems);
+ auto setup_results = signatureCache.setup_bytes(max_size_bytes);
+ if (!setup_results) return false;
+
+ const auto [num_elems, approx_size_bytes] = *setup_results;
+ LogPrintf("Using %zu MiB out of %zu MiB requested for signature cache, able to store %zu elements\n",
+ approx_size_bytes >> 20, max_size_bytes >> 20, num_elems);
+ return true;
}
bool CachingTransactionSignatureChecker::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index 1e21d6f340..290955090d 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -10,14 +10,13 @@
#include <span.h>
#include <util/hasher.h>
+#include <optional>
#include <vector>
-// DoS prevention: limit cache size to 32MB (over 1000000 entries on 64-bit
+// DoS prevention: limit cache size to 32MiB (over 1000000 entries on 64-bit
// systems). Due to how we count cache size, actual memory usage is slightly
-// more (~32.25 MB)
-static const unsigned int DEFAULT_MAX_SIG_CACHE_SIZE = 32;
-// Maximum sig cache size allowed
-static const int64_t MAX_MAX_SIG_CACHE_SIZE = 16384;
+// more (~32.25 MiB)
+static constexpr size_t DEFAULT_MAX_SIG_CACHE_BYTES{32 << 20};
class CPubKey;
@@ -33,6 +32,6 @@ public:
bool VerifySchnorrSignature(Span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const override;
};
-void InitSignatureCache();
+[[nodiscard]] bool InitSignatureCache(size_t max_size_bytes);
#endif // BITCOIN_SCRIPT_SIGCACHE_H
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index a3681d26cc..4014ebadbc 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -165,7 +165,7 @@ static bool SignTaprootScript(const SigningProvider& provider, const BaseSignatu
if (leaf_version != TAPROOT_LEAF_TAPSCRIPT) return false;
SigVersion sigversion = SigVersion::TAPSCRIPT;
- uint256 leaf_hash = (CHashWriter(HASHER_TAPLEAF) << uint8_t(leaf_version) << script).GetSHA256();
+ uint256 leaf_hash = (HashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();
// <xonly pubkey> OP_CHECKSIG
if (script.size() == 34 && script[33] == OP_CHECKSIG && script[0] == 0x20) {
@@ -243,6 +243,11 @@ static bool SignTaproot(const SigningProvider& provider, const BaseSignatureCrea
sigdata.taproot_key_path_sig = sig;
}
}
+ if (sigdata.taproot_key_path_sig.size() == 0) {
+ if (creator.CreateSchnorrSig(provider, sig, output, nullptr, nullptr, SigVersion::TAPROOT)) {
+ sigdata.taproot_key_path_sig = sig;
+ }
+ }
if (sigdata.taproot_key_path_sig.size()) {
result = Vector(sigdata.taproot_key_path_sig);
return true;
@@ -627,25 +632,6 @@ public:
const BaseSignatureCreator& DUMMY_SIGNATURE_CREATOR = DummySignatureCreator(32, 32);
const BaseSignatureCreator& DUMMY_MAXIMUM_SIGNATURE_CREATOR = DummySignatureCreator(33, 32);
-bool IsSolvable(const SigningProvider& provider, const CScript& script)
-{
- // This check is to make sure that the script we created can actually be solved for and signed by us
- // if we were to have the private keys. This is just to make sure that the script is valid and that,
- // if found in a transaction, we would still accept and relay that transaction. In particular,
- // it will reject witness outputs that require signing with an uncompressed public key.
- SignatureData sigs;
- // Make sure that STANDARD_SCRIPT_VERIFY_FLAGS includes SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, the most
- // important property this function is designed to test for.
- static_assert(STANDARD_SCRIPT_VERIFY_FLAGS & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, "IsSolvable requires standard script flags to include WITNESS_PUBKEYTYPE");
- if (ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, script, sigs)) {
- // VerifyScript check is just defensive, and should never fail.
- bool verified = VerifyScript(sigs.scriptSig, script, &sigs.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, DUMMY_CHECKER);
- assert(verified);
- return true;
- }
- return false;
-}
-
bool IsSegWitOutput(const SigningProvider& provider, const CScript& script)
{
int version;
diff --git a/src/script/sign.h b/src/script/sign.h
index 5e58272154..958d673b9f 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -97,12 +97,6 @@ bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom,
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
void UpdateInput(CTxIn& input, const SignatureData& data);
-/* Check whether we know how to sign for an output like this, assuming we
- * have all private keys. While this function does not need private keys, the passed
- * provider is used to look up public keys and redeemscripts by hash.
- * Solvability is unrelated to whether we consider this output to be ours. */
-bool IsSolvable(const SigningProvider& provider, const CScript& script);
-
/** Check whether a scriptPubKey is known to be segwit. */
bool IsSegWitOutput(const SigningProvider& provider, const CScript& script);
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index 5d80891485..6101738061 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -16,9 +16,6 @@
typedef std::vector<unsigned char> valtype;
-bool fAcceptDatacarrier = DEFAULT_ACCEPT_DATACARRIER;
-unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
-
CScriptID::CScriptID(const CScript& in) : BaseHash(Hash160(in)) {}
CScriptID::CScriptID(const ScriptHash& in) : BaseHash(static_cast<uint160>(in)) {}
@@ -375,9 +372,9 @@ bool IsValidDestination(const CTxDestination& dest) {
}
/* Lexicographically sort a and b's hash, and compute parent hash. */
if (a.hash < b.hash) {
- ret.hash = (CHashWriter(HASHER_TAPBRANCH) << a.hash << b.hash).GetSHA256();
+ ret.hash = (HashWriter{HASHER_TAPBRANCH} << a.hash << b.hash).GetSHA256();
} else {
- ret.hash = (CHashWriter(HASHER_TAPBRANCH) << b.hash << a.hash).GetSHA256();
+ ret.hash = (HashWriter{HASHER_TAPBRANCH} << b.hash << a.hash).GetSHA256();
}
return ret;
}
@@ -452,7 +449,7 @@ TaprootBuilder& TaprootBuilder::Add(int depth, const CScript& script, int leaf_v
if (!IsValid()) return *this;
/* Construct NodeInfo object with leaf hash and (if track is true) also leaf information. */
NodeInfo node;
- node.hash = (CHashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();
+ node.hash = (HashWriter{HASHER_TAPLEAF} << uint8_t(leaf_version) << script).GetSHA256();
if (track) node.leaves.emplace_back(LeafInfo{script, leaf_version, {}});
/* Insert into the branch. */
Insert(std::move(node), depth);
@@ -610,7 +607,7 @@ std::optional<std::vector<std::tuple<int, CScript, int>>> InferTaprootTree(const
node.done = true;
stack.pop_back();
} else if (node.sub[0]->done && !node.sub[1]->done && !node.sub[1]->explored && !node.sub[1]->hash.IsNull() &&
- (CHashWriter{HASHER_TAPBRANCH} << node.sub[1]->hash << node.sub[1]->hash).GetSHA256() == node.hash) {
+ (HashWriter{HASHER_TAPBRANCH} << node.sub[1]->hash << node.sub[1]->hash).GetSHA256() == node.hash) {
// Whenever there are nodes with two identical subtrees under it, we run into a problem:
// the control blocks for the leaves underneath those will be identical as well, and thus
// they will all be matched to the same path in the tree. The result is that at the location
diff --git a/src/script/standard.h b/src/script/standard.h
index 448fdff010..1e6769782a 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -33,21 +33,12 @@ public:
};
/**
- * Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
+ * Default setting for -datacarriersize. 80 bytes of data, +1 for OP_RETURN,
* +2 for the pushdata opcodes.
*/
static const unsigned int MAX_OP_RETURN_RELAY = 83;
/**
- * A data carrying output is an unspendable output containing data. The script
- * type is designated as TxoutType::NULL_DATA.
- */
-extern bool fAcceptDatacarrier;
-
-/** Maximum size of TxoutType::NULL_DATA scripts that this node considers standard. */
-extern unsigned nMaxDatacarrierBytes;
-
-/**
* Mandatory script verification flags that all new blocks must comply with for
* them to be valid. (but old blocks may not comply with) Currently just P2SH,
* but in the future other flags may be added.
diff --git a/src/serialize.h b/src/serialize.h
index a1cce78451..89a9f32240 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -520,6 +520,29 @@ struct CompactSizeFormatter
}
};
+template <typename U, bool LOSSY = false>
+struct ChronoFormatter {
+ template <typename Stream, typename Tp>
+ void Unser(Stream& s, Tp& tp)
+ {
+ U u;
+ s >> u;
+ // Lossy deserialization does not make sense, so force Wnarrowing
+ tp = Tp{typename Tp::duration{typename Tp::duration::rep{u}}};
+ }
+ template <typename Stream, typename Tp>
+ void Ser(Stream& s, Tp tp)
+ {
+ if constexpr (LOSSY) {
+ s << U(tp.time_since_epoch().count());
+ } else {
+ s << U{tp.time_since_epoch().count()};
+ }
+ }
+};
+template <typename U>
+using LossyChronoFormatter = ChronoFormatter<U, true>;
+
class CompactSizeWriter
{
protected:
diff --git a/src/streams.h b/src/streams.h
index 96b7696f72..f14d347380 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -465,35 +465,28 @@ public:
};
-
/** Non-refcounted RAII wrapper for FILE*
*
* Will automatically close the file when it goes out of scope if not null.
* If you're returning the file pointer, return file.release().
* If you need to close the file early, use file.fclose() instead of fclose(file).
*/
-class CAutoFile
+class AutoFile
{
-private:
- const int nType;
- const int nVersion;
-
+protected:
FILE* file;
public:
- CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn)
- {
- file = filenew;
- }
+ explicit AutoFile(FILE* filenew) : file{filenew} {}
- ~CAutoFile()
+ ~AutoFile()
{
fclose();
}
// Disallow copies
- CAutoFile(const CAutoFile&) = delete;
- CAutoFile& operator=(const CAutoFile&) = delete;
+ AutoFile(const AutoFile&) = delete;
+ AutoFile& operator=(const AutoFile&) = delete;
void fclose()
{
@@ -504,14 +497,14 @@ public:
}
/** Get wrapped FILE* with transfer of ownership.
- * @note This will invalidate the CAutoFile object, and makes it the responsibility of the caller
+ * @note This will invalidate the AutoFile object, and makes it the responsibility of the caller
* of this function to clean up the returned FILE*.
*/
FILE* release() { FILE* ret = file; file = nullptr; return ret; }
/** Get wrapped FILE* without transfer of ownership.
* @note Ownership of the FILE* will remain with this class. Use this only if the scope of the
- * CAutoFile outlives use of the passed pointer.
+ * AutoFile outlives use of the passed pointer.
*/
FILE* Get() const { return file; }
@@ -522,40 +515,62 @@ public:
//
// Stream subset
//
- int GetType() const { return nType; }
- int GetVersion() const { return nVersion; }
-
void read(Span<std::byte> dst)
{
- if (!file)
- throw std::ios_base::failure("CAutoFile::read: file handle is nullptr");
+ if (!file) throw std::ios_base::failure("AutoFile::read: file handle is nullptr");
if (fread(dst.data(), 1, dst.size(), file) != dst.size()) {
- throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed");
+ throw std::ios_base::failure(feof(file) ? "AutoFile::read: end of file" : "AutoFile::read: fread failed");
}
}
void ignore(size_t nSize)
{
- if (!file)
- throw std::ios_base::failure("CAutoFile::ignore: file handle is nullptr");
+ if (!file) throw std::ios_base::failure("AutoFile::ignore: file handle is nullptr");
unsigned char data[4096];
while (nSize > 0) {
size_t nNow = std::min<size_t>(nSize, sizeof(data));
if (fread(data, 1, nNow, file) != nNow)
- throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed");
+ throw std::ios_base::failure(feof(file) ? "AutoFile::ignore: end of file" : "AutoFile::read: fread failed");
nSize -= nNow;
}
}
void write(Span<const std::byte> src)
{
- if (!file)
- throw std::ios_base::failure("CAutoFile::write: file handle is nullptr");
+ if (!file) throw std::ios_base::failure("AutoFile::write: file handle is nullptr");
if (fwrite(src.data(), 1, src.size(), file) != src.size()) {
- throw std::ios_base::failure("CAutoFile::write: write failed");
+ throw std::ios_base::failure("AutoFile::write: write failed");
}
}
+ template <typename T>
+ AutoFile& operator<<(const T& obj)
+ {
+ if (!file) throw std::ios_base::failure("AutoFile::operator<<: file handle is nullptr");
+ ::Serialize(*this, obj);
+ return *this;
+ }
+
+ template <typename T>
+ AutoFile& operator>>(T&& obj)
+ {
+ if (!file) throw std::ios_base::failure("AutoFile::operator>>: file handle is nullptr");
+ ::Unserialize(*this, obj);
+ return *this;
+ }
+};
+
+class CAutoFile : public AutoFile
+{
+private:
+ const int nType;
+ const int nVersion;
+
+public:
+ CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : AutoFile{filenew}, nType(nTypeIn), nVersion(nVersionIn) {}
+ int GetType() const { return nType; }
+ int GetVersion() const { return nVersion; }
+
template<typename T>
CAutoFile& operator<<(const T& obj)
{
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 12cf1176a6..b10d32ccec 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -225,7 +225,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
- int64_t start_time{GetAdjustedTime()};
+ const auto start_time{Now<NodeSeconds>()};
addr.nTime = start_time;
// test that multiplicity stays at 1 if nTime doesn't increase
@@ -244,7 +244,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
for (unsigned int i = 1; i < 400; ++i) {
std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
CNetAddr source{ResolveIP(addr_ip)};
- addr.nTime = start_time + i;
+ addr.nTime = start_time + std::chrono::seconds{i};
addrman->Add({addr}, source);
}
AddressPosition addr_pos_multi = addrman->FindAddressEntry(addr).value();
@@ -295,15 +295,15 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
- addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false
+ addr1.nTime = Now<NodeSeconds>(); // Set time so isTerrible = false
CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
- addr2.nTime = GetAdjustedTime();
+ addr2.nTime = Now<NodeSeconds>();
CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
- addr3.nTime = GetAdjustedTime();
+ addr3.nTime = Now<NodeSeconds>();
CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
- addr4.nTime = GetAdjustedTime();
+ addr4.nTime = Now<NodeSeconds>();
CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
- addr5.nTime = GetAdjustedTime();
+ addr5.nTime = Now<NodeSeconds>();
CNetAddr source1 = ResolveIP("250.1.2.1");
CNetAddr source2 = ResolveIP("250.2.3.3");
@@ -329,7 +329,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
// Ensure that for all addrs in addrman, isTerrible == false.
- addr.nTime = GetAdjustedTime();
+ addr.nTime = Now<NodeSeconds>();
addrman->Add({addr}, ResolveIP(strAddr));
if (i % 8 == 0)
addrman->Good(addr);
@@ -821,8 +821,8 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
// Ensure test of address fails, so that it is evicted.
// Update entry in tried by setting last good connection in the deep past.
- BOOST_CHECK(!addrman->Good(info, /*nTime=*/1));
- addrman->Attempt(info, /*fCountFailure=*/false, /*nTime=*/GetAdjustedTime() - 61);
+ BOOST_CHECK(!addrman->Good(info, NodeSeconds{1s}));
+ addrman->Attempt(info, /*fCountFailure=*/false, Now<NodeSeconds>() - 61s);
// Should swap 36 for 19.
addrman->ResolveCollisions();
@@ -966,7 +966,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
CNetAddr source{ResolveIP("252.2.2.2")};
CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
- int64_t start_time{GetAdjustedTime() - 10000};
+ const auto start_time{Now<NodeSeconds>() - 10000s};
addr.nTime = start_time;
BOOST_CHECK(addrman->Add({addr}, source));
BOOST_CHECK_EQUAL(addrman->size(), 1U);
@@ -978,7 +978,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
addrman->SetServices(addr_diff_port, NODE_NETWORK_LIMITED);
std::vector<CAddress> vAddr1{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
BOOST_CHECK_EQUAL(vAddr1.size(), 1U);
- BOOST_CHECK_EQUAL(vAddr1.at(0).nTime, start_time);
+ BOOST_CHECK(vAddr1.at(0).nTime == start_time);
BOOST_CHECK_EQUAL(vAddr1.at(0).nServices, NODE_NONE);
// Updating an addrman entry with the correct port is successful
@@ -986,7 +986,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
addrman->SetServices(addr, NODE_NETWORK_LIMITED);
std::vector<CAddress> vAddr2 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
BOOST_CHECK_EQUAL(vAddr2.size(), 1U);
- BOOST_CHECK(vAddr2.at(0).nTime >= start_time + 10000);
+ BOOST_CHECK(vAddr2.at(0).nTime >= start_time + 10000s);
BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED);
}
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 64cc924239..75b29ae0aa 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -184,4 +184,22 @@ BOOST_AUTO_TEST_CASE(bip32_test5) {
}
}
+BOOST_AUTO_TEST_CASE(bip32_max_depth) {
+ CExtKey key_parent{DecodeExtKey(test1.vDerive[0].prv)}, key_child;
+ CExtPubKey pubkey_parent{DecodeExtPubKey(test1.vDerive[0].pub)}, pubkey_child;
+
+ // We can derive up to the 255th depth..
+ for (auto i = 0; i++ < 255;) {
+ BOOST_CHECK(key_parent.Derive(key_child, 0));
+ std::swap(key_parent, key_child);
+ BOOST_CHECK(pubkey_parent.Derive(pubkey_child, 0));
+ std::swap(pubkey_parent, pubkey_child);
+ }
+
+ // But trying to derive a non-existent 256th depth will fail!
+ BOOST_CHECK(key_parent.nDepth == 255 && pubkey_parent.nDepth == 255);
+ BOOST_CHECK(!key_parent.Derive(key_child, 0));
+ BOOST_CHECK(!pubkey_parent.Derive(pubkey_child, 0));
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index c31e4e51f7..1a182209b8 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -7,6 +7,7 @@
#include <consensus/merkle.h>
#include <consensus/validation.h>
#include <index/blockfilterindex.h>
+#include <interfaces/chain.h>
#include <node/miner.h>
#include <pow.h>
#include <script/standard.h>
@@ -110,7 +111,7 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex,
BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
{
- BlockFilterIndex filter_index(BlockFilterType::BASIC, 1 << 20, true);
+ BlockFilterIndex filter_index(interfaces::MakeChain(m_node), BlockFilterType::BASIC, 1 << 20, true);
uint256 last_header;
@@ -137,7 +138,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
// BlockUntilSyncedToCurrentChain should return false before index is started.
BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());
- BOOST_REQUIRE(filter_index.Start(m_node.chainman->ActiveChainstate()));
+ BOOST_REQUIRE(filter_index.Start());
// Allow filter index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000;
@@ -279,14 +280,14 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
BOOST_CHECK(filter_index == nullptr);
- BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
+ BOOST_CHECK(InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1 << 20, true, false));
filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
BOOST_CHECK(filter_index != nullptr);
BOOST_CHECK(filter_index->GetFilterType() == BlockFilterType::BASIC);
// Initialize returns false if index already exists.
- BOOST_CHECK(!InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
+ BOOST_CHECK(!InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1 << 20, true, false));
int iter_count = 0;
ForEachBlockFilterIndex([&iter_count](BlockFilterIndex& _index) { iter_count++; });
@@ -301,7 +302,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
BOOST_CHECK(filter_index == nullptr);
// Reinitialize index.
- BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false));
+ BOOST_CHECK(InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1 << 20, true, false));
DestroyAllBlockFilterIndexes();
diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp
index 50eb479035..c93d05a93b 100644
--- a/src/test/coinstatsindex_tests.cpp
+++ b/src/test/coinstatsindex_tests.cpp
@@ -4,6 +4,7 @@
#include <chainparams.h>
#include <index/coinstatsindex.h>
+#include <interfaces/chain.h>
#include <test/util/setup_common.h>
#include <test/util/validation.h>
#include <util/time.h>
@@ -13,9 +14,6 @@
#include <chrono>
-using kernel::CCoinsStats;
-using kernel::CoinStatsHashType;
-
BOOST_AUTO_TEST_SUITE(coinstatsindex_tests)
static void IndexWaitSynced(BaseIndex& index)
@@ -31,7 +29,7 @@ static void IndexWaitSynced(BaseIndex& index)
BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
{
- CoinStatsIndex coin_stats_index{1 << 20, true};
+ CoinStatsIndex coin_stats_index{interfaces::MakeChain(m_node), 1 << 20, true};
const CBlockIndex* block_index;
{
@@ -46,7 +44,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
// is started.
BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain());
- BOOST_REQUIRE(coin_stats_index.Start(m_node.chainman->ActiveChainstate()));
+ BOOST_REQUIRE(coin_stats_index.Start());
IndexWaitSynced(coin_stats_index);
@@ -90,8 +88,8 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
CChainState& chainstate = Assert(m_node.chainman)->ActiveChainstate();
const CChainParams& params = Params();
{
- CoinStatsIndex index{1 << 20};
- BOOST_REQUIRE(index.Start(chainstate));
+ CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
+ BOOST_REQUIRE(index.Start());
IndexWaitSynced(index);
std::shared_ptr<const CBlock> new_block;
CBlockIndex* new_block_index = nullptr;
@@ -116,9 +114,9 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
}
{
- CoinStatsIndex index{1 << 20};
+ CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
// Make sure the index can be loaded.
- BOOST_REQUIRE(index.Start(chainstate));
+ BOOST_REQUIRE(index.Start());
index.Stop();
}
}
diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp
index c87ed82c88..66c4605afa 100644
--- a/src/test/denialofservice_tests.cpp
+++ b/src/test/denialofservice_tests.cpp
@@ -15,6 +15,7 @@
#include <serialize.h>
#include <test/util/net.h>
#include <test/util/setup_common.h>
+#include <timedata.h>
#include <util/string.h>
#include <util/system.h>
#include <util/time.h>
@@ -44,17 +45,15 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
// work.
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{
- auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman);
+ ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
// Disable inactivity checks for this test to avoid interference
- static_cast<ConnmanTestMsg*>(connman.get())->SetPeerConnectTimeout(99999s);
- auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr,
- *m_node.chainman, *m_node.mempool, false);
+ connman.SetPeerConnectTimeout(99999s);
+ PeerManager& peerman = *m_node.peerman;
// Mock an outbound peer
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
NodeId id{0};
CNode dummyNode1{id++,
- ServiceFlags(NODE_NETWORK | NODE_WITNESS),
/*sock=*/nullptr,
addr1,
/*nKeyedNetGroupIn=*/0,
@@ -63,10 +62,16 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
/*addrNameIn=*/"",
ConnectionType::OUTBOUND_FULL_RELAY,
/*inbound_onion=*/false};
- dummyNode1.SetCommonVersion(PROTOCOL_VERSION);
- peerLogic->InitializeNode(&dummyNode1);
- dummyNode1.fSuccessfullyConnected = true;
+ connman.Handshake(
+ /*node=*/dummyNode1,
+ /*successfully_connected=*/true,
+ /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
+ /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
+ /*permission_flags=*/NetPermissionFlags::None,
+ /*version=*/PROTOCOL_VERSION,
+ /*relay_txs=*/true);
+ TestOnlyResetTimeData();
// This test requires that we have a chain with non-zero work.
{
@@ -78,7 +83,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
// Test starts here
{
LOCK(dummyNode1.cs_sendProcessing);
- BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in getheaders
+ BOOST_CHECK(peerman.SendMessages(&dummyNode1)); // should result in getheaders
}
{
LOCK(dummyNode1.cs_vSend);
@@ -91,7 +96,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
SetMockTime(nStartTime+21*60);
{
LOCK(dummyNode1.cs_sendProcessing);
- BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in getheaders
+ BOOST_CHECK(peerman.SendMessages(&dummyNode1)); // should result in getheaders
}
{
LOCK(dummyNode1.cs_vSend);
@@ -101,18 +106,17 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
SetMockTime(nStartTime+24*60);
{
LOCK(dummyNode1.cs_sendProcessing);
- BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); // should result in disconnect
+ BOOST_CHECK(peerman.SendMessages(&dummyNode1)); // should result in disconnect
}
BOOST_CHECK(dummyNode1.fDisconnect == true);
- peerLogic->FinalizeNode(dummyNode1);
+ peerman.FinalizeNode(dummyNode1);
}
static void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType)
{
CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE);
vNodes.emplace_back(new CNode{id++,
- ServiceFlags(NODE_NETWORK | NODE_WITNESS),
/*sock=*/nullptr,
addr,
/*nKeyedNetGroupIn=*/0,
@@ -124,7 +128,7 @@ static void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerM
CNode &node = *vNodes.back();
node.SetCommonVersion(PROTOCOL_VERSION);
- peerLogic.InitializeNode(&node);
+ peerLogic.InitializeNode(node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
node.fSuccessfullyConnected = true;
connman.AddTestNode(node);
@@ -292,7 +296,6 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
banman->ClearBanned();
NodeId id{0};
nodes[0] = new CNode{id++,
- NODE_NETWORK,
/*sock=*/nullptr,
addr[0],
/*nKeyedNetGroupIn=*/0,
@@ -302,7 +305,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
ConnectionType::INBOUND,
/*inbound_onion=*/false};
nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
- peerLogic->InitializeNode(nodes[0]);
+ peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
nodes[0]->fSuccessfullyConnected = true;
connman->AddTestNode(*nodes[0]);
peerLogic->UnitTestMisbehaving(nodes[0]->GetId(), DISCOURAGEMENT_THRESHOLD); // Should be discouraged
@@ -315,7 +318,6 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
BOOST_CHECK(!banman->IsDiscouraged(other_addr)); // Different address, not discouraged
nodes[1] = new CNode{id++,
- NODE_NETWORK,
/*sock=*/nullptr,
addr[1],
/*nKeyedNetGroupIn=*/1,
@@ -325,7 +327,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
ConnectionType::INBOUND,
/*inbound_onion=*/false};
nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
- peerLogic->InitializeNode(nodes[1]);
+ peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
nodes[1]->fSuccessfullyConnected = true;
connman->AddTestNode(*nodes[1]);
peerLogic->UnitTestMisbehaving(nodes[1]->GetId(), DISCOURAGEMENT_THRESHOLD - 1);
@@ -353,7 +355,6 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
// Make sure non-IP peers are discouraged and disconnected properly.
nodes[2] = new CNode{id++,
- NODE_NETWORK,
/*sock=*/nullptr,
addr[2],
/*nKeyedNetGroupIn=*/1,
@@ -363,7 +364,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
ConnectionType::OUTBOUND_FULL_RELAY,
/*inbound_onion=*/false};
nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
- peerLogic->InitializeNode(nodes[2]);
+ peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
nodes[2]->fSuccessfullyConnected = true;
connman->AddTestNode(*nodes[2]);
peerLogic->UnitTestMisbehaving(nodes[2]->GetId(), DISCOURAGEMENT_THRESHOLD);
@@ -398,7 +399,6 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
CAddress addr(ip(0xa0b0c001), NODE_NONE);
NodeId id{0};
CNode dummyNode{id++,
- NODE_NETWORK,
/*sock=*/nullptr,
addr,
/*nKeyedNetGroupIn=*/4,
@@ -408,7 +408,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
ConnectionType::INBOUND,
/*inbound_onion=*/false};
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
- peerLogic->InitializeNode(&dummyNode);
+ peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
dummyNode.fSuccessfullyConnected = true;
peerLogic->UnitTestMisbehaving(dummyNode.GetId(), DISCOURAGEMENT_THRESHOLD);
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index a8c666079d..1eb4b373b4 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -233,7 +233,7 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
for (const auto& xpub_pair : parent_xpub_cache) {
const CExtPubKey& xpub = xpub_pair.second;
CExtPubKey der;
- xpub.Derive(der, i);
+ BOOST_CHECK(xpub.Derive(der, i));
pubkeys.insert(der.pubkey);
}
int count_pks = 0;
@@ -265,7 +265,7 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
const CExtPubKey& xpub = xpub_pair.second;
pubkeys.insert(xpub.pubkey);
CExtPubKey der;
- xpub.Derive(der, i);
+ BOOST_CHECK(xpub.Derive(der, i));
pubkeys.insert(der.pubkey);
}
int count_pks = 0;
@@ -302,7 +302,6 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
// For each of the produced scripts, verify solvability, and when possible, try to sign a transaction spending it.
for (size_t n = 0; n < spks.size(); ++n) {
BOOST_CHECK_EQUAL(ref[n], HexStr(spks[n]));
- BOOST_CHECK_EQUAL(IsSolvable(Merge(key_provider, script_provider), spks[n]), (flags & UNSOLVABLE) == 0);
if (flags & SIGNABLE) {
CMutableTransaction spend;
@@ -324,7 +323,7 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string&
BOOST_CHECK(inferred->Expand(0, provider_inferred, spks_inferred, provider_inferred));
BOOST_CHECK_EQUAL(spks_inferred.size(), 1U);
BOOST_CHECK(spks_inferred[0] == spks[n]);
- BOOST_CHECK_EQUAL(IsSolvable(provider_inferred, spks_inferred[0]), !(flags & UNSOLVABLE));
+ BOOST_CHECK_EQUAL(InferDescriptor(spks_inferred[0], provider_inferred)->IsSolvable(), !(flags & UNSOLVABLE));
BOOST_CHECK(GetKeyOriginData(provider_inferred, flags) == GetKeyOriginData(script_provider, flags));
}
diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp
index d54d6b6471..605faa08e4 100644
--- a/src/test/flatfile_tests.cpp
+++ b/src/test/flatfile_tests.cpp
@@ -41,26 +41,26 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
// Write first line to file.
{
- CAutoFile file(seq.Open(FlatFilePos(0, pos1)), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(0, pos1))};
file << LIMITED_STRING(line1, 256);
}
// Attempt to append to file opened in read-only mode.
{
- CAutoFile file(seq.Open(FlatFilePos(0, pos2), true), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(0, pos2), true)};
BOOST_CHECK_THROW(file << LIMITED_STRING(line2, 256), std::ios_base::failure);
}
// Append second line to file.
{
- CAutoFile file(seq.Open(FlatFilePos(0, pos2)), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(0, pos2))};
file << LIMITED_STRING(line2, 256);
}
// Read text from file in read-only mode.
{
std::string text;
- CAutoFile file(seq.Open(FlatFilePos(0, pos1), true), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(0, pos1), true)};
file >> LIMITED_STRING(text, 256);
BOOST_CHECK_EQUAL(text, line1);
@@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
// Read text from file with position offset.
{
std::string text;
- CAutoFile file(seq.Open(FlatFilePos(0, pos2)), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(0, pos2))};
file >> LIMITED_STRING(text, 256);
BOOST_CHECK_EQUAL(text, line2);
@@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(flatfile_open)
// Ensure another file in the sequence has no data.
{
std::string text;
- CAutoFile file(seq.Open(FlatFilePos(1, pos2)), SER_DISK, CLIENT_VERSION);
+ AutoFile file{seq.Open(FlatFilePos(1, pos2))};
BOOST_CHECK_THROW(file >> LIMITED_STRING(text, 256), std::ios_base::failure);
}
}
diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp
index af7a282781..7668940cbc 100644
--- a/src/test/fuzz/addrman.cpp
+++ b/src/test/fuzz/addrman.cpp
@@ -113,11 +113,11 @@ void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
for (size_t j = 0; j < num_addresses; ++j) {
const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK};
- const auto time_penalty = fast_random_context.randrange(100000001);
+ const std::chrono::seconds time_penalty{fast_random_context.randrange(100000001)};
addrman.Add({addr}, source, time_penalty);
if (n > 0 && addrman.size() % n == 0) {
- addrman.Good(addr, GetTime());
+ addrman.Good(addr, Now<NodeSeconds>());
}
// Add 10% of the addresses from more than one source.
@@ -161,7 +161,7 @@ public:
CSipHasher hasher(0, 0);
auto addr_key = a.GetKey();
auto source_key = a.source.GetAddrBytes();
- hasher.Write(a.nLastSuccess);
+ hasher.Write(TicksSinceEpoch<std::chrono::seconds>(a.m_last_success));
hasher.Write(a.nAttempts);
hasher.Write(a.nRefCount);
hasher.Write(a.fInTried);
@@ -175,8 +175,8 @@ public:
};
auto addrinfo_eq = [](const AddrInfo& lhs, const AddrInfo& rhs) {
- return std::tie(static_cast<const CService&>(lhs), lhs.source, lhs.nLastSuccess, lhs.nAttempts, lhs.nRefCount, lhs.fInTried) ==
- std::tie(static_cast<const CService&>(rhs), rhs.source, rhs.nLastSuccess, rhs.nAttempts, rhs.nRefCount, rhs.fInTried);
+ return std::tie(static_cast<const CService&>(lhs), lhs.source, lhs.m_last_success, lhs.nAttempts, lhs.nRefCount, lhs.fInTried) ==
+ std::tie(static_cast<const CService&>(rhs), rhs.source, rhs.m_last_success, rhs.nAttempts, rhs.nRefCount, rhs.fInTried);
};
using Addresses = std::unordered_set<AddrInfo, decltype(addrinfo_hasher), decltype(addrinfo_eq)>;
@@ -269,25 +269,25 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
}
const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
if (opt_net_addr) {
- addr_man.Add(addresses, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000));
+ addr_man.Add(addresses, *opt_net_addr, std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)});
}
},
[&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) {
- addr_man.Good(*opt_service, ConsumeTime(fuzzed_data_provider));
+ addr_man.Good(*opt_service, NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
}
},
[&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) {
- addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider));
+ addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
}
},
[&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) {
- addr_man.Connected(*opt_service, ConsumeTime(fuzzed_data_provider));
+ addr_man.Connected(*opt_service, NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
}
},
[&] {
diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp
index 3b410930ed..1a8957d090 100644
--- a/src/test/fuzz/autofile.cpp
+++ b/src/test/fuzz/autofile.cpp
@@ -18,7 +18,7 @@ FUZZ_TARGET(autofile)
{
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
- CAutoFile auto_file = fuzzed_auto_file_provider.open();
+ AutoFile auto_file{fuzzed_auto_file_provider.open()};
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10000) {
CallOneOf(
fuzzed_data_provider,
@@ -53,8 +53,6 @@ FUZZ_TARGET(autofile)
});
}
(void)auto_file.Get();
- (void)auto_file.GetType();
- (void)auto_file.GetVersion();
(void)auto_file.IsNull();
if (fuzzed_data_provider.ConsumeBool()) {
FILE* f = auto_file.release();
diff --git a/src/test/fuzz/chain.cpp b/src/test/fuzz/chain.cpp
index 8c0ed32d51..01edb06138 100644
--- a/src/test/fuzz/chain.cpp
+++ b/src/test/fuzz/chain.cpp
@@ -23,7 +23,7 @@ FUZZ_TARGET(chain)
disk_block_index->phashBlock = &zero;
{
LOCK(::cs_main);
- (void)disk_block_index->GetBlockHash();
+ (void)disk_block_index->ConstructBlockHash();
(void)disk_block_index->GetBlockPos();
(void)disk_block_index->GetBlockTime();
(void)disk_block_index->GetBlockTimeMax();
@@ -31,7 +31,6 @@ FUZZ_TARGET(chain)
(void)disk_block_index->GetUndoPos();
(void)disk_block_index->HaveTxsDownloaded();
(void)disk_block_index->IsValid();
- (void)disk_block_index->ToString();
}
const CBlockHeader block_header = disk_block_index->GetBlockHeader();
diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp
index 72574612a2..c52fca5fe8 100644
--- a/src/test/fuzz/integer.cpp
+++ b/src/test/fuzz/integer.cpp
@@ -87,9 +87,6 @@ FUZZ_TARGET_INIT(integer, initialize_integer)
}
(void)GetSizeOfCompactSize(u64);
(void)GetSpecialScriptSize(u32);
- if (!MultiplicationOverflow(i64, static_cast<int64_t>(::nBytesPerSigOp)) && !AdditionOverflow(i64 * ::nBytesPerSigOp, static_cast<int64_t>(4))) {
- (void)GetVirtualTransactionSize(i64, i64);
- }
if (!MultiplicationOverflow(i64, static_cast<int64_t>(u32)) && !AdditionOverflow(i64, static_cast<int64_t>(4)) && !AdditionOverflow(i64 * u32, static_cast<int64_t>(4))) {
(void)GetVirtualTransactionSize(i64, i64, u32);
}
diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp
index bfea9778f4..a76901e473 100644
--- a/src/test/fuzz/key.cpp
+++ b/src/test/fuzz/key.cpp
@@ -138,8 +138,6 @@ FUZZ_TARGET_INIT(key, initialize_key)
assert(tx_multisig_script.size() == 37);
FillableSigningProvider fillable_signing_provider;
- assert(IsSolvable(fillable_signing_provider, tx_pubkey_script));
- assert(IsSolvable(fillable_signing_provider, tx_multisig_script));
assert(!IsSegWitOutput(fillable_signing_provider, tx_pubkey_script));
assert(!IsSegWitOutput(fillable_signing_provider, tx_multisig_script));
assert(fillable_signing_provider.GetKeys().size() == 0);
@@ -157,12 +155,12 @@ FUZZ_TARGET_INIT(key, initialize_key)
assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
TxoutType which_type_tx_pubkey;
- const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, which_type_tx_pubkey);
+ const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, std::nullopt, which_type_tx_pubkey);
assert(is_standard_tx_pubkey);
assert(which_type_tx_pubkey == TxoutType::PUBKEY);
TxoutType which_type_tx_multisig;
- const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, which_type_tx_multisig);
+ const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, std::nullopt, which_type_tx_multisig);
assert(is_standard_tx_multisig);
assert(which_type_tx_multisig == TxoutType::MULTISIG);
diff --git a/src/test/fuzz/load_external_block_file.cpp b/src/test/fuzz/load_external_block_file.cpp
index bfa977520b..f4b7dc08fd 100644
--- a/src/test/fuzz/load_external_block_file.cpp
+++ b/src/test/fuzz/load_external_block_file.cpp
@@ -31,6 +31,13 @@ FUZZ_TARGET_INIT(load_external_block_file, initialize_load_external_block_file)
if (fuzzed_block_file == nullptr) {
return;
}
- FlatFilePos flat_file_pos;
- g_setup->m_node.chainman->ActiveChainstate().LoadExternalBlockFile(fuzzed_block_file, fuzzed_data_provider.ConsumeBool() ? &flat_file_pos : nullptr);
+ if (fuzzed_data_provider.ConsumeBool()) {
+ // Corresponds to the -reindex case (track orphan blocks across files).
+ FlatFilePos flat_file_pos;
+ std::multimap<uint256, FlatFilePos> blocks_with_unknown_parent;
+ g_setup->m_node.chainman->ActiveChainstate().LoadExternalBlockFile(fuzzed_block_file, &flat_file_pos, &blocks_with_unknown_parent);
+ } else {
+ // Corresponds to the -loadblock= case (orphan blocks aren't tracked across files).
+ g_setup->m_node.chainman->ActiveChainstate().LoadExternalBlockFile(fuzzed_block_file);
+ }
}
diff --git a/src/test/fuzz/mempool_utils.h b/src/test/fuzz/mempool_utils.h
new file mode 100644
index 0000000000..bfe12e30ba
--- /dev/null
+++ b/src/test/fuzz/mempool_utils.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_TEST_FUZZ_MEMPOOL_UTILS_H
+#define BITCOIN_TEST_FUZZ_MEMPOOL_UTILS_H
+
+#include <validation.h>
+
+class DummyChainState final : public CChainState
+{
+public:
+ void SetMempool(CTxMemPool* mempool)
+ {
+ m_mempool = mempool;
+ }
+};
+
+#endif // BITCOIN_TEST_FUZZ_MEMPOOL_UTILS_H
diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp
index 4981287152..741810f6a2 100644
--- a/src/test/fuzz/net.cpp
+++ b/src/test/fuzz/net.cpp
@@ -68,7 +68,6 @@ FUZZ_TARGET_INIT(net, initialize_net)
(void)node.GetAddrLocal();
(void)node.GetId();
(void)node.GetLocalNonce();
- (void)node.GetLocalServices();
const int ref_count = node.GetRefCount();
assert(ref_count >= 0);
(void)node.GetCommonVersion();
diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp
index c7a76aa52f..0cc210f26f 100644
--- a/src/test/fuzz/parse_univalue.cpp
+++ b/src/test/fuzz/parse_univalue.cpp
@@ -26,7 +26,7 @@ FUZZ_TARGET_INIT(parse_univalue, initialize_parse_univalue)
return ParseNonRFCJSONValue(random_string);
} catch (const std::runtime_error&) {
valid = false;
- return NullUniValue;
+ return UniValue{};
}
}();
if (!valid) {
diff --git a/src/test/fuzz/policy_estimator.cpp b/src/test/fuzz/policy_estimator.cpp
index 58c19a91cb..637ba503c6 100644
--- a/src/test/fuzz/policy_estimator.cpp
+++ b/src/test/fuzz/policy_estimator.cpp
@@ -76,7 +76,7 @@ FUZZ_TARGET_INIT(policy_estimator, initialize_policy_estimator)
}
{
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
- CAutoFile fuzzed_auto_file = fuzzed_auto_file_provider.open();
+ AutoFile fuzzed_auto_file{fuzzed_auto_file_provider.open()};
block_policy_estimator.Write(fuzzed_auto_file);
block_policy_estimator.Read(fuzzed_auto_file);
}
diff --git a/src/test/fuzz/policy_estimator_io.cpp b/src/test/fuzz/policy_estimator_io.cpp
index 77402c260a..436873c955 100644
--- a/src/test/fuzz/policy_estimator_io.cpp
+++ b/src/test/fuzz/policy_estimator_io.cpp
@@ -26,7 +26,7 @@ FUZZ_TARGET_INIT(policy_estimator_io, initialize_policy_estimator_io)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
FuzzedAutoFileProvider fuzzed_auto_file_provider = ConsumeAutoFile(fuzzed_data_provider);
- CAutoFile fuzzed_auto_file = fuzzed_auto_file_provider.open();
+ AutoFile fuzzed_auto_file{fuzzed_auto_file_provider.open()};
// Re-using block_policy_estimator across runs to avoid costly creation of CBlockPolicyEstimator object.
static CBlockPolicyEstimator block_policy_estimator{FeeestPath(*g_setup->m_node.args)};
if (block_policy_estimator.Read(fuzzed_auto_file)) {
diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp
index 4801635791..1a06ae886e 100644
--- a/src/test/fuzz/rbf.cpp
+++ b/src/test/fuzz/rbf.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <mempool_args.h>
+#include <node/mempool_args.h>
#include <policy/rbf.h>
#include <primitives/transaction.h>
#include <sync.h>
diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp
index fdcd0da37d..00d7b7e29a 100644
--- a/src/test/fuzz/script.cpp
+++ b/src/test/fuzz/script.cpp
@@ -55,7 +55,7 @@ FUZZ_TARGET_INIT(script, initialize_script)
}
TxoutType which_type;
- bool is_standard_ret = IsStandard(script, which_type);
+ bool is_standard_ret = IsStandard(script, std::nullopt, which_type);
if (!is_standard_ret) {
assert(which_type == TxoutType::NONSTANDARD ||
which_type == TxoutType::NULL_DATA ||
@@ -89,7 +89,6 @@ FUZZ_TARGET_INIT(script, initialize_script)
const FlatSigningProvider signing_provider;
(void)InferDescriptor(script, signing_provider);
(void)IsSegWitOutput(signing_provider, script);
- (void)IsSolvable(signing_provider, script);
(void)RecursiveDynamicUsage(script);
diff --git a/src/test/fuzz/script_sigcache.cpp b/src/test/fuzz/script_sigcache.cpp
index f7e45d6889..f6af7947df 100644
--- a/src/test/fuzz/script_sigcache.cpp
+++ b/src/test/fuzz/script_sigcache.cpp
@@ -10,18 +10,21 @@
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
+namespace {
+const BasicTestingSetup* g_setup;
+} // namespace
+
void initialize_script_sigcache()
{
- static const ECCVerifyHandle ecc_verify_handle;
- ECC_Start();
- SelectParams(CBaseChainParams::REGTEST);
- InitSignatureCache();
+ static const auto testing_setup = MakeNoLogFileContext<>();
+ g_setup = testing_setup.get();
}
FUZZ_TARGET_INIT(script_sigcache, initialize_script_sigcache)
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index 273aa0dc5c..7fa4523800 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -69,8 +69,8 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE};
std::string reason;
- const bool is_standard_with_permit_bare_multisig = IsStandardTx(tx, /* permit_bare_multisig= */ true, dust_relay_fee, reason);
- const bool is_standard_without_permit_bare_multisig = IsStandardTx(tx, /* permit_bare_multisig= */ false, dust_relay_fee, reason);
+ const bool is_standard_with_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_multisig= */ true, dust_relay_fee, reason);
+ const bool is_standard_without_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_multisig= */ false, dust_relay_fee, reason);
if (is_standard_without_permit_bare_multisig) {
assert(is_standard_with_permit_bare_multisig);
}
@@ -92,7 +92,6 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction)
(void)GetTransactionWeight(tx);
(void)GetVirtualTransactionSize(tx);
(void)IsFinalTx(tx, /* nBlockHeight= */ 1024, /* nBlockTime= */ 1024);
- (void)IsStandardTx(tx, reason);
(void)RecursiveDynamicUsage(tx);
(void)SignalsOptInRBF(tx);
diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp
index 2d88ee295b..3191367870 100644
--- a/src/test/fuzz/tx_pool.cpp
+++ b/src/test/fuzz/tx_pool.cpp
@@ -3,11 +3,12 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/validation.h>
-#include <mempool_args.h>
#include <node/context.h>
+#include <node/mempool_args.h>
#include <node/miner.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <test/fuzz/mempool_utils.h>
#include <test/fuzz/util.h>
#include <test/util/mining.h>
#include <test/util/script.h>
@@ -34,15 +35,6 @@ struct MockedTxPool : public CTxMemPool {
}
};
-class DummyChainState final : public CChainState
-{
-public:
- void SetMempool(CTxMemPool* mempool)
- {
- m_mempool = mempool;
- }
-};
-
void initialize_tx_pool()
{
static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
@@ -124,7 +116,7 @@ void MockTime(FuzzedDataProvider& fuzzed_data_provider, const CChainState& chain
SetMockTime(time);
}
-CTxMemPool MakeMempool(const NodeContext& node)
+CTxMemPool MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
{
// Take the default options for tests...
CTxMemPool::Options mempool_opts{MemPoolOptionsForTest(node)};
@@ -132,6 +124,7 @@ CTxMemPool MakeMempool(const NodeContext& node)
// ...override specific options for this specific fuzz suite
mempool_opts.estimator = nullptr;
mempool_opts.check_ratio = 1;
+ mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();
// ...and construct a CTxMemPool from it
return CTxMemPool{mempool_opts};
@@ -144,7 +137,6 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};
MockTime(fuzzed_data_provider, chainstate);
- SetMempoolConstraints(*node.args, fuzzed_data_provider);
// All RBF-spendable outpoints
std::set<COutPoint> outpoints_rbf;
@@ -158,7 +150,8 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
// The sum of the values of all spendable outpoints
constexpr CAmount SUPPLY_TOTAL{COINBASE_MATURITY * 50 * COIN};
- CTxMemPool tx_pool_{MakeMempool(node)};
+ SetMempoolConstraints(*node.args, fuzzed_data_provider);
+ CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
chainstate.SetMempool(&tx_pool);
@@ -229,9 +222,6 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
MockTime(fuzzed_data_provider, chainstate);
}
if (fuzzed_data_provider.ConsumeBool()) {
- SetMempoolConstraints(*node.args, fuzzed_data_provider);
- }
- if (fuzzed_data_provider.ConsumeBool()) {
tx_pool.RollingFeeUpdate();
}
if (fuzzed_data_provider.ConsumeBool()) {
@@ -248,7 +238,6 @@ FUZZ_TARGET_INIT(tx_pool_standard, initialize_tx_pool)
auto txr = std::make_shared<TransactionsDelta>(removed, added);
RegisterSharedValidationInterface(txr);
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
- ::fRequireStandard = fuzzed_data_provider.ConsumeBool();
// Make sure ProcessNewPackage on one transaction works.
// The result is not guaranteed to be the same as what is returned by ATMP.
@@ -324,7 +313,6 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
auto& chainstate = node.chainman->ActiveChainstate();
MockTime(fuzzed_data_provider, chainstate);
- SetMempoolConstraints(*node.args, fuzzed_data_provider);
std::vector<uint256> txids;
for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
@@ -336,7 +324,8 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
txids.push_back(ConsumeUInt256(fuzzed_data_provider));
}
- CTxMemPool tx_pool_{MakeMempool(node)};
+ SetMempoolConstraints(*node.args, fuzzed_data_provider);
+ CTxMemPool tx_pool_{MakeMempool(fuzzed_data_provider, node)};
MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(&tx_pool_);
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
@@ -347,9 +336,6 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
MockTime(fuzzed_data_provider, chainstate);
}
if (fuzzed_data_provider.ConsumeBool()) {
- SetMempoolConstraints(*node.args, fuzzed_data_provider);
- }
- if (fuzzed_data_provider.ConsumeBool()) {
tx_pool.RollingFeeUpdate();
}
if (fuzzed_data_provider.ConsumeBool()) {
@@ -362,7 +348,6 @@ FUZZ_TARGET_INIT(tx_pool, initialize_tx_pool)
const auto tx = MakeTransactionRef(mut_tx);
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
- ::fRequireStandard = fuzzed_data_provider.ConsumeBool();
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false));
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
if (accepted) {
diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp
index d318baa6a2..7580651371 100644
--- a/src/test/fuzz/txorphan.cpp
+++ b/src/test/fuzz/txorphan.cpp
@@ -3,8 +3,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <consensus/amount.h>
-#include <net.h>
+#include <consensus/validation.h>
#include <net_processing.h>
+#include <node/eviction.h>
+#include <policy/policy.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <sync.h>
@@ -65,7 +67,7 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
for (uint32_t i = 0; i < num_out; i++) {
tx_mut.vout.emplace_back(CAmount{0}, CScript{});
}
- // restore previously poped outpoints
+ // restore previously popped outpoints
for (auto& in : tx_mut.vin) {
outpoints.push_back(in.prevout);
}
@@ -99,16 +101,20 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
[&] {
bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
// AddTx should return false if tx is too big or already have it
+ // tx weight is unknown, we only check when tx is already in orphanage
{
LOCK(g_cs_orphans);
- Assert(have_tx != orphanage.AddTx(tx, peer_id));
+ bool add_tx = orphanage.AddTx(tx, peer_id);
+ // have_tx == true -> add_tx == false
+ Assert(!have_tx || !add_tx);
}
have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
- // tx should already be added since it will not be too big in the test
- // have_tx should be true and AddTx should fail
{
LOCK(g_cs_orphans);
- Assert(have_tx && !orphanage.AddTx(tx, peer_id));
+ bool add_tx = orphanage.AddTx(tx, peer_id);
+ // if have_tx is still false, it must be too big
+ Assert(!have_tx == (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT));
+ Assert(!have_tx || !add_tx);
}
},
[&] {
@@ -132,10 +138,8 @@ FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
[&] {
// test mocktime and expiry
SetMockTime(ConsumeTime(fuzzed_data_provider));
- auto size_before = orphanage.Size();
auto limit = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
- auto n_evicted = WITH_LOCK(g_cs_orphans, return orphanage.LimitOrphans(limit));
- Assert(size_before - n_evicted <= limit);
+ WITH_LOCK(g_cs_orphans, orphanage.LimitOrphans(limit));
Assert(orphanage.Size() <= limit);
});
}
diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp
index f0cff74f94..ba1a634e41 100644
--- a/src/test/fuzz/util.cpp
+++ b/src/test/fuzz/util.cpp
@@ -294,6 +294,7 @@ void FillNode(FuzzedDataProvider& fuzzed_data_provider, ConnmanTestMsg& connman,
connman.Handshake(node,
/*successfully_connected=*/fuzzed_data_provider.ConsumeBool(),
/*remote_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
+ /*local_services=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS),
/*permission_flags=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS),
/*version=*/fuzzed_data_provider.ConsumeIntegralInRange<int32_t>(MIN_PEER_PROTO_VERSION, std::numeric_limits<int32_t>::max()),
/*relay_txs=*/fuzzed_data_provider.ConsumeBool());
@@ -526,6 +527,11 @@ CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept
return net_addr;
}
+CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
+{
+ return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}};
+}
+
FILE* FuzzedFileProvider::open()
{
SetFuzzedErrNo(m_fuzzed_data_provider);
diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h
index d189a50a51..33d9ab3cc3 100644
--- a/src/test/fuzz/util.h
+++ b/src/test/fuzz/util.h
@@ -8,7 +8,7 @@
#include <arith_uint256.h>
#include <chainparamsbase.h>
#include <coins.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <merkleblock.h>
@@ -287,16 +287,12 @@ inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcep
return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
}
-inline CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
-{
- return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
-}
+CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
template <bool ReturnUniquePtr = false>
auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept
{
const NodeId node_id = node_id_in.value_or(fuzzed_data_provider.ConsumeIntegralInRange<NodeId>(0, std::numeric_limits<NodeId>::max()));
- const ServiceFlags local_services = ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS);
const auto sock = std::make_shared<FuzzedSock>(fuzzed_data_provider);
const CAddress address = ConsumeAddress(fuzzed_data_provider);
const uint64_t keyed_net_group = fuzzed_data_provider.ConsumeIntegral<uint64_t>();
@@ -307,7 +303,6 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
const bool inbound_onion{conn_type == ConnectionType::INBOUND ? fuzzed_data_provider.ConsumeBool() : false};
if constexpr (ReturnUniquePtr) {
return std::make_unique<CNode>(node_id,
- local_services,
sock,
address,
keyed_net_group,
@@ -318,7 +313,6 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N
inbound_onion);
} else {
return CNode{node_id,
- local_services,
sock,
address,
keyed_net_group,
@@ -361,17 +355,16 @@ public:
class FuzzedAutoFileProvider
{
- FuzzedDataProvider& m_fuzzed_data_provider;
FuzzedFileProvider m_fuzzed_file_provider;
public:
- FuzzedAutoFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider}, m_fuzzed_file_provider{fuzzed_data_provider}
+ FuzzedAutoFileProvider(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_file_provider{fuzzed_data_provider}
{
}
- CAutoFile open()
+ AutoFile open()
{
- return {m_fuzzed_file_provider.open(), m_fuzzed_data_provider.ConsumeIntegral<int>(), m_fuzzed_data_provider.ConsumeIntegral<int>()};
+ return AutoFile{m_fuzzed_file_provider.open()};
}
};
diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp
index 33496a457e..0b596492be 100644
--- a/src/test/fuzz/utxo_snapshot.cpp
+++ b/src/test/fuzz/utxo_snapshot.cpp
@@ -39,13 +39,13 @@ FUZZ_TARGET_INIT(utxo_snapshot, initialize_chain)
Assert(!chainman.SnapshotBlockhash());
{
- CAutoFile outfile{fsbridge::fopen(snapshot_path, "wb"), SER_DISK, CLIENT_VERSION};
+ AutoFile outfile{fsbridge::fopen(snapshot_path, "wb")};
const auto file_data{ConsumeRandomLengthByteVector(fuzzed_data_provider)};
outfile << Span{file_data};
}
const auto ActivateFuzzedSnapshot{[&] {
- CAutoFile infile{fsbridge::fopen(snapshot_path, "rb"), SER_DISK, CLIENT_VERSION};
+ AutoFile infile{fsbridge::fopen(snapshot_path, "rb")};
SnapshotMetadata metadata;
try {
infile >> metadata;
diff --git a/src/test/fuzz/validation_load_mempool.cpp b/src/test/fuzz/validation_load_mempool.cpp
index 9532610f8d..8241dff189 100644
--- a/src/test/fuzz/validation_load_mempool.cpp
+++ b/src/test/fuzz/validation_load_mempool.cpp
@@ -2,10 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <kernel/mempool_persist.h>
+
#include <chainparamsbase.h>
-#include <mempool_args.h>
+#include <node/mempool_args.h>
+#include <node/mempool_persist_args.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
+#include <test/fuzz/mempool_utils.h>
#include <test/fuzz/util.h>
#include <test/util/setup_common.h>
#include <txmempool.h>
@@ -15,6 +19,10 @@
#include <cstdint>
#include <vector>
+using kernel::DumpMempool;
+
+using node::MempoolPath;
+
namespace {
const TestingSetup* g_setup;
} // namespace
@@ -33,9 +41,12 @@ FUZZ_TARGET_INIT(validation_load_mempool, initialize_validation_load_mempool)
CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)};
+ auto& chainstate{static_cast<DummyChainState&>(g_setup->m_node.chainman->ActiveChainstate())};
+ chainstate.SetMempool(&pool);
+
auto fuzzed_fopen = [&](const fs::path&, const char*) {
return fuzzed_file_provider.open();
};
- (void)LoadMempool(pool, g_setup->m_node.chainman->ActiveChainstate(), fuzzed_fopen);
- (void)DumpMempool(pool, fuzzed_fopen, true);
+ (void)chainstate.LoadMempool(MempoolPath(g_setup->m_args), fuzzed_fopen);
+ (void)DumpMempool(pool, MempoolPath(g_setup->m_args), fuzzed_fopen, true);
}
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 20d670c1e1..d88aed7d4a 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -325,7 +325,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
- m_node.chainman->ActiveChain().SetTip(next);
+ m_node.chainman->ActiveChain().SetTip(*next);
}
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
// Extend to a 210000-long block chain.
@@ -337,7 +337,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
next->pprev = prev;
next->nHeight = prev->nHeight + 1;
next->BuildSkip();
- m_node.chainman->ActiveChain().SetTip(next);
+ m_node.chainman->ActiveChain().SetTip(*next);
}
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
@@ -362,7 +362,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
// Delete the dummy blocks again.
while (m_node.chainman->ActiveChain().Tip()->nHeight > nHeight) {
CBlockIndex* del = m_node.chainman->ActiveChain().Tip();
- m_node.chainman->ActiveChain().SetTip(del->pprev);
+ m_node.chainman->ActiveChain().SetTip(*Assert(del->pprev));
m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(del->pprev->GetBlockHash());
delete del->phashBlock;
delete del;
@@ -389,7 +389,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
tx.nLockTime = 0;
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
- BOOST_CHECK(CheckFinalTxAtTip(m_node.chainman->ActiveChain().Tip(), CTransaction{tx})); // Locktime passes
+ BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes
BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
{
@@ -403,7 +403,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
prevheights[0] = baseheight + 2;
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
- BOOST_CHECK(CheckFinalTxAtTip(m_node.chainman->ActiveChain().Tip(), CTransaction{tx})); // Locktime passes
+ BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes
BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
const int SEQUENCE_LOCK_TIME = 512; // Sequence locks pass 512 seconds later
@@ -426,7 +426,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
tx.nLockTime = m_node.chainman->ActiveChain().Tip()->nHeight + 1;
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
- BOOST_CHECK(!CheckFinalTxAtTip(m_node.chainman->ActiveChain().Tip(), CTransaction{tx})); // Locktime fails
+ BOOST_CHECK(!CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime fails
BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast())); // Locktime passes on 2nd block
@@ -437,7 +437,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
prevheights[0] = baseheight + 4;
hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx));
- BOOST_CHECK(!CheckFinalTxAtTip(m_node.chainman->ActiveChain().Tip(), CTransaction{tx})); // Locktime fails
+ BOOST_CHECK(!CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime fails
BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later
@@ -446,7 +446,7 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
prevheights[0] = m_node.chainman->ActiveChain().Tip()->nHeight + 1;
tx.nLockTime = 0;
tx.vin[0].nSequence = 0;
- BOOST_CHECK(CheckFinalTxAtTip(m_node.chainman->ActiveChain().Tip(), CTransaction{tx})); // Locktime passes
+ BOOST_CHECK(CheckFinalTxAtTip(*Assert(m_node.chainman->ActiveChain().Tip()), CTransaction{tx})); // Locktime passes
BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass
tx.vin[0].nSequence = 1;
BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail
diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp
index bc5c49ef63..95e8476b77 100644
--- a/src/test/miniscript_tests.cpp
+++ b/src/test/miniscript_tests.cpp
@@ -120,6 +120,8 @@ struct KeyConverter {
//! Singleton instance of KeyConverter.
const KeyConverter CONVERTER{};
+// https://github.com/llvm/llvm-project/issues/53444
+// NOLINTNEXTLINE(misc-unused-using-decls)
using miniscript::operator"" _mst;
enum TestMode : int {
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index dccc7ce795..ce23d6013d 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -141,23 +141,30 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
for (int i = 0; i < 4; i++)
key[i].MakeNewKey(true);
- TxoutType whichType;
+ const auto is_standard{[](const CScript& spk) {
+ TxoutType type;
+ bool res{::IsStandard(spk, std::nullopt, type)};
+ if (res) {
+ BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);
+ }
+ return res;
+ }};
CScript a_and_b;
a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(::IsStandard(a_and_b, whichType));
+ BOOST_CHECK(is_standard(a_and_b));
CScript a_or_b;
a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
- BOOST_CHECK(::IsStandard(a_or_b, whichType));
+ BOOST_CHECK(is_standard(a_or_b));
CScript escrow;
escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
- BOOST_CHECK(::IsStandard(escrow, whichType));
+ BOOST_CHECK(is_standard(escrow));
CScript one_of_four;
one_of_four << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << ToByteVector(key[3].GetPubKey()) << OP_4 << OP_CHECKMULTISIG;
- BOOST_CHECK(!::IsStandard(one_of_four, whichType));
+ BOOST_CHECK(!is_standard(one_of_four));
CScript malformed[6];
malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
@@ -167,8 +174,9 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG;
malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey());
- for (int i = 0; i < 6; i++)
- BOOST_CHECK(!::IsStandard(malformed[i], whichType));
+ for (int i = 0; i < 6; i++) {
+ BOOST_CHECK(!is_standard(malformed[i]));
+ }
}
BOOST_AUTO_TEST_CASE(multisig_Sign)
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 115c4b9b24..f6642d3218 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -4,7 +4,7 @@
#include <chainparams.h>
#include <clientversion.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <cstdint>
#include <net.h>
#include <net_processing.h>
@@ -58,7 +58,6 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
std::string pszDest;
std::unique_ptr<CNode> pnode1 = std::make_unique<CNode>(id++,
- NODE_NETWORK,
/*sock=*/nullptr,
addr,
/*nKeyedNetGroupIn=*/0,
@@ -77,7 +76,6 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4);
std::unique_ptr<CNode> pnode2 = std::make_unique<CNode>(id++,
- NODE_NETWORK,
/*sock=*/nullptr,
addr,
/*nKeyedNetGroupIn=*/1,
@@ -96,7 +94,6 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4);
std::unique_ptr<CNode> pnode3 = std::make_unique<CNode>(id++,
- NODE_NETWORK,
/*sock=*/nullptr,
addr,
/*nKeyedNetGroupIn=*/0,
@@ -115,7 +112,6 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4);
std::unique_ptr<CNode> pnode4 = std::make_unique<CNode>(id++,
- NODE_NETWORK,
/*sock=*/nullptr,
addr,
/*nKeyedNetGroupIn=*/1,
@@ -629,7 +625,6 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
ipv4AddrPeer.s_addr = 0xa0b0c001;
CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
std::unique_ptr<CNode> pnode = std::make_unique<CNode>(/*id=*/0,
- NODE_NETWORK,
/*sock=*/nullptr,
addr,
/*nKeyedNetGroupIn=*/0,
@@ -648,7 +643,7 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
pnode->SetAddrLocal(addrLocal);
// before patch, this causes undefined behavior detectable with clang's -fsanitize=memory
- GetLocalAddrForPeer(&*pnode);
+ GetLocalAddrForPeer(*pnode);
// suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer
BOOST_CHECK(1);
@@ -675,19 +670,15 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
const uint16_t bind_port = 20001;
m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port));
- const uint32_t current_time = static_cast<uint32_t>(GetAdjustedTime());
- SetMockTime(current_time);
-
// Our address:port as seen from the peer, completely different from the above.
in_addr peer_us_addr;
peer_us_addr.s_addr = htonl(0x02030405);
- const CAddress peer_us{CService{peer_us_addr, 20002}, NODE_NETWORK, current_time};
+ const CService peer_us{peer_us_addr, 20002};
// Create a peer with a routable IPv4 address (outbound).
in_addr peer_out_in_addr;
peer_out_in_addr.s_addr = htonl(0x01020304);
CNode peer_out{/*id=*/0,
- /*nLocalServicesIn=*/NODE_NETWORK,
/*sock=*/nullptr,
/*addrIn=*/CAddress{CService{peer_out_in_addr, 8333}, NODE_NETWORK},
/*nKeyedNetGroupIn=*/0,
@@ -700,16 +691,15 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
peer_out.SetAddrLocal(peer_us);
// Without the fix peer_us:8333 is chosen instead of the proper peer_us:bind_port.
- auto chosen_local_addr = GetLocalAddrForPeer(&peer_out);
+ auto chosen_local_addr = GetLocalAddrForPeer(peer_out);
BOOST_REQUIRE(chosen_local_addr);
- const CAddress expected{CService{peer_us_addr, bind_port}, NODE_NETWORK, current_time};
+ const CService expected{peer_us_addr, bind_port};
BOOST_CHECK(*chosen_local_addr == expected);
// Create a peer with a routable IPv4 address (inbound).
in_addr peer_in_in_addr;
peer_in_in_addr.s_addr = htonl(0x05060708);
CNode peer_in{/*id=*/0,
- /*nLocalServicesIn=*/NODE_NETWORK,
/*sock=*/nullptr,
/*addrIn=*/CAddress{CService{peer_in_in_addr, 8333}, NODE_NETWORK},
/*nKeyedNetGroupIn=*/0,
@@ -722,7 +712,7 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
peer_in.SetAddrLocal(peer_us);
// Without the fix peer_us:8333 is chosen instead of the proper peer_us:peer_us.GetPort().
- chosen_local_addr = GetLocalAddrForPeer(&peer_in);
+ chosen_local_addr = GetLocalAddrForPeer(peer_in);
BOOST_REQUIRE(chosen_local_addr);
BOOST_CHECK(*chosen_local_addr == peer_us);
@@ -837,7 +827,6 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
in_addr peer_in_addr;
peer_in_addr.s_addr = htonl(0x01020304);
CNode peer{/*id=*/0,
- /*nLocalServicesIn=*/NODE_NETWORK,
/*sock=*/nullptr,
/*addrIn=*/CAddress{CService{peer_in_addr, 8333}, NODE_NETWORK},
/*nKeyedNetGroupIn=*/0,
@@ -857,7 +846,7 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
*static_cast<TestChainState*>(&m_node.chainman->ActiveChainstate());
chainstate.JumpOutOfIbd();
- m_node.peerman->InitializeNode(&peer);
+ m_node.peerman->InitializeNode(peer, NODE_NETWORK);
std::atomic<bool> interrupt_dummy{false};
std::chrono::microseconds time_received_dummy{0};
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 224dc88d0f..c2d2fa37b4 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -480,21 +480,21 @@ BOOST_AUTO_TEST_CASE(netbase_dont_resolve_strings_with_embedded_nul_characters)
// try a few edge cases for port, service flags and time.
static const std::vector<CAddress> fixture_addresses({
- CAddress(
+ CAddress{
CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0 /* port */),
NODE_NONE,
- 0x4966bc61U /* Fri Jan 9 02:54:25 UTC 2009 */
- ),
- CAddress(
+ NodeSeconds{0x4966bc61s}, /* Fri Jan 9 02:54:25 UTC 2009 */
+ },
+ CAddress{
CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0x00f1 /* port */),
NODE_NETWORK,
- 0x83766279U /* Tue Nov 22 11:22:33 UTC 2039 */
- ),
- CAddress(
+ NodeSeconds{0x83766279s}, /* Tue Nov 22 11:22:33 UTC 2039 */
+ },
+ CAddress{
CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0xf1f2 /* port */),
static_cast<ServiceFlags>(NODE_WITNESS | NODE_COMPACT_FILTERS | NODE_NETWORK_LIMITED),
- 0xffffffffU /* Sun Feb 7 06:28:15 UTC 2106 */
- )
+ NodeSeconds{0xffffffffs}, /* Sun Feb 7 06:28:15 UTC 2106 */
+ },
});
// fixture_addresses should equal to this when serialized in V1 format.
diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp
index 9b2760fd1c..96fb28dc9f 100644
--- a/src/test/random_tests.cpp
+++ b/src/test/random_tests.cpp
@@ -53,6 +53,16 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50));
+ {
+ struct MicroClock {
+ using duration = std::chrono::microseconds;
+ };
+ FastRandomContext ctx{true};
+ // Check with clock type
+ BOOST_CHECK_EQUAL(47222, ctx.rand_uniform_duration<MicroClock>(1s).count());
+ // Check with time-point type
+ BOOST_CHECK_EQUAL(2782, ctx.rand_uniform_duration<SteadySeconds>(9h).count());
+ }
// Check that a nondeterministic ones are not
g_mock_deterministic_tests = false;
diff --git a/src/test/rbf_tests.cpp b/src/test/rbf_tests.cpp
new file mode 100644
index 0000000000..c88cd36688
--- /dev/null
+++ b/src/test/rbf_tests.cpp
@@ -0,0 +1,230 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <policy/rbf.h>
+#include <random.h>
+#include <txmempool.h>
+#include <util/system.h>
+#include <util/time.h>
+
+#include <test/util/setup_common.h>
+
+#include <boost/test/unit_test.hpp>
+#include <optional>
+#include <vector>
+
+BOOST_FIXTURE_TEST_SUITE(rbf_tests, TestingSetup)
+
+static inline CTransactionRef make_tx(const std::vector<CTransactionRef>& inputs,
+ const std::vector<CAmount>& output_values)
+{
+ CMutableTransaction tx = CMutableTransaction();
+ tx.vin.resize(inputs.size());
+ tx.vout.resize(output_values.size());
+ for (size_t i = 0; i < inputs.size(); ++i) {
+ tx.vin[i].prevout.hash = inputs[i]->GetHash();
+ tx.vin[i].prevout.n = 0;
+ // Add a witness so wtxid != txid
+ CScriptWitness witness;
+ witness.stack.push_back(std::vector<unsigned char>(i + 10));
+ tx.vin[i].scriptWitness = witness;
+ }
+ for (size_t i = 0; i < output_values.size(); ++i) {
+ tx.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx.vout[i].nValue = output_values[i];
+ }
+ return MakeTransactionRef(tx);
+}
+
+static void add_descendants(const CTransactionRef& tx, int32_t num_descendants, CTxMemPool& pool)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs)
+{
+ AssertLockHeld(::cs_main);
+ AssertLockHeld(pool.cs);
+ TestMemPoolEntryHelper entry;
+ // Assumes this isn't already spent in mempool
+ auto tx_to_spend = tx;
+ for (int32_t i{0}; i < num_descendants; ++i) {
+ auto next_tx = make_tx(/*inputs=*/{tx_to_spend}, /*output_values=*/{(50 - i) * CENT});
+ pool.addUnchecked(entry.FromTx(next_tx));
+ tx_to_spend = next_tx;
+ }
+}
+
+BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
+{
+ CTxMemPool& pool = *Assert(m_node.mempool);
+ LOCK2(::cs_main, pool.cs);
+ TestMemPoolEntryHelper entry;
+
+ const CAmount low_fee{CENT/100};
+ const CAmount normal_fee{CENT/10};
+ const CAmount high_fee{CENT};
+
+ // Create a parent tx1 and child tx2 with normal fees:
+ const auto tx1 = make_tx(/*inputs=*/ {m_coinbase_txns[0]}, /*output_values=*/ {10 * COIN});
+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx1));
+ const auto tx2 = make_tx(/*inputs=*/ {tx1}, /*output_values=*/ {995 * CENT});
+ pool.addUnchecked(entry.Fee(normal_fee).FromTx(tx2));
+
+ // Create a low-feerate parent tx3 and high-feerate child tx4 (cpfp)
+ const auto tx3 = make_tx(/*inputs=*/ {m_coinbase_txns[1]}, /*output_values=*/ {1099 * CENT});
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx3));
+ const auto tx4 = make_tx(/*inputs=*/ {tx3}, /*output_values=*/ {999 * CENT});
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx4));
+
+ // Create a parent tx5 and child tx6 where both have very low fees
+ const auto tx5 = make_tx(/*inputs=*/ {m_coinbase_txns[2]}, /*output_values=*/ {1099 * CENT});
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx5));
+ const auto tx6 = make_tx(/*inputs=*/ {tx5}, /*output_values=*/ {1098 * CENT});
+ pool.addUnchecked(entry.Fee(low_fee).FromTx(tx6));
+ // Make tx6's modified fee much higher than its base fee. This should cause it to pass
+ // the fee-related checks despite being low-feerate.
+ pool.PrioritiseTransaction(tx6->GetHash(), 1 * COIN);
+
+ // Two independent high-feerate transactions, tx7 and tx8
+ const auto tx7 = make_tx(/*inputs=*/ {m_coinbase_txns[3]}, /*output_values=*/ {999 * CENT});
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx7));
+ const auto tx8 = make_tx(/*inputs=*/ {m_coinbase_txns[4]}, /*output_values=*/ {999 * CENT});
+ pool.addUnchecked(entry.Fee(high_fee).FromTx(tx8));
+
+ const auto entry1 = pool.GetIter(tx1->GetHash()).value();
+ const auto entry2 = pool.GetIter(tx2->GetHash()).value();
+ const auto entry3 = pool.GetIter(tx3->GetHash()).value();
+ const auto entry4 = pool.GetIter(tx4->GetHash()).value();
+ const auto entry5 = pool.GetIter(tx5->GetHash()).value();
+ const auto entry6 = pool.GetIter(tx6->GetHash()).value();
+ const auto entry7 = pool.GetIter(tx7->GetHash()).value();
+ const auto entry8 = pool.GetIter(tx8->GetHash()).value();
+
+ BOOST_CHECK_EQUAL(entry1->GetFee(), normal_fee);
+ BOOST_CHECK_EQUAL(entry2->GetFee(), normal_fee);
+ BOOST_CHECK_EQUAL(entry3->GetFee(), low_fee);
+ BOOST_CHECK_EQUAL(entry4->GetFee(), high_fee);
+ BOOST_CHECK_EQUAL(entry5->GetFee(), low_fee);
+ BOOST_CHECK_EQUAL(entry6->GetFee(), low_fee);
+ BOOST_CHECK_EQUAL(entry7->GetFee(), high_fee);
+ BOOST_CHECK_EQUAL(entry8->GetFee(), high_fee);
+
+ CTxMemPool::setEntries set_12_normal{entry1, entry2};
+ CTxMemPool::setEntries set_34_cpfp{entry3, entry4};
+ CTxMemPool::setEntries set_56_low{entry5, entry6};
+ CTxMemPool::setEntries all_entries{entry1, entry2, entry3, entry4, entry5, entry6, entry7, entry8};
+ CTxMemPool::setEntries empty_set;
+
+ const auto unused_txid{GetRandHash()};
+
+ // Tests for PaysMoreThanConflicts
+ // These tests use feerate, not absolute fee.
+ BOOST_CHECK(PaysMoreThanConflicts(/*iters_conflicting=*/set_12_normal,
+ /*replacement_feerate=*/CFeeRate(entry1->GetModifiedFee() + 1, entry1->GetTxSize() + 2),
+ /*txid=*/unused_txid).has_value());
+ // Replacement must be strictly greater than the originals.
+ BOOST_CHECK(PaysMoreThanConflicts(set_12_normal, CFeeRate(entry1->GetModifiedFee(), entry1->GetTxSize()), unused_txid).has_value());
+ BOOST_CHECK(PaysMoreThanConflicts(set_12_normal, CFeeRate(entry1->GetModifiedFee() + 1, entry1->GetTxSize()), unused_txid) == std::nullopt);
+ // These tests use modified fees (including prioritisation), not base fees.
+ BOOST_CHECK(PaysMoreThanConflicts({entry5}, CFeeRate(entry5->GetModifiedFee() + 1, entry5->GetTxSize()), unused_txid) == std::nullopt);
+ BOOST_CHECK(PaysMoreThanConflicts({entry6}, CFeeRate(entry6->GetFee() + 1, entry6->GetTxSize()), unused_txid).has_value());
+ BOOST_CHECK(PaysMoreThanConflicts({entry6}, CFeeRate(entry6->GetModifiedFee() + 1, entry6->GetTxSize()), unused_txid) == std::nullopt);
+ // PaysMoreThanConflicts checks individual feerate, not ancestor feerate. This test compares
+ // replacement_feerate and entry4's feerate, which are the same. The replacement_feerate is
+ // considered too low even though entry4 has a low ancestor feerate.
+ BOOST_CHECK(PaysMoreThanConflicts(set_34_cpfp, CFeeRate(entry4->GetModifiedFee(), entry4->GetTxSize()), unused_txid).has_value());
+
+ // Tests for EntriesAndTxidsDisjoint
+ BOOST_CHECK(EntriesAndTxidsDisjoint(empty_set, {tx1->GetHash()}, unused_txid) == std::nullopt);
+ BOOST_CHECK(EntriesAndTxidsDisjoint(set_12_normal, {tx3->GetHash()}, unused_txid) == std::nullopt);
+ // EntriesAndTxidsDisjoint uses txids, not wtxids.
+ BOOST_CHECK(EntriesAndTxidsDisjoint({entry2}, {tx2->GetWitnessHash()}, unused_txid) == std::nullopt);
+ BOOST_CHECK(EntriesAndTxidsDisjoint({entry2}, {tx2->GetHash()}, unused_txid).has_value());
+ BOOST_CHECK(EntriesAndTxidsDisjoint(set_12_normal, {tx1->GetHash()}, unused_txid).has_value());
+ BOOST_CHECK(EntriesAndTxidsDisjoint(set_12_normal, {tx2->GetHash()}, unused_txid).has_value());
+ // EntriesAndTxidsDisjoint does not calculate descendants of iters_conflicting; it uses whatever
+ // the caller passed in. As such, no error is returned even though entry2 is a descendant of tx1.
+ BOOST_CHECK(EntriesAndTxidsDisjoint({entry2}, {tx1->GetHash()}, unused_txid) == std::nullopt);
+
+ // Tests for PaysForRBF
+ const CFeeRate incremental_relay_feerate{DEFAULT_INCREMENTAL_RELAY_FEE};
+ const CFeeRate higher_relay_feerate{2 * DEFAULT_INCREMENTAL_RELAY_FEE};
+ // Must pay at least as much as the original.
+ BOOST_CHECK(PaysForRBF(/*original_fees=*/high_fee,
+ /*replacement_fees=*/high_fee,
+ /*replacement_vsize=*/1,
+ /*relay_fee=*/CFeeRate(0),
+ /*txid=*/unused_txid)
+ == std::nullopt);
+ BOOST_CHECK(PaysForRBF(high_fee, high_fee - 1, 1, CFeeRate(0), unused_txid).has_value());
+ BOOST_CHECK(PaysForRBF(high_fee + 1, high_fee, 1, CFeeRate(0), unused_txid).has_value());
+ // Additional fees must cover the replacement's vsize at incremental relay fee
+ BOOST_CHECK(PaysForRBF(high_fee, high_fee + 1, 2, incremental_relay_feerate, unused_txid).has_value());
+ BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 2, incremental_relay_feerate, unused_txid) == std::nullopt);
+ BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 2, higher_relay_feerate, unused_txid).has_value());
+ BOOST_CHECK(PaysForRBF(high_fee, high_fee + 4, 2, higher_relay_feerate, unused_txid) == std::nullopt);
+ BOOST_CHECK(PaysForRBF(low_fee, high_fee, 99999999, incremental_relay_feerate, unused_txid).has_value());
+ BOOST_CHECK(PaysForRBF(low_fee, high_fee + 99999999, 99999999, incremental_relay_feerate, unused_txid) == std::nullopt);
+
+ // Tests for GetEntriesForConflicts
+ CTxMemPool::setEntries all_parents{entry1, entry3, entry5, entry7, entry8};
+ CTxMemPool::setEntries all_children{entry2, entry4, entry6};
+ const std::vector<CTransactionRef> parent_inputs({m_coinbase_txns[0], m_coinbase_txns[1], m_coinbase_txns[2],
+ m_coinbase_txns[3], m_coinbase_txns[4]});
+ const auto conflicts_with_parents = make_tx(parent_inputs, {50 * CENT});
+ CTxMemPool::setEntries all_conflicts;
+ BOOST_CHECK(GetEntriesForConflicts(/*tx=*/ *conflicts_with_parents.get(),
+ /*pool=*/ pool,
+ /*iters_conflicting=*/ all_parents,
+ /*all_conflicts=*/ all_conflicts) == std::nullopt);
+ BOOST_CHECK(all_conflicts == all_entries);
+ auto conflicts_size = all_conflicts.size();
+ all_conflicts.clear();
+
+ add_descendants(tx2, 23, pool);
+ BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
+ conflicts_size += 23;
+ BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
+ all_conflicts.clear();
+
+ add_descendants(tx4, 23, pool);
+ BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
+ conflicts_size += 23;
+ BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
+ all_conflicts.clear();
+
+ add_descendants(tx6, 23, pool);
+ BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
+ conflicts_size += 23;
+ BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
+ all_conflicts.clear();
+
+ add_descendants(tx7, 23, pool);
+ BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts) == std::nullopt);
+ conflicts_size += 23;
+ BOOST_CHECK_EQUAL(all_conflicts.size(), conflicts_size);
+ BOOST_CHECK_EQUAL(all_conflicts.size(), 100);
+ all_conflicts.clear();
+
+ // Exceeds maximum number of conflicts.
+ add_descendants(tx8, 1, pool);
+ BOOST_CHECK(GetEntriesForConflicts(*conflicts_with_parents.get(), pool, all_parents, all_conflicts).has_value());
+
+ // Tests for HasNoNewUnconfirmed
+ const auto spends_unconfirmed = make_tx({tx1}, {36 * CENT});
+ for (const auto& input : spends_unconfirmed->vin) {
+ // Spends unconfirmed inputs.
+ BOOST_CHECK(pool.exists(GenTxid::Txid(input.prevout.hash)));
+ }
+ BOOST_CHECK(HasNoNewUnconfirmed(/*tx=*/ *spends_unconfirmed.get(),
+ /*pool=*/ pool,
+ /*iters_conflicting=*/ all_entries) == std::nullopt);
+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, {entry2}) == std::nullopt);
+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_unconfirmed.get(), pool, empty_set).has_value());
+
+ const auto spends_new_unconfirmed = make_tx({tx1, tx8}, {36 * CENT});
+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, {entry2}).has_value());
+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_new_unconfirmed.get(), pool, all_entries).has_value());
+
+ const auto spends_conflicting_confirmed = make_tx({m_coinbase_txns[0], m_coinbase_txns[1]}, {45 * CENT});
+ BOOST_CHECK(HasNoNewUnconfirmed(*spends_conflicting_confirmed.get(), pool, {entry1, entry3}) == std::nullopt);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/result_tests.cpp b/src/test/result_tests.cpp
new file mode 100644
index 0000000000..6a23a7b895
--- /dev/null
+++ b/src/test/result_tests.cpp
@@ -0,0 +1,96 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <util/result.h>
+
+#include <boost/test/unit_test.hpp>
+
+inline bool operator==(const bilingual_str& a, const bilingual_str& b)
+{
+ return a.original == b.original && a.translated == b.translated;
+}
+
+inline std::ostream& operator<<(std::ostream& os, const bilingual_str& s)
+{
+ return os << "bilingual_str('" << s.original << "' , '" << s.translated << "')";
+}
+
+BOOST_AUTO_TEST_SUITE(result_tests)
+
+struct NoCopy {
+ NoCopy(int n) : m_n{std::make_unique<int>(n)} {}
+ std::unique_ptr<int> m_n;
+};
+
+bool operator==(const NoCopy& a, const NoCopy& b)
+{
+ return *a.m_n == *b.m_n;
+}
+
+std::ostream& operator<<(std::ostream& os, const NoCopy& o)
+{
+ return os << "NoCopy(" << *o.m_n << ")";
+}
+
+util::Result<int> IntFn(int i, bool success)
+{
+ if (success) return i;
+ return util::Error{Untranslated(strprintf("int %i error.", i))};
+}
+
+util::Result<bilingual_str> StrFn(bilingual_str s, bool success)
+{
+ if (success) return s;
+ return util::Error{strprintf(Untranslated("str %s error."), s.original)};
+}
+
+util::Result<NoCopy> NoCopyFn(int i, bool success)
+{
+ if (success) return {i};
+ return util::Error{Untranslated(strprintf("nocopy %i error.", i))};
+}
+
+template <typename T>
+void ExpectResult(const util::Result<T>& result, bool success, const bilingual_str& str)
+{
+ BOOST_CHECK_EQUAL(bool(result), success);
+ BOOST_CHECK_EQUAL(util::ErrorString(result), str);
+}
+
+template <typename T, typename... Args>
+void ExpectSuccess(const util::Result<T>& result, const bilingual_str& str, Args&&... args)
+{
+ ExpectResult(result, true, str);
+ BOOST_CHECK_EQUAL(result.has_value(), true);
+ BOOST_CHECK_EQUAL(result.value(), T{std::forward<Args>(args)...});
+ BOOST_CHECK_EQUAL(&result.value(), &*result);
+}
+
+template <typename T, typename... Args>
+void ExpectFail(const util::Result<T>& result, const bilingual_str& str)
+{
+ ExpectResult(result, false, str);
+}
+
+BOOST_AUTO_TEST_CASE(check_returned)
+{
+ ExpectSuccess(IntFn(5, true), {}, 5);
+ ExpectFail(IntFn(5, false), Untranslated("int 5 error."));
+ ExpectSuccess(NoCopyFn(5, true), {}, 5);
+ ExpectFail(NoCopyFn(5, false), Untranslated("nocopy 5 error."));
+ ExpectSuccess(StrFn(Untranslated("S"), true), {}, Untranslated("S"));
+ ExpectFail(StrFn(Untranslated("S"), false), Untranslated("str S error."));
+}
+
+BOOST_AUTO_TEST_CASE(check_value_or)
+{
+ BOOST_CHECK_EQUAL(IntFn(10, true).value_or(20), 10);
+ BOOST_CHECK_EQUAL(IntFn(10, false).value_or(20), 20);
+ BOOST_CHECK_EQUAL(NoCopyFn(10, true).value_or(20), 10);
+ BOOST_CHECK_EQUAL(NoCopyFn(10, false).value_or(20), 20);
+ BOOST_CHECK_EQUAL(StrFn(Untranslated("A"), true).value_or(Untranslated("B")), Untranslated("A"));
+ BOOST_CHECK_EQUAL(StrFn(Untranslated("A"), false).value_or(Untranslated("B")), Untranslated("B"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 3e9e04da25..a52530e179 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -181,10 +181,10 @@ BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
BOOST_CHECK_EQUAL(ValueFromAmount(std::numeric_limits<CAmount>::min()).write(), "-92233720368.54775808");
}
-static UniValue ValueFromString(const std::string &str)
+static UniValue ValueFromString(const std::string& str) noexcept
{
UniValue value;
- BOOST_CHECK(value.setNumStr(str));
+ value.setNumStr(str);
return value;
}
diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp
index a221e02d2f..a02d51eecc 100644
--- a/src/test/script_p2sh_tests.cpp
+++ b/src/test/script_p2sh_tests.cpp
@@ -18,15 +18,18 @@
#include <boost/test/unit_test.hpp>
// Helpers:
-static std::vector<unsigned char>
-Serialize(const CScript& s)
+static bool IsStandardTx(const CTransaction& tx, std::string& reason)
+{
+ return IsStandardTx(tx, std::nullopt, DEFAULT_PERMIT_BAREMULTISIG, CFeeRate{DUST_RELAY_TX_FEE}, reason);
+}
+
+static std::vector<unsigned char> Serialize(const CScript& s)
{
std::vector<unsigned char> sSerialized(s.begin(), s.end());
return sSerialized;
}
-static bool
-Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
+static bool Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
{
// Create dummy to/from transactions:
CMutableTransaction txFrom;
@@ -49,7 +52,6 @@ BOOST_FIXTURE_TEST_SUITE(script_p2sh_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(sign)
{
- LOCK(cs_main);
// Pay-to-script-hash looks like this:
// scriptSig: <sig> <sig...> <serialized_script>
// scriptPubKey: HASH160 <hash> EQUAL
@@ -149,7 +151,6 @@ BOOST_AUTO_TEST_CASE(norecurse)
BOOST_AUTO_TEST_CASE(set)
{
- LOCK(cs_main);
// Test the CScript::Set* methods
FillableSigningProvider keystore;
CKey key[4];
@@ -263,7 +264,6 @@ BOOST_AUTO_TEST_CASE(switchover)
BOOST_AUTO_TEST_CASE(AreInputsStandard)
{
- LOCK(cs_main);
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
FillableSigningProvider keystore;
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 05bb89ab55..9e7a376d6b 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1514,8 +1514,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_returns_true)
CScriptWitness wit;
scriptPubKey << OP_1;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << spendTx;
@@ -1537,8 +1537,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_index_err)
CScriptWitness wit;
scriptPubKey << OP_EQUAL;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << spendTx;
@@ -1560,8 +1560,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_size)
CScriptWitness wit;
scriptPubKey << OP_EQUAL;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << spendTx;
@@ -1583,8 +1583,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_serialization)
CScriptWitness wit;
scriptPubKey << OP_EQUAL;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << 0xffffffff;
@@ -1606,8 +1606,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_amount_required_err)
CScriptWitness wit;
scriptPubKey << OP_EQUAL;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << spendTx;
@@ -1629,8 +1629,8 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_invalid_flags)
CScriptWitness wit;
scriptPubKey << OP_EQUAL;
- CTransaction creditTx = BuildCreditingTransaction(scriptPubKey, 1);
- CTransaction spendTx = BuildSpendingTransaction(scriptSig, wit, creditTx);
+ CTransaction creditTx{BuildCreditingTransaction(scriptPubKey, 1)};
+ CTransaction spendTx{BuildSpendingTransaction(scriptSig, wit, creditTx)};
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << spendTx;
@@ -1813,7 +1813,7 @@ BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors)
BOOST_CHECK_EQUAL(HexStr(sighash), input["intermediary"]["sigHash"].get_str());
// To verify the sigmsg, hash the expected sigmsg, and compare it with the (expected) sighash.
- BOOST_CHECK_EQUAL(HexStr((CHashWriter(HASHER_TAPSIGHASH) << Span{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
+ BOOST_CHECK_EQUAL(HexStr((HashWriter{HASHER_TAPSIGHASH} << Span{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
}
}
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index 6dadf09176..3d3fd5d93d 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -72,7 +72,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
// Build a CChain for the main branch.
CChain chain;
- chain.SetTip(&vBlocksMain.back());
+ chain.SetTip(vBlocksMain.back());
// Test 100 random starting points for locators.
for (int n=0; n<100; n++) {
@@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test)
// Build a CChain for the main branch.
CChain chain;
- chain.SetTip(&vBlocksMain.back());
+ chain.SetTip(vBlocksMain.back());
// Verify that FindEarliestAtLeast is correct.
for (unsigned int i=0; i<10000; ++i) {
@@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_edge_test)
}
CChain chain;
- chain.SetTip(&blocks.back());
+ chain.SetTip(blocks.back());
BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(50, 0)->nHeight, 0);
BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(100, 0)->nHeight, 0);
diff --git a/src/test/sock_tests.cpp b/src/test/sock_tests.cpp
index 01a402833d..8376ec1a68 100644
--- a/src/test/sock_tests.cpp
+++ b/src/test/sock_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <compat.h>
+#include <compat/compat.h>
#include <test/util/setup_common.h>
#include <threadinterrupt.h>
#include <util/sock.h>
diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp
index 3f5353b5a2..f160bb08a5 100644
--- a/src/test/system_tests.cpp
+++ b/src/test/system_tests.cpp
@@ -7,11 +7,6 @@
#include <univalue.h>
#ifdef ENABLE_EXTERNAL_SIGNER
-#if defined(WIN32) && !defined(__kernel_entry)
-// A workaround for boost 1.71 incompatibility with mingw-w64 compiler.
-// For details see https://github.com/bitcoin/bitcoin/pull/22348.
-#define __kernel_entry
-#endif
#if defined(__GNUC__)
// Boost 1.78 requires the following workaround.
// See: https://github.com/boostorg/process/issues/235
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 4e6c223ccc..cd6bf11327 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -40,6 +40,9 @@ typedef std::vector<unsigned char> valtype;
// In script_tests.cpp
UniValue read_json(const std::string& jsondata);
+static CFeeRate g_dust{DUST_RELAY_TX_FEE};
+static bool g_bare_multi{DEFAULT_PERMIT_BAREMULTISIG};
+
static std::map<std::string, unsigned int> mapFlagNames = {
{std::string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH},
{std::string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC},
@@ -745,7 +748,6 @@ BOOST_AUTO_TEST_CASE(test_witness)
BOOST_AUTO_TEST_CASE(test_IsStandard)
{
- LOCK(cs_main);
FillableSigningProvider keystore;
CCoinsView coinsDummy;
CCoinsViewCache coins(&coinsDummy);
@@ -765,19 +767,19 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
constexpr auto CheckIsStandard = [](const auto& t) {
std::string reason;
- BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
+ BOOST_CHECK(IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason));
BOOST_CHECK(reason.empty());
};
constexpr auto CheckIsNotStandard = [](const auto& t, const std::string& reason_in) {
std::string reason;
- BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
+ BOOST_CHECK(!IsStandardTx(CTransaction{t}, MAX_OP_RETURN_RELAY, g_bare_multi, g_dust, reason));
BOOST_CHECK_EQUAL(reason_in, reason);
};
CheckIsStandard(t);
// Check dust with default relay fee:
- CAmount nDustThreshold = 182 * dustRelayFee.GetFeePerK() / 1000;
+ CAmount nDustThreshold = 182 * g_dust.GetFeePerK() / 1000;
BOOST_CHECK_EQUAL(nDustThreshold, 546);
// dust:
t.vout[0].nValue = nDustThreshold - 1;
@@ -805,14 +807,14 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
// Check dust with odd relay fee to verify rounding:
// nDustThreshold = 182 * 3702 / 1000
- dustRelayFee = CFeeRate(3702);
+ g_dust = CFeeRate(3702);
// dust:
t.vout[0].nValue = 674 - 1;
CheckIsNotStandard(t, "dust");
// not dust:
t.vout[0].nValue = 674;
CheckIsStandard(t);
- dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
+ g_dust = CFeeRate{DUST_RELAY_TX_FEE};
t.vout[0].scriptPubKey = CScript() << OP_1;
CheckIsNotStandard(t, "scriptpubkey");
@@ -924,16 +926,16 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(t)), 400004);
CheckIsNotStandard(t, "tx-size");
- // Check bare multisig (standard if policy flag fIsBareMultisigStd is set)
- fIsBareMultisigStd = true;
+ // Check bare multisig (standard if policy flag g_bare_multi is set)
+ g_bare_multi = true;
t.vout[0].scriptPubKey = GetScriptForMultisig(1, {key.GetPubKey()}); // simple 1-of-1
t.vin.resize(1);
t.vin[0].scriptSig = CScript() << std::vector<unsigned char>(65, 0);
CheckIsStandard(t);
- fIsBareMultisigStd = false;
+ g_bare_multi = false;
CheckIsNotStandard(t, "bare-multisig");
- fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
+ g_bare_multi = DEFAULT_PERMIT_BAREMULTISIG;
// Check P2WPKH outputs dust threshold
t.vout[0].scriptPubKey = CScript() << OP_0 << ParseHex("ffffffffffffffffffffffffffffffffffffffff");
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp
index 15213f826b..62c7ddb673 100644
--- a/src/test/txindex_tests.cpp
+++ b/src/test/txindex_tests.cpp
@@ -4,6 +4,7 @@
#include <chainparams.h>
#include <index/txindex.h>
+#include <interfaces/chain.h>
#include <script/standard.h>
#include <test/util/setup_common.h>
#include <util/time.h>
@@ -15,7 +16,7 @@ BOOST_AUTO_TEST_SUITE(txindex_tests)
BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
{
- TxIndex txindex(1 << 20, true);
+ TxIndex txindex(interfaces::MakeChain(m_node), 1 << 20, true);
CTransactionRef tx_disk;
uint256 block_hash;
@@ -28,7 +29,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
// BlockUntilSyncedToCurrentChain should return false before txindex is started.
BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain());
- BOOST_REQUIRE(txindex.Start(m_node.chainman->ActiveChainstate()));
+ BOOST_REQUIRE(txindex.Start());
// Allow tx index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000;
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index dd4bc5af75..633f75ff4f 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -161,11 +161,6 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup)
{
// Test that passing CheckInputScripts with one set of script flags doesn't imply
// that we would pass again with a different set of flags.
- {
- LOCK(cs_main);
- InitScriptExecutionCache();
- }
-
CScript p2pk_scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
CScript p2sh_scriptPubKey = GetScriptForDestination(ScriptHash(p2pk_scriptPubKey));
CScript p2pkh_scriptPubKey = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h
index 5ac504c24f..13e0e684b8 100644
--- a/src/test/util/chainstate.h
+++ b/src/test/util/chainstate.h
@@ -16,7 +16,7 @@
#include <boost/test/unit_test.hpp>
-const auto NoMalleation = [](CAutoFile& file, node::SnapshotMetadata& meta){};
+const auto NoMalleation = [](AutoFile& file, node::SnapshotMetadata& meta){};
/**
* Create and activate a UTXO snapshot, optionally providing a function to
@@ -32,7 +32,7 @@ CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F ma
WITH_LOCK(::cs_main, height = node.chainman->ActiveHeight());
fs::path snapshot_path = root / fs::u8path(tfm::format("test_snapshot.%d.dat", height));
FILE* outfile{fsbridge::fopen(snapshot_path, "wb")};
- CAutoFile auto_outfile{outfile, SER_DISK, CLIENT_VERSION};
+ AutoFile auto_outfile{outfile};
UniValue result = CreateUTXOSnapshot(
node, node.chainman->ActiveChainstate(), auto_outfile, snapshot_path, snapshot_path);
@@ -42,7 +42,7 @@ CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F ma
// Read the written snapshot in and then activate it.
//
FILE* infile{fsbridge::fopen(snapshot_path, "rb")};
- CAutoFile auto_infile{infile, SER_DISK, CLIENT_VERSION};
+ AutoFile auto_infile{infile};
node::SnapshotMetadata metadata;
auto_infile >> metadata;
diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp
index e70ad036bd..223db16c6c 100644
--- a/src/test/util/net.cpp
+++ b/src/test/util/net.cpp
@@ -16,6 +16,7 @@
void ConnmanTestMsg::Handshake(CNode& node,
bool successfully_connected,
ServiceFlags remote_services,
+ ServiceFlags local_services,
NetPermissionFlags permission_flags,
int32_t version,
bool relay_txs)
@@ -24,7 +25,7 @@ void ConnmanTestMsg::Handshake(CNode& node,
auto& connman{*this};
const CNetMsgMaker mm{0};
- peerman.InitializeNode(&node);
+ peerman.InitializeNode(node, local_services);
CSerializedNetMsg msg_version{
mm.Make(NetMsgType::VERSION,
@@ -51,10 +52,10 @@ void ConnmanTestMsg::Handshake(CNode& node,
if (node.fDisconnect) return;
assert(node.nVersion == version);
assert(node.GetCommonVersion() == std::min(version, PROTOCOL_VERSION));
- assert(node.nServices == remote_services);
CNodeStateStats statestats;
assert(peerman.GetNodeStateStats(node.GetId(), statestats));
assert(statestats.m_relay_txs == (relay_txs && !node.IsBlockOnlyConn()));
+ assert(statestats.their_services == remote_services);
node.m_permissionFlags = permission_flags;
if (successfully_connected) {
CSerializedNetMsg msg_verack{mm.Make(NetMsgType::VERACK)};
diff --git a/src/test/util/net.h b/src/test/util/net.h
index 0cf55f8a22..ec6b4e6e88 100644
--- a/src/test/util/net.h
+++ b/src/test/util/net.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_TEST_UTIL_NET_H
#define BITCOIN_TEST_UTIL_NET_H
-#include <compat.h>
+#include <compat/compat.h>
#include <node/eviction.h>
#include <netaddress.h>
#include <net.h>
@@ -42,6 +42,7 @@ struct ConnmanTestMsg : public CConnman {
void Handshake(CNode& node,
bool successfully_connected,
ServiceFlags remote_services,
+ ServiceFlags local_services,
NetPermissionFlags permission_flags,
int32_t version,
bool relay_txs);
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 0fba9258f1..30d26ecf79 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -4,6 +4,8 @@
#include <test/util/setup_common.h>
+#include <kernel/validation_cache_sizes.h>
+
#include <addrman.h>
#include <banman.h>
#include <chainparams.h>
@@ -14,13 +16,14 @@
#include <init.h>
#include <init/common.h>
#include <interfaces/chain.h>
-#include <mempool_args.h>
#include <net.h>
#include <net_processing.h>
#include <node/blockstorage.h>
#include <node/chainstate.h>
#include <node/context.h>
+#include <node/mempool_args.h>
#include <node/miner.h>
+#include <node/validation_cache_args.h>
#include <noui.h>
#include <policy/fees.h>
#include <policy/fees_args.h>
@@ -52,10 +55,10 @@
#include <functional>
#include <stdexcept>
+using kernel::ValidationCacheSizes;
+using node::ApplyArgsManOptions;
using node::BlockAssembler;
using node::CalculateCacheSizes;
-using node::fPruneMode;
-using node::fReindex;
using node::LoadChainstate;
using node::NodeContext;
using node::RegenerateCommitments;
@@ -135,8 +138,12 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
m_node.kernel = std::make_unique<kernel::Context>();
SetupEnvironment();
SetupNetworking();
- InitSignatureCache();
- InitScriptExecutionCache();
+
+ ValidationCacheSizes validation_cache_sizes{};
+ ApplyArgsManOptions(*m_node.args, validation_cache_sizes);
+ Assert(InitSignatureCache(validation_cache_sizes.signature_cache_bytes));
+ Assert(InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes));
+
m_node.chain = interfaces::MakeChain(m_node);
fCheckBlockIndex = true;
static bool noui_connected = false;
@@ -162,7 +169,8 @@ CTxMemPool::Options MemPoolOptionsForTest(const NodeContext& node)
// chainparams.DefaultConsistencyChecks for tests
.check_ratio = 1,
};
- ApplyArgsManOptions(*node.args, mempool_opts);
+ const auto err{ApplyArgsManOptions(*node.args, ::Params(), mempool_opts)};
+ Assert(!err);
return mempool_opts;
}
@@ -218,25 +226,20 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
// instead of unit tests, but for now we need these here.
RegisterAllCoreRPCCommands(tableRPC);
- auto maybe_load_error = LoadChainstate(fReindex.load(),
- *Assert(m_node.chainman.get()),
- Assert(m_node.mempool.get()),
- fPruneMode,
- m_args.GetBoolArg("-reindex-chainstate", false),
- m_cache_sizes.block_tree_db,
- m_cache_sizes.coins_db,
- m_cache_sizes.coins,
- /*block_tree_db_in_memory=*/true,
- /*coins_db_in_memory=*/true);
- assert(!maybe_load_error.has_value());
-
- auto maybe_verify_error = VerifyLoadedChainstate(
- *Assert(m_node.chainman),
- fReindex.load(),
- m_args.GetBoolArg("-reindex-chainstate", false),
- m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS),
- m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL));
- assert(!maybe_verify_error.has_value());
+ node::ChainstateLoadOptions options;
+ options.mempool = Assert(m_node.mempool.get());
+ options.block_tree_db_in_memory = true;
+ options.coins_db_in_memory = true;
+ options.reindex = node::fReindex;
+ options.reindex_chainstate = m_args.GetBoolArg("-reindex-chainstate", false);
+ options.prune = node::fPruneMode;
+ options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
+ options.check_level = m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
+ auto [status, error] = LoadChainstate(*Assert(m_node.chainman), m_cache_sizes, options);
+ assert(status == node::ChainstateLoadStatus::SUCCESS);
+
+ std::tie(status, error) = VerifyLoadedChainstate(*Assert(m_node.chainman), options);
+ assert(status == node::ChainstateLoadStatus::SUCCESS);
BlockValidationState state;
if (!m_node.chainman->ActiveChainstate().ActivateBestChain(state)) {
diff --git a/src/test/util/wallet.cpp b/src/test/util/wallet.cpp
index 7a00ac9e1f..b54774cbb9 100644
--- a/src/test/util/wallet.cpp
+++ b/src/test/util/wallet.cpp
@@ -8,6 +8,7 @@
#include <outputtype.h>
#include <script/standard.h>
#ifdef ENABLE_WALLET
+#include <util/check.h>
#include <util/translation.h>
#include <wallet/wallet.h>
#endif
@@ -20,10 +21,7 @@ const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqq
std::string getnewaddress(CWallet& w)
{
constexpr auto output_type = OutputType::BECH32;
- auto op_dest = w.GetNewDestination(output_type, "");
- assert(op_dest.HasRes());
-
- return EncodeDestination(op_dest.GetObj());
+ return EncodeDestination(*Assert(w.GetNewDestination(output_type, "")));
}
#endif // ENABLE_WALLET
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index fda56ccff7..70e2f89e0b 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -249,6 +249,22 @@ BOOST_AUTO_TEST_CASE(util_Join)
BOOST_CHECK_EQUAL(Join<std::string>({"foo", "bar"}, ", ", op_upper), "FOO, BAR");
}
+BOOST_AUTO_TEST_CASE(util_ReplaceAll)
+{
+ const std::string original("A test \"%s\" string '%s'.");
+ auto test_replaceall = [&original](const std::string& search, const std::string& substitute, const std::string& expected) {
+ auto test = original;
+ ReplaceAll(test, search, substitute);
+ BOOST_CHECK_EQUAL(test, expected);
+ };
+
+ test_replaceall("", "foo", original);
+ test_replaceall(original, "foo", "foo");
+ test_replaceall("%s", "foo", "A test \"foo\" string 'foo'.");
+ test_replaceall("\"", "foo", "A test foo%sfoo string '%s'.");
+ test_replaceall("'", "foo", "A test \"%s\" string foo%sfoo.");
+}
+
BOOST_AUTO_TEST_CASE(util_TrimString)
{
BOOST_CHECK_EQUAL(TrimString(" foo bar "), "foo bar");
diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp
index 78adb521ac..ee60f9aa4d 100644
--- a/src/test/validation_chainstate_tests.cpp
+++ b/src/test/validation_chainstate_tests.cpp
@@ -9,7 +9,6 @@
#include <sync.h>
#include <test/util/chainstate.h>
#include <test/util/setup_common.h>
-#include <timedata.h>
#include <uint256.h>
#include <validation.h>
@@ -17,19 +16,13 @@
#include <boost/test/unit_test.hpp>
-BOOST_FIXTURE_TEST_SUITE(validation_chainstate_tests, TestingSetup)
+BOOST_FIXTURE_TEST_SUITE(validation_chainstate_tests, ChainTestingSetup)
//! Test resizing coins-related CChainState caches during runtime.
//!
BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches)
{
- const ChainstateManager::Options chainman_opts{
- .chainparams = Params(),
- .adjusted_time_callback = GetAdjustedTime,
- };
- ChainstateManager manager{chainman_opts};
-
- WITH_LOCK(::cs_main, manager.m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(1 << 20, true));
+ ChainstateManager& manager = *Assert(m_node.chainman);
CTxMemPool& mempool = *Assert(m_node.mempool);
//! Create and add a Coin with DynamicMemoryUsage of 80 bytes to the given view.
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index 6dc522b421..14de96ff41 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -193,7 +193,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
// Should not load malleated snapshots
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
+ m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
// A UTXO is missing but count is correct
metadata.m_coins_count -= 1;
@@ -204,22 +204,22 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup)
auto_infile >> coin;
}));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
+ m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
// Coins count is larger than coins in file
metadata.m_coins_count += 1;
}));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
+ m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
// Coins count is smaller than coins in file
metadata.m_coins_count -= 1;
}));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
+ m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
// Wrong hash
metadata.m_base_blockhash = uint256::ZERO;
}));
BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
- m_node, m_path_root, [](CAutoFile& auto_infile, SnapshotMetadata& metadata) {
+ m_node, m_path_root, [](AutoFile& auto_infile, SnapshotMetadata& metadata) {
// Wrong hash
metadata.m_base_blockhash = uint256::ONE;
}));
diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp
index 012169b17e..74b2af6858 100644
--- a/src/test/validation_flush_tests.cpp
+++ b/src/test/validation_flush_tests.cpp
@@ -4,14 +4,11 @@
//
#include <sync.h>
#include <test/util/setup_common.h>
-#include <txmempool.h>
#include <validation.h>
#include <boost/test/unit_test.hpp>
-using node::BlockManager;
-
-BOOST_FIXTURE_TEST_SUITE(validation_flush_tests, ChainTestingSetup)
+BOOST_FIXTURE_TEST_SUITE(validation_flush_tests, TestingSetup)
//! Test utilities for detecting when we need to flush the coins cache based
//! on estimated memory usage.
@@ -20,11 +17,7 @@ BOOST_FIXTURE_TEST_SUITE(validation_flush_tests, ChainTestingSetup)
//!
BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
{
- CTxMemPool& mempool = *Assert(m_node.mempool);
- BlockManager blockman{};
- CChainState chainstate{&mempool, blockman, *Assert(m_node.chainman)};
- chainstate.InitCoinsDB(/*cache_size_bytes=*/1 << 10, /*in_memory=*/true, /*should_wipe=*/false);
- WITH_LOCK(::cs_main, chainstate.InitCoinsCache(1 << 10));
+ CChainState& chainstate{m_node.chainman->ActiveChainstate()};
constexpr bool is_64_bit = sizeof(void*) == 8;
diff --git a/src/threadinterrupt.cpp b/src/threadinterrupt.cpp
index 340106ed99..e28b447c1d 100644
--- a/src/threadinterrupt.cpp
+++ b/src/threadinterrupt.cpp
@@ -28,18 +28,8 @@ void CThreadInterrupt::operator()()
cond.notify_all();
}
-bool CThreadInterrupt::sleep_for(std::chrono::milliseconds rel_time)
+bool CThreadInterrupt::sleep_for(Clock::duration rel_time)
{
WAIT_LOCK(mut, lock);
return !cond.wait_for(lock, rel_time, [this]() { return flag.load(std::memory_order_acquire); });
}
-
-bool CThreadInterrupt::sleep_for(std::chrono::seconds rel_time)
-{
- return sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(rel_time));
-}
-
-bool CThreadInterrupt::sleep_for(std::chrono::minutes rel_time)
-{
- return sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(rel_time));
-}
diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h
index 992016b4f6..363aab39ce 100644
--- a/src/threadinterrupt.h
+++ b/src/threadinterrupt.h
@@ -19,13 +19,12 @@
class CThreadInterrupt
{
public:
+ using Clock = std::chrono::steady_clock;
CThreadInterrupt();
explicit operator bool() const;
void operator()() EXCLUSIVE_LOCKS_REQUIRED(!mut);
void reset();
- bool sleep_for(std::chrono::milliseconds rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
- bool sleep_for(std::chrono::seconds rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
- bool sleep_for(std::chrono::minutes rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
+ bool sleep_for(Clock::duration rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
private:
std::condition_variable cond;
diff --git a/src/timedata.h b/src/timedata.h
index 2f039d5465..cfe5111644 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -5,9 +5,12 @@
#ifndef BITCOIN_TIMEDATA_H
#define BITCOIN_TIMEDATA_H
+#include <util/time.h>
+
#include <algorithm>
-#include <assert.h>
-#include <stdint.h>
+#include <cassert>
+#include <chrono>
+#include <cstdint>
#include <vector>
static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT = 70 * 60;
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index d6e792a55f..3a21a79a34 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -7,7 +7,7 @@
#include <chainparams.h>
#include <chainparamsbase.h>
-#include <compat.h>
+#include <compat/compat.h>
#include <crypto/hmac_sha256.h>
#include <net.h>
#include <netaddress.h>
diff --git a/src/txdb.cpp b/src/txdb.cpp
index c048c2d92a..bad3bb80a9 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -310,7 +310,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
CDiskBlockIndex diskindex;
if (pcursor->GetValue(diskindex)) {
// Construct block index object
- CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
+ CBlockIndex* pindexNew = insertBlockIndex(diskindex.ConstructBlockHash());
pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
pindexNew->nHeight = diskindex.nHeight;
pindexNew->nFile = diskindex.nFile;
diff --git a/src/txdb.h b/src/txdb.h
index faa543b412..a04596f7bb 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -8,6 +8,7 @@
#include <coins.h>
#include <dbwrapper.h>
+#include <sync.h>
#include <memory>
#include <optional>
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index aeaa10034e..b151953d0d 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -106,7 +106,7 @@ void CTxMemPoolEntry::UpdateLockPoints(const LockPoints& lp)
size_t CTxMemPoolEntry::GetTxSize() const
{
- return GetVirtualTransactionSize(nTxWeight, sigOpCost);
+ return GetVirtualTransactionSize(nTxWeight, sigOpCost, ::nBytesPerSigOp);
}
void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants,
@@ -458,6 +458,12 @@ CTxMemPool::CTxMemPool(const Options& opts)
minerPolicyEstimator{opts.estimator},
m_max_size_bytes{opts.max_size_bytes},
m_expiry{opts.expiry},
+ m_incremental_relay_feerate{opts.incremental_relay_feerate},
+ m_min_relay_feerate{opts.min_relay_feerate},
+ m_dust_relay_feerate{opts.dust_relay_feerate},
+ m_permit_bare_multisig{opts.permit_bare_multisig},
+ m_max_datacarrier_bytes{opts.max_datacarrier_bytes},
+ m_require_standard{opts.require_standard},
m_full_rbf{opts.full_rbf},
m_limits{opts.limits}
{
@@ -1117,12 +1123,12 @@ CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);
lastRollingFeeUpdate = time;
- if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() / 2) {
+ if (rollingMinimumFeeRate < (double)m_incremental_relay_feerate.GetFeePerK() / 2) {
rollingMinimumFeeRate = 0;
return CFeeRate(0);
}
}
- return std::max(CFeeRate(llround(rollingMinimumFeeRate)), incrementalRelayFee);
+ return std::max(CFeeRate(llround(rollingMinimumFeeRate)), m_incremental_relay_feerate);
}
void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
@@ -1146,7 +1152,7 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
// to have 0 fee). This way, we don't allow txn to enter mempool with feerate
// equal to txn which were removed with no block in between.
CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());
- removed += incrementalRelayFee;
+ removed += m_incremental_relay_feerate;
trackPackageRemoved(removed);
maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);
@@ -1210,14 +1216,14 @@ void CTxMemPool::GetTransactionAncestry(const uint256& txid, size_t& ancestors,
}
}
-bool CTxMemPool::IsLoaded() const
+bool CTxMemPool::GetLoadTried() const
{
LOCK(cs);
- return m_is_loaded;
+ return m_load_tried;
}
-void CTxMemPool::SetIsLoaded(bool loaded)
+void CTxMemPool::SetLoadTried(bool load_tried)
{
LOCK(cs);
- m_is_loaded = loaded;
+ m_load_tried = load_tried;
}
diff --git a/src/txmempool.h b/src/txmempool.h
index 6e37f59f2e..73904cc370 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -451,7 +451,7 @@ protected:
void trackPackageRemoved(const CFeeRate& rate) EXCLUSIVE_LOCKS_REQUIRED(cs);
- bool m_is_loaded GUARDED_BY(cs){false};
+ bool m_load_tried GUARDED_BY(cs){false};
CFeeRate GetMinFee(size_t sizelimit) const;
@@ -568,6 +568,12 @@ public:
const int64_t m_max_size_bytes;
const std::chrono::seconds m_expiry;
+ const CFeeRate m_incremental_relay_feerate;
+ const CFeeRate m_min_relay_feerate;
+ const CFeeRate m_dust_relay_feerate;
+ const bool m_permit_bare_multisig;
+ const std::optional<unsigned> m_max_datacarrier_bytes;
+ const bool m_require_standard;
const bool m_full_rbf;
using Limits = kernel::MemPoolLimits;
@@ -702,11 +708,11 @@ public:
void CalculateDescendants(txiter it, setEntries& setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** The minimum fee to get into the mempool, which may itself not be enough
- * for larger-sized transactions.
- * The incrementalRelayFee policy variable is used to bound the time it
- * takes the fee rate to go back down all the way to 0. When the feerate
- * would otherwise be half of this, it is set to 0 instead.
- */
+ * for larger-sized transactions.
+ * The m_incremental_relay_feerate policy variable is used to bound the time it
+ * takes the fee rate to go back down all the way to 0. When the feerate
+ * would otherwise be half of this, it is set to 0 instead.
+ */
CFeeRate GetMinFee() const {
return GetMinFee(m_max_size_bytes);
}
@@ -728,11 +734,17 @@ public:
*/
void GetTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants, size_t* ancestorsize = nullptr, CAmount* ancestorfees = nullptr) const;
- /** @returns true if the mempool is fully loaded */
- bool IsLoaded() const;
+ /**
+ * @returns true if we've made an attempt to load the mempool regardless of
+ * whether the attempt was successful or not
+ */
+ bool GetLoadTried() const;
- /** Sets the current loaded state */
- void SetIsLoaded(bool loaded);
+ /**
+ * Set whether or not we've made an attempt to load the mempool (regardless
+ * of whether the attempt was successful or not)
+ */
+ void SetLoadTried(bool load_tried);
unsigned long size() const
{
diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp
index ed4783f1a5..69ae8ea582 100644
--- a/src/txorphanage.cpp
+++ b/src/txorphanage.cpp
@@ -102,7 +102,7 @@ void TxOrphanage::EraseForPeer(NodeId peer)
if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx from peer=%d\n", nErased, peer);
}
-unsigned int TxOrphanage::LimitOrphans(unsigned int max_orphans)
+void TxOrphanage::LimitOrphans(unsigned int max_orphans)
{
AssertLockHeld(g_cs_orphans);
@@ -135,7 +135,7 @@ unsigned int TxOrphanage::LimitOrphans(unsigned int max_orphans)
EraseTx(m_orphan_list[randompos]->first);
++nEvicted;
}
- return nEvicted;
+ if (nEvicted > 0) LogPrint(BCLog::MEMPOOL, "orphanage overflow, removed %u tx\n", nEvicted);
}
void TxOrphanage::AddChildrenToWorkSet(const CTransaction& tx, std::set<uint256>& orphan_work_set) const
diff --git a/src/txorphanage.h b/src/txorphanage.h
index 24c8318f36..9363e6f733 100644
--- a/src/txorphanage.h
+++ b/src/txorphanage.h
@@ -41,7 +41,7 @@ public:
void EraseForBlock(const CBlock& block) LOCKS_EXCLUDED(::g_cs_orphans);
/** Limit the orphanage to the given maximum */
- unsigned int LimitOrphans(unsigned int max_orphans) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
+ void LimitOrphans(unsigned int max_orphans) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
/** Add any orphans that list a particular tx as a parent into a peer's work set
* (ie orphans that may have found their final missing parent, and so should be reconsidered for the mempool) */
diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h
index 7f9a6aaffd..8ba6fd5425 100644
--- a/src/univalue/include/univalue.h
+++ b/src/univalue/include/univalue.h
@@ -24,41 +24,39 @@ public:
typ = initialType;
val = initialStr;
}
- UniValue(uint64_t val_) {
- setInt(val_);
- }
- UniValue(int64_t val_) {
- setInt(val_);
- }
- UniValue(bool val_) {
- setBool(val_);
- }
- UniValue(int val_) {
- setInt(val_);
- }
- UniValue(double val_) {
- setFloat(val_);
- }
- UniValue(const std::string& val_) {
- setStr(val_);
- }
- UniValue(const char *val_) {
- std::string s(val_);
- setStr(s);
+ template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
+ std::enable_if_t<std::is_floating_point_v<T> || // setFloat
+ std::is_same_v<bool, T> || // setBool
+ std::is_signed_v<T> || std::is_unsigned_v<T> || // setInt
+ std::is_constructible_v<std::string, T>, // setStr
+ bool> = true>
+ UniValue(Ref&& val)
+ {
+ if constexpr (std::is_floating_point_v<T>) {
+ setFloat(val);
+ } else if constexpr (std::is_same_v<bool, T>) {
+ setBool(val);
+ } else if constexpr (std::is_signed_v<T>) {
+ setInt(int64_t{val});
+ } else if constexpr (std::is_unsigned_v<T>) {
+ setInt(uint64_t{val});
+ } else {
+ setStr(std::string{std::forward<Ref>(val)});
+ }
}
void clear();
- bool setNull();
- bool setBool(bool val);
- bool setNumStr(const std::string& val);
- bool setInt(uint64_t val);
- bool setInt(int64_t val);
- bool setInt(int val_) { return setInt((int64_t)val_); }
- bool setFloat(double val);
- bool setStr(const std::string& val);
- bool setArray();
- bool setObject();
+ void setNull();
+ void setBool(bool val);
+ void setNumStr(const std::string& val);
+ void setInt(uint64_t val);
+ void setInt(int64_t val);
+ void setInt(int val_) { return setInt(int64_t{val_}); }
+ void setFloat(double val);
+ void setStr(const std::string& val);
+ void setArray();
+ void setObject();
enum VType getType() const { return typ; }
const std::string& getValStr() const { return val; }
@@ -82,14 +80,14 @@ public:
bool isArray() const { return (typ == VARR); }
bool isObject() const { return (typ == VOBJ); }
- bool push_back(const UniValue& val);
- bool push_backV(const std::vector<UniValue>& vec);
+ void push_back(const UniValue& val);
+ void push_backV(const std::vector<UniValue>& vec);
template <class It>
- bool push_backV(It first, It last);
+ void push_backV(It first, It last);
void __pushKV(const std::string& key, const UniValue& val);
- bool pushKV(const std::string& key, const UniValue& val);
- bool pushKVs(const UniValue& obj);
+ void pushKV(const std::string& key, const UniValue& val);
+ void pushKVs(const UniValue& obj);
std::string write(unsigned int prettyIndent = 0,
unsigned int indentLevel = 0) const;
@@ -106,6 +104,7 @@ private:
std::vector<std::string> keys;
std::vector<UniValue> values;
+ void checkType(const VType& expected) const;
bool findKey(const std::string& key, size_t& retIdx) const;
void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
@@ -116,19 +115,7 @@ public:
const std::vector<std::string>& getKeys() const;
const std::vector<UniValue>& getValues() const;
template <typename Int>
- auto getInt() const
- {
- static_assert(std::is_integral<Int>::value);
- if (typ != VNUM) {
- throw std::runtime_error("JSON value is not an integer as expected");
- }
- Int result;
- const auto [first_nonmatching, error_condition] = std::from_chars(val.data(), val.data() + val.size(), result);
- if (first_nonmatching != val.data() + val.size() || error_condition != std::errc{}) {
- throw std::runtime_error("JSON integer out of range");
- }
- return result;
- }
+ Int getInt() const;
bool get_bool() const;
const std::string& get_str() const;
double get_real() const;
@@ -140,11 +127,23 @@ public:
};
template <class It>
-bool UniValue::push_backV(It first, It last)
+void UniValue::push_backV(It first, It last)
{
- if (typ != VARR) return false;
+ checkType(VARR);
values.insert(values.end(), first, last);
- return true;
+}
+
+template <typename Int>
+Int UniValue::getInt() const
+{
+ static_assert(std::is_integral<Int>::value);
+ checkType(VNUM);
+ Int result;
+ const auto [first_nonmatching, error_condition] = std::from_chars(val.data(), val.data() + val.size(), result);
+ if (first_nonmatching != val.data() + val.size() || error_condition != std::errc{}) {
+ throw std::runtime_error("JSON integer out of range");
+ }
+ return result;
}
enum jtokentype {
diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp
index 3553995c28..55e777b8ae 100644
--- a/src/univalue/lib/univalue.cpp
+++ b/src/univalue/lib/univalue.cpp
@@ -23,19 +23,17 @@ void UniValue::clear()
values.clear();
}
-bool UniValue::setNull()
+void UniValue::setNull()
{
clear();
- return true;
}
-bool UniValue::setBool(bool val_)
+void UniValue::setBool(bool val_)
{
clear();
typ = VBOOL;
if (val_)
val = "1";
- return true;
}
static bool validNumStr(const std::string& s)
@@ -46,18 +44,18 @@ static bool validNumStr(const std::string& s)
return (tt == JTOK_NUMBER);
}
-bool UniValue::setNumStr(const std::string& val_)
+void UniValue::setNumStr(const std::string& val_)
{
- if (!validNumStr(val_))
- return false;
+ if (!validNumStr(val_)) {
+ throw std::runtime_error{"The string '" + val_ + "' is not a valid JSON number"};
+ }
clear();
typ = VNUM;
val = val_;
- return true;
}
-bool UniValue::setInt(uint64_t val_)
+void UniValue::setInt(uint64_t val_)
{
std::ostringstream oss;
@@ -66,7 +64,7 @@ bool UniValue::setInt(uint64_t val_)
return setNumStr(oss.str());
}
-bool UniValue::setInt(int64_t val_)
+void UniValue::setInt(int64_t val_)
{
std::ostringstream oss;
@@ -75,86 +73,74 @@ bool UniValue::setInt(int64_t val_)
return setNumStr(oss.str());
}
-bool UniValue::setFloat(double val_)
+void UniValue::setFloat(double val_)
{
std::ostringstream oss;
oss << std::setprecision(16) << val_;
- bool ret = setNumStr(oss.str());
- typ = VNUM;
- return ret;
+ return setNumStr(oss.str());
}
-bool UniValue::setStr(const std::string& val_)
+void UniValue::setStr(const std::string& val_)
{
clear();
typ = VSTR;
val = val_;
- return true;
}
-bool UniValue::setArray()
+void UniValue::setArray()
{
clear();
typ = VARR;
- return true;
}
-bool UniValue::setObject()
+void UniValue::setObject()
{
clear();
typ = VOBJ;
- return true;
}
-bool UniValue::push_back(const UniValue& val_)
+void UniValue::push_back(const UniValue& val_)
{
- if (typ != VARR)
- return false;
+ checkType(VARR);
values.push_back(val_);
- return true;
}
-bool UniValue::push_backV(const std::vector<UniValue>& vec)
+void UniValue::push_backV(const std::vector<UniValue>& vec)
{
- if (typ != VARR)
- return false;
+ checkType(VARR);
values.insert(values.end(), vec.begin(), vec.end());
-
- return true;
}
void UniValue::__pushKV(const std::string& key, const UniValue& val_)
{
+ checkType(VOBJ);
+
keys.push_back(key);
values.push_back(val_);
}
-bool UniValue::pushKV(const std::string& key, const UniValue& val_)
+void UniValue::pushKV(const std::string& key, const UniValue& val_)
{
- if (typ != VOBJ)
- return false;
+ checkType(VOBJ);
size_t idx;
if (findKey(key, idx))
values[idx] = val_;
else
__pushKV(key, val_);
- return true;
}
-bool UniValue::pushKVs(const UniValue& obj)
+void UniValue::pushKVs(const UniValue& obj)
{
- if (typ != VOBJ || obj.typ != VOBJ)
- return false;
+ checkType(VOBJ);
+ obj.checkType(VOBJ);
for (size_t i = 0; i < obj.keys.size(); i++)
__pushKV(obj.keys[i], obj.values.at(i));
-
- return true;
}
void UniValue::getObjMap(std::map<std::string,UniValue>& kv) const
@@ -221,6 +207,14 @@ const UniValue& UniValue::operator[](size_t index) const
return values.at(index);
}
+void UniValue::checkType(const VType& expected) const
+{
+ if (typ != expected) {
+ throw std::runtime_error{"JSON value of type " + std::string{uvTypeName(typ)} + " is not of expected type " +
+ std::string{uvTypeName(expected)}};
+ }
+}
+
const char *uvTypeName(UniValue::VType t)
{
switch (t) {
diff --git a/src/univalue/lib/univalue_get.cpp b/src/univalue/lib/univalue_get.cpp
index 9bbdb1fe69..5c58f388dd 100644
--- a/src/univalue/lib/univalue_get.cpp
+++ b/src/univalue/lib/univalue_get.cpp
@@ -46,8 +46,7 @@ bool ParseDouble(const std::string& str, double *out)
const std::vector<std::string>& UniValue::getKeys() const
{
- if (typ != VOBJ)
- throw std::runtime_error("JSON value is not an object as expected");
+ checkType(VOBJ);
return keys;
}
@@ -60,22 +59,19 @@ const std::vector<UniValue>& UniValue::getValues() const
bool UniValue::get_bool() const
{
- if (typ != VBOOL)
- throw std::runtime_error("JSON value is not a boolean as expected");
+ checkType(VBOOL);
return getBool();
}
const std::string& UniValue::get_str() const
{
- if (typ != VSTR)
- throw std::runtime_error("JSON value is not a string as expected");
+ checkType(VSTR);
return getValStr();
}
double UniValue::get_real() const
{
- if (typ != VNUM)
- throw std::runtime_error("JSON value is not a number as expected");
+ checkType(VNUM);
double retval;
if (!ParseDouble(getValStr(), &retval))
throw std::runtime_error("JSON double out of range");
@@ -84,15 +80,12 @@ double UniValue::get_real() const
const UniValue& UniValue::get_obj() const
{
- if (typ != VOBJ)
- throw std::runtime_error("JSON value is not an object as expected");
+ checkType(VOBJ);
return *this;
}
const UniValue& UniValue::get_array() const
{
- if (typ != VARR)
- throw std::runtime_error("JSON value is not an array as expected");
+ checkType(VARR);
return *this;
}
-
diff --git a/src/univalue/sources.mk b/src/univalue/sources.mk
index e156216378..5e4d9c3831 100644
--- a/src/univalue/sources.mk
+++ b/src/univalue/sources.mk
@@ -1,12 +1,8 @@
-# - All variables are namespaced with UNIVALUE_ to avoid colliding with
-# downstream makefiles.
# - All Variables ending in _HEADERS or _SOURCES confuse automake, so the
# _INT postfix is applied.
# - Convenience variables, for example a UNIVALUE_TEST_DIR should not be used
# as they interfere with automatic dependency generation
-# - The %reldir% is the relative path from the Makefile.am. This allows
-# downstreams to use these variables without having to manually account for
-# the path change.
+# - The %reldir% is the relative path from the Makefile.am.
UNIVALUE_INCLUDE_DIR_INT = %reldir%/include
@@ -29,9 +25,6 @@ UNIVALUE_TEST_UNITESTER_INT += %reldir%/test/unitester.cpp
UNIVALUE_TEST_JSON_INT =
UNIVALUE_TEST_JSON_INT += %reldir%/test/test_json.cpp
-UNIVALUE_TEST_NO_NUL_INT =
-UNIVALUE_TEST_NO_NUL_INT += %reldir%/test/no_nul.cpp
-
UNIVALUE_TEST_OBJECT_INT =
UNIVALUE_TEST_OBJECT_INT += %reldir%/test/object.cpp
diff --git a/src/univalue/test/.gitignore b/src/univalue/test/.gitignore
index 7b27cf0da2..5812c96b14 100644
--- a/src/univalue/test/.gitignore
+++ b/src/univalue/test/.gitignore
@@ -2,7 +2,6 @@
object
unitester
test_json
-no_nul
*.trs
*.log
diff --git a/src/univalue/test/no_nul.cpp b/src/univalue/test/no_nul.cpp
deleted file mode 100644
index 3a7a727abb..0000000000
--- a/src/univalue/test/no_nul.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <univalue.h>
-
-int main (int argc, char *argv[])
-{
- char buf[] = "___[1,2,3]___";
- UniValue val;
- return val.read(buf + 3, 7) ? 0 : 1;
-}
diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp
index 8a35bf914d..94d7343ff3 100644
--- a/src/univalue/test/object.cpp
+++ b/src/univalue/test/object.cpp
@@ -13,9 +13,6 @@
#include <string>
#include <vector>
-#define BOOST_FIXTURE_TEST_SUITE(a, b)
-#define BOOST_AUTO_TEST_CASE(funcName) void funcName()
-#define BOOST_AUTO_TEST_SUITE_END()
#define BOOST_CHECK(expr) assert(expr)
#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2))
#define BOOST_CHECK_THROW(stmt, excMatch) { \
@@ -35,9 +32,7 @@
} \
}
-BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup)
-
-BOOST_AUTO_TEST_CASE(univalue_constructor)
+void univalue_constructor()
{
UniValue v1;
BOOST_CHECK(v1.isNull());
@@ -50,7 +45,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
BOOST_CHECK_EQUAL(v3.getValStr(), "foo");
UniValue numTest;
- BOOST_CHECK(numTest.setNumStr("82"));
+ numTest.setNumStr("82");
BOOST_CHECK(numTest.isNum());
BOOST_CHECK_EQUAL(numTest.getValStr(), "82");
@@ -85,36 +80,46 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
BOOST_CHECK_EQUAL(v9.getValStr(), "zappa");
}
-BOOST_AUTO_TEST_CASE(univalue_typecheck)
+void univalue_push_throw()
+{
+ UniValue j;
+ BOOST_CHECK_THROW(j.push_back(1), std::runtime_error);
+ BOOST_CHECK_THROW(j.push_backV({1}), std::runtime_error);
+ BOOST_CHECK_THROW(j.__pushKV("k", 1), std::runtime_error);
+ BOOST_CHECK_THROW(j.pushKV("k", 1), std::runtime_error);
+ BOOST_CHECK_THROW(j.pushKVs({}), std::runtime_error);
+}
+
+void univalue_typecheck()
{
UniValue v1;
- BOOST_CHECK(v1.setNumStr("1"));
+ v1.setNumStr("1");
BOOST_CHECK(v1.isNum());
BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);
{
UniValue v_negative;
- BOOST_CHECK(v_negative.setNumStr("-1"));
+ v_negative.setNumStr("-1");
BOOST_CHECK_THROW(v_negative.getInt<uint8_t>(), std::runtime_error);
BOOST_CHECK_EQUAL(v_negative.getInt<int8_t>(), -1);
}
UniValue v2;
- BOOST_CHECK(v2.setBool(true));
+ v2.setBool(true);
BOOST_CHECK_EQUAL(v2.get_bool(), true);
BOOST_CHECK_THROW(v2.getInt<int>(), std::runtime_error);
UniValue v3;
- BOOST_CHECK(v3.setNumStr("32482348723847471234"));
+ v3.setNumStr("32482348723847471234");
BOOST_CHECK_THROW(v3.getInt<int64_t>(), std::runtime_error);
- BOOST_CHECK(v3.setNumStr("1000"));
+ v3.setNumStr("1000");
BOOST_CHECK_EQUAL(v3.getInt<int64_t>(), 1000);
UniValue v4;
- BOOST_CHECK(v4.setNumStr("2147483648"));
+ v4.setNumStr("2147483648");
BOOST_CHECK_EQUAL(v4.getInt<int64_t>(), 2147483648);
BOOST_CHECK_THROW(v4.getInt<int>(), std::runtime_error);
- BOOST_CHECK(v4.setNumStr("1000"));
+ v4.setNumStr("1000");
BOOST_CHECK_EQUAL(v4.getInt<int>(), 1000);
BOOST_CHECK_THROW(v4.get_str(), std::runtime_error);
BOOST_CHECK_EQUAL(v4.get_real(), 1000);
@@ -134,77 +139,77 @@ BOOST_AUTO_TEST_CASE(univalue_typecheck)
BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error);
}
-BOOST_AUTO_TEST_CASE(univalue_set)
+void univalue_set()
{
UniValue v(UniValue::VSTR, "foo");
v.clear();
BOOST_CHECK(v.isNull());
BOOST_CHECK_EQUAL(v.getValStr(), "");
- BOOST_CHECK(v.setObject());
+ v.setObject();
BOOST_CHECK(v.isObject());
BOOST_CHECK_EQUAL(v.size(), 0);
BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
BOOST_CHECK(v.empty());
- BOOST_CHECK(v.setArray());
+ v.setArray();
BOOST_CHECK(v.isArray());
BOOST_CHECK_EQUAL(v.size(), 0);
- BOOST_CHECK(v.setStr("zum"));
+ v.setStr("zum");
BOOST_CHECK(v.isStr());
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
- BOOST_CHECK(v.setFloat(-1.01));
+ v.setFloat(-1.01);
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
- BOOST_CHECK(v.setInt((int)1023));
+ v.setInt(int{1023});
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "1023");
- BOOST_CHECK(v.setInt((int64_t)-1023LL));
+ v.setInt(int64_t{-1023LL});
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-1023");
- BOOST_CHECK(v.setInt((uint64_t)1023ULL));
+ v.setInt(uint64_t{1023ULL});
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "1023");
- BOOST_CHECK(v.setNumStr("-688"));
+ v.setNumStr("-688");
BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-688");
- BOOST_CHECK(v.setBool(false));
+ v.setBool(false);
BOOST_CHECK_EQUAL(v.isBool(), true);
BOOST_CHECK_EQUAL(v.isTrue(), false);
BOOST_CHECK_EQUAL(v.isFalse(), true);
BOOST_CHECK_EQUAL(v.getBool(), false);
- BOOST_CHECK(v.setBool(true));
+ v.setBool(true);
BOOST_CHECK_EQUAL(v.isBool(), true);
BOOST_CHECK_EQUAL(v.isTrue(), true);
BOOST_CHECK_EQUAL(v.isFalse(), false);
BOOST_CHECK_EQUAL(v.getBool(), true);
- BOOST_CHECK(!v.setNumStr("zombocom"));
+ BOOST_CHECK_THROW(v.setNumStr("zombocom"), std::runtime_error);
- BOOST_CHECK(v.setNull());
+ v.setNull();
BOOST_CHECK(v.isNull());
}
-BOOST_AUTO_TEST_CASE(univalue_array)
+void univalue_array()
{
UniValue arr(UniValue::VARR);
UniValue v((int64_t)1023LL);
- BOOST_CHECK(arr.push_back(v));
+ arr.push_back(v);
std::string vStr("zippy");
- BOOST_CHECK(arr.push_back(vStr));
+ arr.push_back(vStr);
const char *s = "pippy";
- BOOST_CHECK(arr.push_back(s));
+ arr.push_back(s);
std::vector<UniValue> vec;
v.setStr("boing");
@@ -213,13 +218,13 @@ BOOST_AUTO_TEST_CASE(univalue_array)
v.setStr("going");
vec.push_back(v);
- BOOST_CHECK(arr.push_backV(vec));
+ arr.push_backV(vec);
- BOOST_CHECK(arr.push_back((uint64_t) 400ULL));
- BOOST_CHECK(arr.push_back((int64_t) -400LL));
- BOOST_CHECK(arr.push_back((int) -401));
- BOOST_CHECK(arr.push_back(-40.1));
- BOOST_CHECK(arr.push_back(true));
+ arr.push_back(uint64_t{400ULL});
+ arr.push_back(int64_t{-400LL});
+ arr.push_back(int{-401});
+ arr.push_back(-40.1);
+ arr.push_back(true);
BOOST_CHECK_EQUAL(arr.empty(), false);
BOOST_CHECK_EQUAL(arr.size(), 10);
@@ -252,7 +257,7 @@ BOOST_AUTO_TEST_CASE(univalue_array)
BOOST_CHECK_EQUAL(arr.size(), 0);
}
-BOOST_AUTO_TEST_CASE(univalue_object)
+void univalue_object()
{
UniValue obj(UniValue::VOBJ);
std::string strKey, strVal;
@@ -260,39 +265,39 @@ BOOST_AUTO_TEST_CASE(univalue_object)
strKey = "age";
v.setInt(100);
- BOOST_CHECK(obj.pushKV(strKey, v));
+ obj.pushKV(strKey, v);
strKey = "first";
strVal = "John";
- BOOST_CHECK(obj.pushKV(strKey, strVal));
+ obj.pushKV(strKey, strVal);
strKey = "last";
- const char *cVal = "Smith";
- BOOST_CHECK(obj.pushKV(strKey, cVal));
+ const char* cVal = "Smith";
+ obj.pushKV(strKey, cVal);
strKey = "distance";
- BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25));
+ obj.pushKV(strKey, int64_t{25});
strKey = "time";
- BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600));
+ obj.pushKV(strKey, uint64_t{3600});
strKey = "calories";
- BOOST_CHECK(obj.pushKV(strKey, (int) 12));
+ obj.pushKV(strKey, int{12});
strKey = "temperature";
- BOOST_CHECK(obj.pushKV(strKey, (double) 90.012));
+ obj.pushKV(strKey, double{90.012});
strKey = "moon";
- BOOST_CHECK(obj.pushKV(strKey, true));
+ obj.pushKV(strKey, true);
strKey = "spoon";
- BOOST_CHECK(obj.pushKV(strKey, false));
+ obj.pushKV(strKey, false);
UniValue obj2(UniValue::VOBJ);
- BOOST_CHECK(obj2.pushKV("cat1", 9000));
- BOOST_CHECK(obj2.pushKV("cat2", 12345));
+ obj2.pushKV("cat1", 9000);
+ obj2.pushKV("cat2", 12345);
- BOOST_CHECK(obj.pushKVs(obj2));
+ obj.pushKVs(obj2);
BOOST_CHECK_EQUAL(obj.empty(), false);
BOOST_CHECK_EQUAL(obj.size(), 11);
@@ -347,7 +352,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
BOOST_CHECK_EQUAL(obj.size(), 0);
BOOST_CHECK_EQUAL(obj.getType(), UniValue::VNULL);
- BOOST_CHECK_EQUAL(obj.setObject(), true);
+ obj.setObject();
UniValue uv;
uv.setInt(42);
obj.__pushKV("age", uv);
@@ -371,7 +376,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
static const char *json1 =
"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]";
-BOOST_AUTO_TEST_CASE(univalue_readwrite)
+void univalue_readwrite()
{
UniValue v;
BOOST_CHECK(v.read(json1));
@@ -414,11 +419,10 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite)
BOOST_CHECK(!v.read("{} 42"));
}
-BOOST_AUTO_TEST_SUITE_END()
-
-int main (int argc, char *argv[])
+int main(int argc, char* argv[])
{
univalue_constructor();
+ univalue_push_throw();
univalue_typecheck();
univalue_set();
univalue_array();
@@ -426,4 +430,3 @@ int main (int argc, char *argv[])
univalue_readwrite();
return 0;
}
-
diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp
index 94c149b39f..6344a5a0ab 100644
--- a/src/univalue/test/unitester.cpp
+++ b/src/univalue/test/unitester.cpp
@@ -149,6 +149,13 @@ void unescape_unicode_test()
assert(val[0].get_str() == "\xf0\x9d\x85\xa1");
}
+void no_nul_test()
+{
+ char buf[] = "___[1,2,3]___";
+ UniValue val;
+ assert(val.read(buf + 3, 7));
+}
+
int main (int argc, char *argv[])
{
for (const auto& f: filenames) {
@@ -156,6 +163,7 @@ int main (int argc, char *argv[])
}
unescape_unicode_test();
+ no_nul_test();
return 0;
}
diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp
index b1db3b5f0d..33258d9962 100644
--- a/src/util/asmap.cpp
+++ b/src/util/asmap.cpp
@@ -198,7 +198,7 @@ std::vector<bool> DecodeAsmap(fs::path path)
{
std::vector<bool> bits;
FILE *filestr = fsbridge::fopen(path, "rb");
- CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
+ AutoFile file{filestr};
if (file.IsNull()) {
LogPrintf("Failed to open asmap file from disk\n");
return bits;
diff --git a/src/util/message.cpp b/src/util/message.cpp
index d395c4b0bc..028251a5a8 100644
--- a/src/util/message.cpp
+++ b/src/util/message.cpp
@@ -74,7 +74,7 @@ bool MessageSign(
uint256 MessageHash(const std::string& message)
{
- CHashWriter hasher(SER_GETHASH, 0);
+ HashWriter hasher{};
hasher << MESSAGE_MAGIC << message;
return hasher.GetHash();
diff --git a/src/util/result.h b/src/util/result.h
index 2f586a4c9b..972b1aada0 100644
--- a/src/util/result.h
+++ b/src/util/result.h
@@ -5,45 +5,80 @@
#ifndef BITCOIN_UTIL_RESULT_H
#define BITCOIN_UTIL_RESULT_H
+#include <attributes.h>
#include <util/translation.h>
#include <variant>
-/*
- * 'BResult' is a generic class useful for wrapping a return object
- * (in case of success) or propagating the error cause.
-*/
-template<class T>
-class BResult {
+namespace util {
+
+struct Error {
+ bilingual_str message;
+};
+
+//! The util::Result class provides a standard way for functions to return
+//! either error messages or result values.
+//!
+//! It is intended for high-level functions that need to report error strings to
+//! end users. Lower-level functions that don't need this error-reporting and
+//! only need error-handling should avoid util::Result and instead use standard
+//! classes like std::optional, std::variant, and std::tuple, or custom structs
+//! and enum types to return function results.
+//!
+//! Usage examples can be found in \example ../test/result_tests.cpp, but in
+//! general code returning `util::Result<T>` values is very similar to code
+//! returning `std::optional<T>` values. Existing functions returning
+//! `std::optional<T>` can be updated to return `util::Result<T>` and return
+//! error strings usually just replacing `return std::nullopt;` with `return
+//! util::Error{error_string};`.
+template <class T>
+class Result
+{
private:
std::variant<bilingual_str, T> m_variant;
-public:
- BResult() : m_variant{Untranslated("")} {}
- BResult(T obj) : m_variant{std::move(obj)} {}
- BResult(bilingual_str error) : m_variant{std::move(error)} {}
+ template <typename FT>
+ friend bilingual_str ErrorString(const Result<FT>& result);
- /* Whether the function succeeded or not */
- bool HasRes() const { return std::holds_alternative<T>(m_variant); }
+public:
+ Result(T obj) : m_variant{std::in_place_index_t<1>{}, std::move(obj)} {}
+ Result(Error error) : m_variant{std::in_place_index_t<0>{}, std::move(error.message)} {}
- /* In case of success, the result object */
- const T& GetObj() const {
- assert(HasRes());
- return std::get<T>(m_variant);
+ //! std::optional methods, so functions returning optional<T> can change to
+ //! return Result<T> with minimal changes to existing code, and vice versa.
+ bool has_value() const noexcept { return m_variant.index() == 1; }
+ const T& value() const LIFETIMEBOUND
+ {
+ assert(has_value());
+ return std::get<1>(m_variant);
}
- T ReleaseObj()
+ T& value() LIFETIMEBOUND
{
- assert(HasRes());
- return std::move(std::get<T>(m_variant));
+ assert(has_value());
+ return std::get<1>(m_variant);
}
-
- /* In case of failure, the error cause */
- const bilingual_str& GetError() const {
- assert(!HasRes());
- return std::get<bilingual_str>(m_variant);
+ template <class U>
+ T value_or(U&& default_value) const&
+ {
+ return has_value() ? value() : std::forward<U>(default_value);
}
-
- explicit operator bool() const { return HasRes(); }
+ template <class U>
+ T value_or(U&& default_value) &&
+ {
+ return has_value() ? std::move(value()) : std::forward<U>(default_value);
+ }
+ explicit operator bool() const noexcept { return has_value(); }
+ const T* operator->() const LIFETIMEBOUND { return &value(); }
+ const T& operator*() const LIFETIMEBOUND { return value(); }
+ T* operator->() LIFETIMEBOUND { return &value(); }
+ T& operator*() LIFETIMEBOUND { return value(); }
};
+template <typename T>
+bilingual_str ErrorString(const Result<T>& result)
+{
+ return result ? bilingual_str{} : std::get<0>(result.m_variant);
+}
+} // namespace util
+
#endif // BITCOIN_UTIL_RESULT_H
diff --git a/src/util/sock.cpp b/src/util/sock.cpp
index 2588575d81..125dbc7f18 100644
--- a/src/util/sock.cpp
+++ b/src/util/sock.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <compat.h>
+#include <compat/compat.h>
#include <logging.h>
#include <threadinterrupt.h>
#include <tinyformat.h>
diff --git a/src/util/sock.h b/src/util/sock.h
index b854609c22..38a7dc80d6 100644
--- a/src/util/sock.h
+++ b/src/util/sock.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_UTIL_SOCK_H
#define BITCOIN_UTIL_SOCK_H
-#include <compat.h>
+#include <compat/compat.h>
#include <threadinterrupt.h>
#include <util/time.h>
diff --git a/src/util/string.cpp b/src/util/string.cpp
index dff782c330..db6dbe4135 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -4,11 +4,12 @@
#include <util/string.h>
-#include <boost/algorithm/string/replace.hpp>
-
+#include <regex>
#include <string>
+#include <utility>
-void ReplaceAll(std::string& in_out, std::string_view search, std::string_view substitute)
+void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute)
{
- boost::replace_all(in_out, search, substitute);
+ if (search.empty()) return;
+ in_out = std::regex_replace(in_out, std::regex(std::move(search)), substitute);
}
diff --git a/src/util/string.h b/src/util/string.h
index df20e34ae9..dd4de888bb 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -17,7 +17,7 @@
#include <string_view>
#include <vector>
-void ReplaceAll(std::string& in_out, std::string_view search, std::string_view substitute);
+void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute);
[[nodiscard]] inline std::vector<std::string> SplitString(std::string_view str, char sep)
{
diff --git a/src/util/system.cpp b/src/util/system.cpp
index f6f2828fc8..1953a9f836 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -522,7 +522,7 @@ bool ArgsManager::InitSettings(std::string& error)
bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp, bool backup) const
{
- fs::path settings = GetPathArg("-settings", fs::path{BITCOIN_SETTINGS_FILENAME});
+ fs::path settings = GetPathArg("-settings", BITCOIN_SETTINGS_FILENAME);
if (settings.empty()) {
return false;
}
@@ -740,7 +740,7 @@ std::string ArgsManager::GetHelpMessage() const
{
const bool show_debug = GetBoolArg("-help-debug", false);
- std::string usage = "";
+ std::string usage;
LOCK(cs_args);
for (const auto& arg_map : m_available_args) {
switch(arg_map.first) {
@@ -885,9 +885,9 @@ bool CheckDataDirOption()
return datadir.empty() || fs::is_directory(fs::absolute(datadir));
}
-fs::path GetConfigFile(const std::string& confPath)
+fs::path GetConfigFile(const fs::path& configuration_file_path)
{
- return AbsPathForConfigVal(fs::PathFromString(confPath), false);
+ return AbsPathForConfigVal(configuration_file_path, /*net_specific=*/false);
}
static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections)
@@ -971,17 +971,17 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
m_config_sections.clear();
}
- const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME);
- std::ifstream stream{GetConfigFile(confPath)};
+ const fs::path conf_path = GetPathArg("-conf", BITCOIN_CONF_FILENAME);
+ std::ifstream stream{GetConfigFile(conf_path)};
// not ok to have a config file specified that cannot be opened
if (IsArgSet("-conf") && !stream.good()) {
- error = strprintf("specified config file \"%s\" could not be opened.", confPath);
+ error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path));
return false;
}
// ok to not have a config file
if (stream.good()) {
- if (!ReadConfigStream(stream, confPath, error, ignore_invalid_keys)) {
+ if (!ReadConfigStream(stream, fs::PathToString(conf_path), error, ignore_invalid_keys)) {
return false;
}
// `-includeconf` cannot be included in the command line arguments except
@@ -1019,7 +1019,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
const size_t default_includes = add_includes({});
for (const std::string& conf_file_name : conf_file_names) {
- std::ifstream conf_file_stream{GetConfigFile(conf_file_name)};
+ std::ifstream conf_file_stream{GetConfigFile(fs::PathFromString(conf_file_name))};
if (conf_file_stream.good()) {
if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) {
return false;
diff --git a/src/util/system.h b/src/util/system.h
index 04c66341d3..756e6642f2 100644
--- a/src/util/system.h
+++ b/src/util/system.h
@@ -14,7 +14,7 @@
#include <config/bitcoin-config.h>
#endif
-#include <compat.h>
+#include <compat/compat.h>
#include <compat/assumptions.h>
#include <fs.h>
#include <logging.h>
@@ -97,7 +97,7 @@ bool TryCreateDirectories(const fs::path& p);
fs::path GetDefaultDataDir();
// Return true if -datadir option points to a valid directory or is not specified.
bool CheckDataDirOption();
-fs::path GetConfigFile(const std::string& confPath);
+fs::path GetConfigFile(const fs::path& configuration_file_path);
#ifdef WIN32
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
diff --git a/src/util/time.cpp b/src/util/time.cpp
index 2cafc55c69..f6d37347f8 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -7,7 +7,7 @@
#include <config/bitcoin-config.h>
#endif
-#include <compat.h>
+#include <compat/compat.h>
#include <tinyformat.h>
#include <util/time.h>
#include <util/check.h>
diff --git a/src/util/time.h b/src/util/time.h
index 9df69a953c..4f9bde5d56 100644
--- a/src/util/time.h
+++ b/src/util/time.h
@@ -6,7 +6,7 @@
#ifndef BITCOIN_UTIL_TIME_H
#define BITCOIN_UTIL_TIME_H
-#include <compat.h>
+#include <compat/compat.h>
#include <chrono>
#include <cstdint>
@@ -24,6 +24,7 @@ struct NodeClock : public std::chrono::system_clock {
};
using NodeSeconds = std::chrono::time_point<NodeClock, std::chrono::seconds>;
+using SteadyClock = std::chrono::steady_clock;
using SteadySeconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::seconds>;
using SteadyMilliseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::milliseconds>;
using SteadyMicroseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds>;
@@ -54,6 +55,7 @@ constexpr int64_t count_seconds(std::chrono::seconds t) { return t.count(); }
constexpr int64_t count_milliseconds(std::chrono::milliseconds t) { return t.count(); }
constexpr int64_t count_microseconds(std::chrono::microseconds t) { return t.count(); }
+using HoursDouble = std::chrono::duration<double, std::chrono::hours::period>;
using SecondsDouble = std::chrono::duration<double, std::chrono::seconds::period>;
/**
diff --git a/src/validation.cpp b/src/validation.cpp
index 4c694a2c21..d276cea2f7 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -5,6 +5,9 @@
#include <validation.h>
+#include <kernel/coinstats.h>
+#include <kernel/mempool_persist.h>
+
#include <arith_uint256.h>
#include <chain.h>
#include <chainparams.h>
@@ -17,8 +20,8 @@
#include <consensus/validation.h>
#include <cuckoocache.h>
#include <flatfile.h>
+#include <fs.h>
#include <hash.h>
-#include <kernel/coinstats.h>
#include <logging.h>
#include <logging/timer.h>
#include <node/blockstorage.h>
@@ -47,12 +50,15 @@
#include <util/rbf.h>
#include <util/strencodings.h>
#include <util/system.h>
+#include <util/time.h>
#include <util/trace.h>
#include <util/translation.h>
#include <validationinterface.h>
#include <warnings.h>
#include <algorithm>
+#include <cassert>
+#include <chrono>
#include <deque>
#include <numeric>
#include <optional>
@@ -61,8 +67,9 @@
using kernel::CCoinsStats;
using kernel::CoinStatsHashType;
using kernel::ComputeUTXOStats;
+using kernel::LoadMempool;
-using node::BLOCKFILE_CHUNK_SIZE;
+using fsbridge::FopenFn;
using node::BlockManager;
using node::BlockMap;
using node::CBlockIndexHeightOnlyComparator;
@@ -70,11 +77,8 @@ using node::CBlockIndexWorkComparator;
using node::fImporting;
using node::fPruneMode;
using node::fReindex;
-using node::nPruneTarget;
-using node::OpenBlockFile;
using node::ReadBlockFromDisk;
using node::SnapshotMetadata;
-using node::UNDOFILE_CHUNK_SIZE;
using node::UndoReadFromDisk;
using node::UnlinkPrunedFiles;
@@ -120,7 +124,6 @@ GlobalMutex g_best_block_mutex;
std::condition_variable g_best_block_cv;
uint256 g_best_block;
bool g_parallel_script_checks{false};
-bool fRequireStandard = true;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
@@ -154,10 +157,9 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
std::vector<CScriptCheck>* pvChecks = nullptr)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-bool CheckFinalTxAtTip(const CBlockIndex* active_chain_tip, const CTransaction& tx)
+bool CheckFinalTxAtTip(const CBlockIndex& active_chain_tip, const CTransaction& tx)
{
AssertLockHeld(cs_main);
- assert(active_chain_tip); // TODO: Make active_chain_tip a reference
// CheckFinalTxAtTip() uses active_chain_tip.Height()+1 to evaluate
// nLockTime because when IsFinalTx() is called within
@@ -165,14 +167,14 @@ bool CheckFinalTxAtTip(const CBlockIndex* active_chain_tip, const CTransaction&
// evaluated is what is used. Thus if we want to know if a
// transaction can be part of the *next* block, we need to call
// IsFinalTx() with one more than active_chain_tip.Height().
- const int nBlockHeight = active_chain_tip->nHeight + 1;
+ const int nBlockHeight = active_chain_tip.nHeight + 1;
// BIP113 requires that time-locked transactions have nLockTime set to
// less than the median time of the previous block they're contained in.
// When the next block is created its previous block will be the current
// chain tip, so we use that to calculate the median time passed to
// IsFinalTx().
- const int64_t nBlockTime{active_chain_tip->GetMedianTimePast()};
+ const int64_t nBlockTime{active_chain_tip.GetMedianTimePast()};
return IsFinalTx(tx, nBlockHeight, nBlockTime);
}
@@ -334,7 +336,7 @@ void CChainState::MaybeUpdateMempoolForReorg(
const CTransaction& tx = it->GetTx();
// The transaction must be final.
- if (!CheckFinalTxAtTip(m_chain.Tip(), tx)) return true;
+ if (!CheckFinalTxAtTip(*Assert(m_chain.Tip()), tx)) return true;
LockPoints lp = it->GetLockPoints();
const bool validLP{TestLockPointValidity(m_chain, lp)};
CCoinsViewMemPool view_mempool(&CoinsTip(), *m_mempool);
@@ -643,8 +645,9 @@ private:
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
}
- if (package_fee < ::minRelayTxFee.GetFee(package_size)) {
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
+ if (package_fee < m_pool.m_min_relay_feerate.GetFee(package_size)) {
+ return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met",
+ strprintf("%d < %d", package_fee, m_pool.m_min_relay_feerate.GetFee(package_size)));
}
return true;
}
@@ -696,8 +699,9 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
std::string reason;
- if (fRequireStandard && !IsStandardTx(tx, reason))
+ if (m_pool.m_require_standard && !IsStandardTx(tx, m_pool.m_max_datacarrier_bytes, m_pool.m_permit_bare_multisig, m_pool.m_dust_relay_feerate, reason)) {
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason);
+ }
// Do not work on transactions that are too small.
// A transaction with 1 segwit input and 1 P2WPHK output has non-witness size of 82 bytes.
@@ -709,7 +713,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
- if (!CheckFinalTxAtTip(m_active_chainstate.m_chain.Tip(), tx)) {
+ if (!CheckFinalTxAtTip(*Assert(m_active_chainstate.m_chain.Tip()), tx)) {
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-final");
}
@@ -803,13 +807,14 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return false; // state filled in by CheckTxInputs
}
- if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
+ if (m_pool.m_require_standard && !AreInputsStandard(tx, m_view)) {
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
}
// Check for non-standard witnesses.
- if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, m_view))
+ if (tx.HasWitness() && m_pool.m_require_standard && !IsWitnessStandard(tx, m_view)) {
return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, "bad-witness-nonstandard");
+ }
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
@@ -836,7 +841,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
strprintf("%d", nSigOpsCost));
- // No individual transactions are allowed below minRelayTxFee and mempool min fee except from
+ // No individual transactions are allowed below the min relay feerate and mempool min feerate except from
// disconnected blocks and transactions in a package. Package transactions will be checked using
// package feerate later.
if (!bypass_limits && !args.m_package_feerates && !CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state)) return false;
@@ -954,7 +959,7 @@ bool MemPoolAccept::ReplacementChecks(Workspace& ws)
ws.m_conflicting_size += it->GetTxSize();
}
if (const auto err_string{PaysForRBF(ws.m_conflicting_fees, ws.m_modified_fees, ws.m_vsize,
- ::incrementalRelayFee, hash)}) {
+ m_pool.m_incremental_relay_feerate, hash)}) {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string);
}
return true;
@@ -1650,7 +1655,8 @@ bool CScriptCheck::operator()() {
static CuckooCache::cache<uint256, SignatureCacheHasher> g_scriptExecutionCache;
static CSHA256 g_scriptExecutionCacheHasher;
-void InitScriptExecutionCache() {
+bool InitScriptExecutionCache(size_t max_size_bytes)
+{
// Setup the salted hasher
uint256 nonce = GetRandHash();
// We want the nonce to be 64 bytes long to force the hasher to process
@@ -1658,12 +1664,14 @@ void InitScriptExecutionCache() {
// just write our 32-byte entropy twice to fill the 64 bytes.
g_scriptExecutionCacheHasher.Write(nonce.begin(), 32);
g_scriptExecutionCacheHasher.Write(nonce.begin(), 32);
- // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
- // setup_bytes creates the minimum possible cache (2 elements).
- size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetIntArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
- size_t nElems = g_scriptExecutionCache.setup_bytes(nMaxCacheSize);
- LogPrintf("Using %zu MiB out of %zu/2 requested for script execution cache, able to store %zu elements\n",
- (nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems);
+
+ auto setup_results = g_scriptExecutionCache.setup_bytes(max_size_bytes);
+ if (!setup_results) return false;
+
+ const auto [num_elems, approx_size_bytes] = *setup_results;
+ LogPrintf("Using %zu MiB out of %zu MiB requested for script execution cache, able to store %zu elements\n",
+ approx_size_bytes >> 20, max_size_bytes >> 20, num_elems);
+ return true;
}
/**
@@ -2263,7 +2271,6 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
m_blockman.m_dirty_blockindex.insert(pindex);
}
- assert(pindex->phashBlock);
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
@@ -2575,6 +2582,7 @@ bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTr
CBlockIndex *pindexDelete = m_chain.Tip();
assert(pindexDelete);
+ assert(pindexDelete->pprev);
// Read block from disk.
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
CBlock& block = *pblock;
@@ -2622,7 +2630,7 @@ bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTr
}
}
- m_chain.SetTip(pindexDelete->pprev);
+ m_chain.SetTip(*pindexDelete->pprev);
UpdateTip(pindexDelete->pprev);
// Let wallets know transactions went from 1-confirmed to
@@ -2736,7 +2744,7 @@ bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew
disconnectpool.removeForBlock(blockConnecting.vtx);
}
// Update m_chain & related variables.
- m_chain.SetTip(pindexNew);
+ m_chain.SetTip(*pindexNew);
UpdateTip(pindexNew);
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
@@ -3861,13 +3869,11 @@ void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeigh
}
}
-void CChainState::LoadMempool(const ArgsManager& args)
+void CChainState::LoadMempool(const fs::path& load_path, FopenFn mockable_fopen_function)
{
if (!m_mempool) return;
- if (args.GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
- ::LoadMempool(*m_mempool, *this);
- }
- m_mempool->SetIsLoaded(!ShutdownRequested());
+ ::LoadMempool(*m_mempool, load_path, *this, mockable_fopen_function);
+ m_mempool->SetLoadTried(!ShutdownRequested());
}
bool CChainState::LoadChainTip()
@@ -3886,7 +3892,7 @@ bool CChainState::LoadChainTip()
if (!pindex) {
return false;
}
- m_chain.SetTip(pindex);
+ m_chain.SetTip(*pindex);
PruneBlockIndexCandidates();
tip = m_chain.Tip();
@@ -4256,11 +4262,16 @@ bool CChainState::LoadGenesisBlock()
return true;
}
-void CChainState::LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp)
+void CChainState::LoadExternalBlockFile(
+ FILE* fileIn,
+ FlatFilePos* dbp,
+ std::multimap<uint256, FlatFilePos>* blocks_with_unknown_parent)
{
AssertLockNotHeld(m_chainstate_mutex);
- // Map of disk positions for blocks with unknown parent (only used for reindex)
- static std::multimap<uint256, FlatFilePos> mapBlocksUnknownParent;
+
+ // Either both should be specified (-reindex), or neither (-loadblock).
+ assert(!dbp == !blocks_with_unknown_parent);
+
int64_t nStart = GetTimeMillis();
int nLoaded = 0;
@@ -4310,8 +4321,9 @@ void CChainState::LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp)
if (hash != m_params.GetConsensus().hashGenesisBlock && !m_blockman.LookupBlockIndex(block.hashPrevBlock)) {
LogPrint(BCLog::REINDEX, "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(),
block.hashPrevBlock.ToString());
- if (dbp)
- mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp));
+ if (dbp && blocks_with_unknown_parent) {
+ blocks_with_unknown_parent->emplace(block.hashPrevBlock, *dbp);
+ }
continue;
}
@@ -4340,13 +4352,15 @@ void CChainState::LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp)
NotifyHeaderTip(*this);
+ if (!blocks_with_unknown_parent) continue;
+
// Recursively process earlier encountered successors of this block
std::deque<uint256> queue;
queue.push_back(hash);
while (!queue.empty()) {
uint256 head = queue.front();
queue.pop_front();
- std::pair<std::multimap<uint256, FlatFilePos>::iterator, std::multimap<uint256, FlatFilePos>::iterator> range = mapBlocksUnknownParent.equal_range(head);
+ auto range = blocks_with_unknown_parent->equal_range(head);
while (range.first != range.second) {
std::multimap<uint256, FlatFilePos>::iterator it = range.first;
std::shared_ptr<CBlock> pblockrecursive = std::make_shared<CBlock>();
@@ -4361,7 +4375,7 @@ void CChainState::LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp)
}
}
range.first++;
- mapBlocksUnknownParent.erase(it);
+ blocks_with_unknown_parent->erase(it);
NotifyHeaderTip(*this);
}
}
@@ -4638,153 +4652,6 @@ bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
return ret;
}
-static const uint64_t MEMPOOL_DUMP_VERSION = 1;
-
-bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function)
-{
- int64_t nExpiryTimeout = std::chrono::seconds{pool.m_expiry}.count();
- FILE* filestr{mockable_fopen_function(gArgs.GetDataDirNet() / "mempool.dat", "rb")};
- CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
- if (file.IsNull()) {
- LogPrintf("Failed to open mempool file from disk. Continuing anyway.\n");
- return false;
- }
-
- int64_t count = 0;
- int64_t expired = 0;
- int64_t failed = 0;
- int64_t already_there = 0;
- int64_t unbroadcast = 0;
- int64_t nNow = GetTime();
-
- try {
- uint64_t version;
- file >> version;
- if (version != MEMPOOL_DUMP_VERSION) {
- return false;
- }
- uint64_t num;
- file >> num;
- while (num) {
- --num;
- CTransactionRef tx;
- int64_t nTime;
- int64_t nFeeDelta;
- file >> tx;
- file >> nTime;
- file >> nFeeDelta;
-
- CAmount amountdelta = nFeeDelta;
- if (amountdelta) {
- pool.PrioritiseTransaction(tx->GetHash(), amountdelta);
- }
- if (nTime > nNow - nExpiryTimeout) {
- LOCK(cs_main);
- const auto& accepted = AcceptToMemoryPool(active_chainstate, tx, nTime, /*bypass_limits=*/false, /*test_accept=*/false);
- if (accepted.m_result_type == MempoolAcceptResult::ResultType::VALID) {
- ++count;
- } else {
- // mempool may contain the transaction already, e.g. from
- // wallet(s) having loaded it while we were processing
- // mempool transactions; consider these as valid, instead of
- // failed, but mark them as 'already there'
- if (pool.exists(GenTxid::Txid(tx->GetHash()))) {
- ++already_there;
- } else {
- ++failed;
- }
- }
- } else {
- ++expired;
- }
- if (ShutdownRequested())
- return false;
- }
- std::map<uint256, CAmount> mapDeltas;
- file >> mapDeltas;
-
- for (const auto& i : mapDeltas) {
- pool.PrioritiseTransaction(i.first, i.second);
- }
-
- std::set<uint256> unbroadcast_txids;
- file >> unbroadcast_txids;
- unbroadcast = unbroadcast_txids.size();
- for (const auto& txid : unbroadcast_txids) {
- // Ensure transactions were accepted to mempool then add to
- // unbroadcast set.
- if (pool.get(txid) != nullptr) pool.AddUnbroadcastTx(txid);
- }
- } catch (const std::exception& e) {
- LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
- return false;
- }
-
- LogPrintf("Imported mempool transactions from disk: %i succeeded, %i failed, %i expired, %i already there, %i waiting for initial broadcast\n", count, failed, expired, already_there, unbroadcast);
- return true;
-}
-
-bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function, bool skip_file_commit)
-{
- int64_t start = GetTimeMicros();
-
- std::map<uint256, CAmount> mapDeltas;
- std::vector<TxMempoolInfo> vinfo;
- std::set<uint256> unbroadcast_txids;
-
- static Mutex dump_mutex;
- LOCK(dump_mutex);
-
- {
- LOCK(pool.cs);
- for (const auto &i : pool.mapDeltas) {
- mapDeltas[i.first] = i.second;
- }
- vinfo = pool.infoAll();
- unbroadcast_txids = pool.GetUnbroadcastTxs();
- }
-
- int64_t mid = GetTimeMicros();
-
- try {
- FILE* filestr{mockable_fopen_function(gArgs.GetDataDirNet() / "mempool.dat.new", "wb")};
- if (!filestr) {
- return false;
- }
-
- CAutoFile file(filestr, SER_DISK, CLIENT_VERSION);
-
- uint64_t version = MEMPOOL_DUMP_VERSION;
- file << version;
-
- file << (uint64_t)vinfo.size();
- for (const auto& i : vinfo) {
- file << *(i.tx);
- file << int64_t{count_seconds(i.m_time)};
- file << int64_t{i.nFeeDelta};
- mapDeltas.erase(i.tx->GetHash());
- }
-
- file << mapDeltas;
-
- LogPrintf("Writing %d unbroadcast transactions to disk.\n", unbroadcast_txids.size());
- file << unbroadcast_txids;
-
- if (!skip_file_commit && !FileCommit(file.Get()))
- throw std::runtime_error("FileCommit failed");
- file.fclose();
- if (!RenameOver(gArgs.GetDataDirNet() / "mempool.dat.new", gArgs.GetDataDirNet() / "mempool.dat")) {
- throw std::runtime_error("Rename failed");
- }
- int64_t last = GetTimeMicros();
- LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*MICRO, (last-mid)*MICRO);
- } catch (const std::exception& e) {
- LogPrintf("Failed to dump mempool: %s. Continuing anyway.\n", e.what());
- return false;
- }
- return true;
-}
-
//! Guess how far we are in the verification process at the given block index
//! require cs_main if pindex has not been validated yet (because nChainTx might be unset)
double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pindex) {
@@ -4867,7 +4734,7 @@ const AssumeutxoData* ExpectedAssumeutxo(
}
bool ChainstateManager::ActivateSnapshot(
- CAutoFile& coins_file,
+ AutoFile& coins_file,
const SnapshotMetadata& metadata,
bool in_memory)
{
@@ -4962,7 +4829,7 @@ static void FlushSnapshotToDisk(CCoinsViewCache& coins_cache, bool snapshot_load
bool ChainstateManager::PopulateAndValidateSnapshot(
CChainState& snapshot_chainstate,
- CAutoFile& coins_file,
+ AutoFile& coins_file,
const SnapshotMetadata& metadata)
{
// It's okay to release cs_main before we're done using `coins_cache` because we know
@@ -5102,7 +4969,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
return false;
}
- snapshot_chainstate.m_chain.SetTip(snapshot_start_block);
+ snapshot_chainstate.m_chain.SetTip(*snapshot_start_block);
// The remainder of this function requires modifying data protected by cs_main.
LOCK(::cs_main);
diff --git a/src/validation.h b/src/validation.h
index aa9fcf9f2d..17286c7910 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -68,8 +68,6 @@ static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = false;
static constexpr bool DEFAULT_COINSTATSINDEX{false};
static const char* const DEFAULT_BLOCKFILTERINDEX = "0";
-/** Default for -persistmempool */
-static const bool DEFAULT_PERSIST_MEMPOOL = true;
/** Default for -stopatheight */
static const int DEFAULT_STOPATHEIGHT = 0;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pruned. */
@@ -102,7 +100,6 @@ extern uint256 g_best_block;
* False indicates all script checking is done on the main threadMessageHandler thread.
*/
extern bool g_parallel_script_checks;
-extern bool fRequireStandard;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
/** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
@@ -259,12 +256,12 @@ PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTx
const Package& txns, bool test_accept)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-/* Transaction policy functions */
+/* Mempool validation helper functions */
/**
* Check if transaction will be final in the next block to be created.
*/
-bool CheckFinalTxAtTip(const CBlockIndex* active_chain_tip, const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+bool CheckFinalTxAtTip(const CBlockIndex& active_chain_tip, const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
/**
* Check if transaction will be BIP68 final in the next block to be created on top of tip.
@@ -326,7 +323,7 @@ public:
};
/** Initializes the script-execution cache */
-void InitScriptExecutionCache();
+[[nodiscard]] bool InitScriptExecutionCache(size_t max_size_bytes);
/** Functions for validating blocks and updating the block tree */
@@ -577,8 +574,36 @@ public:
bool ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
- /** Import blocks from an external file */
- void LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp = nullptr)
+ /**
+ * Import blocks from an external file
+ *
+ * During reindexing, this function is called for each block file (datadir/blocks/blk?????.dat).
+ * It reads all blocks contained in the given file and attempts to process them (add them to the
+ * block index). The blocks may be out of order within each file and across files. Often this
+ * function reads a block but finds that its parent hasn't been read yet, so the block can't be
+ * processed yet. The function will add an entry to the blocks_with_unknown_parent map (which is
+ * passed as an argument), so that when the block's parent is later read and processed, this
+ * function can re-read the child block from disk and process it.
+ *
+ * Because a block's parent may be in a later file, not just later in the same file, the
+ * blocks_with_unknown_parent map must be passed in and out with each call. It's a multimap,
+ * rather than just a map, because multiple blocks may have the same parent (when chain splits
+ * or stale blocks exist). It maps from parent-hash to child-disk-position.
+ *
+ * This function can also be used to read blocks from user-specified block files using the
+ * -loadblock= option. There's no unknown-parent tracking, so the last two arguments are omitted.
+ *
+ *
+ * @param[in] fileIn FILE handle to file containing blocks to read
+ * @param[in] dbp (optional) Disk block position (only for reindex)
+ * @param[in,out] blocks_with_unknown_parent (optional) Map of disk positions for blocks with
+ * unknown parent, key is parent block hash
+ * (only used for reindex)
+ * */
+ void LoadExternalBlockFile(
+ FILE* fileIn,
+ FlatFilePos* dbp = nullptr,
+ std::multimap<uint256, FlatFilePos>* blocks_with_unknown_parent = nullptr)
EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex);
/**
@@ -679,7 +704,7 @@ public:
void CheckBlockIndex();
/** Load the persisted mempool from disk */
- void LoadMempool(const ArgsManager& args);
+ void LoadMempool(const fs::path& load_path, fsbridge::FopenFn mockable_fopen_function = fsbridge::fopen);
/** Update the chain tip based on database information, i.e. CoinsTip()'s best block. */
bool LoadChainTip() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -820,7 +845,7 @@ private:
//! Internal helper for ActivateSnapshot().
[[nodiscard]] bool PopulateAndValidateSnapshot(
CChainState& snapshot_chainstate,
- CAutoFile& coins_file,
+ AutoFile& coins_file,
const node::SnapshotMetadata& metadata);
/**
@@ -909,7 +934,7 @@ public:
//! - Move the new chainstate to `m_snapshot_chainstate` and make it our
//! ChainstateActive().
[[nodiscard]] bool ActivateSnapshot(
- CAutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory);
+ AutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory);
//! The most-work chain.
CChainState& ActiveChainstate() const;
@@ -1014,14 +1039,6 @@ bool DeploymentEnabled(const ChainstateManager& chainman, DEP dep)
return DeploymentEnabled(chainman.GetConsensus(), dep);
}
-using FopenFn = std::function<FILE*(const fs::path&, const char*)>;
-
-/** Dump the mempool to disk. */
-bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function = fsbridge::fopen, bool skip_file_commit = false);
-
-/** Load the mempool from disk. */
-bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function = fsbridge::fopen);
-
/**
* Return the expected assumeutxo value for a given height, if one exists.
*
diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp
index dbd768a758..60715ff3c8 100644
--- a/src/wallet/bdb.cpp
+++ b/src/wallet/bdb.cpp
@@ -3,6 +3,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include <compat/compat.h>
#include <fs.h>
#include <wallet/bdb.h>
#include <wallet/db.h>
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index 9135e48104..e257d3f7c7 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -125,8 +125,6 @@ struct CoinSelectionParams {
CAmount m_min_change_target{0};
/** Cost of creating the change output. */
CAmount m_change_fee{0};
- /** The pre-determined minimum value to target when funding a change output. */
- CAmount m_change_target{0};
/** Cost of creating the change output + cost of spending the change output in the future. */
CAmount m_cost_of_change{0};
/** The targeted feerate of the transaction being built. */
diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp
index d80c3e25b0..f7fee443d0 100644
--- a/src/wallet/dump.cpp
+++ b/src/wallet/dump.cpp
@@ -41,7 +41,7 @@ bool DumpWallet(const ArgsManager& args, CWallet& wallet, bilingual_str& error)
return false;
}
- CHashWriter hasher(0, 0);
+ HashWriter hasher{};
WalletDatabase& db = wallet.GetDatabase();
std::unique_ptr<DatabaseBatch> batch = db.MakeBatch();
@@ -132,7 +132,7 @@ bool CreateFromDump(const ArgsManager& args, const std::string& name, const fs::
std::ifstream dump_file{dump_path};
// Compute the checksum
- CHashWriter hasher(0, 0);
+ HashWriter hasher{};
uint256 checksum;
// Check the magic and version
diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp
index 9d5f58b784..76de51ac3e 100644
--- a/src/wallet/external_signer_scriptpubkeyman.cpp
+++ b/src/wallet/external_signer_scriptpubkeyman.cpp
@@ -45,7 +45,8 @@ ExternalSigner ExternalSignerScriptPubKeyMan::GetExternalSigner() {
std::vector<ExternalSigner> signers;
ExternalSigner::Enumerate(command, signers, Params().NetworkIDString());
if (signers.empty()) throw std::runtime_error(std::string(__func__) + ": No external signers found");
- // TODO: add fingerprint argument in case of multiple signers
+ // TODO: add fingerprint argument instead of failing in case of multiple signers.
+ if (signers.size() > 1) throw std::runtime_error(std::string(__func__) + ": More than one external signer found. Please connect only one at a time.");
return signers[0];
}
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 43fdcee48d..c2b8082eae 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -21,7 +21,7 @@ namespace wallet {
//! mined, or conflicts with a mined transaction. Return a feebumper::Result.
static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWalletTx& wtx, std::vector<bilingual_str>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{
- if (wallet.HasWalletSpend(wtx.GetHash())) {
+ if (wallet.HasWalletSpend(wtx.tx)) {
errors.push_back(Untranslated("Transaction has descendants in the wallet"));
return feebumper::Result::INVALID_PARAMETER;
}
@@ -221,11 +221,11 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
constexpr int RANDOM_CHANGE_POSITION = -1;
auto res = CreateTransaction(wallet, recipients, RANDOM_CHANGE_POSITION, new_coin_control, false);
if (!res) {
- errors.push_back(Untranslated("Unable to create transaction.") + Untranslated(" ") + res.GetError());
+ errors.push_back(Untranslated("Unable to create transaction.") + Untranslated(" ") + util::ErrorString(res));
return Result::WALLET_ERROR;
}
- const auto& txr = res.GetObj();
+ const auto& txr = *res;
// Write back new fee if successful
new_fee = txr.fee;
diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp
index 6f81fa30a1..3514d018b7 100644
--- a/src/wallet/fees.cpp
+++ b/src/wallet/fees.cpp
@@ -87,7 +87,7 @@ CFeeRate GetDiscardRate(const CWallet& wallet)
CFeeRate discard_rate = wallet.chain().estimateSmartFee(highest_target, false /* conservative */);
// Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
discard_rate = (discard_rate == CFeeRate(0)) ? wallet.m_discard_rate : std::min(discard_rate, wallet.m_discard_rate);
- // Discard rate must be at least dustRelayFee
+ // Discard rate must be at least dust relay feerate
discard_rate = std::max(discard_rate, wallet.chain().relayDustFee());
return discard_rate;
}
diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp
index 23f91d9b3a..4fbc519e39 100644
--- a/src/wallet/interfaces.cpp
+++ b/src/wallet/interfaces.cpp
@@ -48,6 +48,8 @@ using interfaces::WalletTxStatus;
using interfaces::WalletValueMap;
namespace wallet {
+// All members of the classes in this namespace are intentionally public, as the
+// classes themselves are private.
namespace {
//! Construct wallet tx struct.
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
@@ -146,7 +148,7 @@ public:
void abortRescan() override { m_wallet->AbortRescan(); }
bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }
std::string getWalletName() override { return m_wallet->GetName(); }
- BResult<CTxDestination> getNewDestination(const OutputType type, const std::string label) override
+ util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string& label) override
{
LOCK(m_wallet->cs_wallet);
return m_wallet->GetNewDestination(type, label);
@@ -249,17 +251,17 @@ public:
LOCK(m_wallet->cs_wallet);
return m_wallet->ListLockedCoins(outputs);
}
- BResult<CTransactionRef> createTransaction(const std::vector<CRecipient>& recipients,
+ util::Result<CTransactionRef> createTransaction(const std::vector<CRecipient>& recipients,
const CCoinControl& coin_control,
bool sign,
int& change_pos,
CAmount& fee) override
{
LOCK(m_wallet->cs_wallet);
- const auto& res = CreateTransaction(*m_wallet, recipients, change_pos,
+ auto res = CreateTransaction(*m_wallet, recipients, change_pos,
coin_control, sign);
- if (!res) return res.GetError();
- const auto& txr = res.GetObj();
+ if (!res) return util::Error{util::ErrorString(res)};
+ const auto& txr = *res;
fee = txr.fee;
change_pos = txr.change_pos;
@@ -318,13 +320,12 @@ public:
}
return {};
}
- std::vector<WalletTx> getWalletTxs() override
+ std::set<WalletTx> getWalletTxs() override
{
LOCK(m_wallet->cs_wallet);
- std::vector<WalletTx> result;
- result.reserve(m_wallet->mapWallet.size());
+ std::set<WalletTx> result;
for (const auto& entry : m_wallet->mapWallet) {
- result.emplace_back(MakeWalletTx(*m_wallet, entry.second));
+ result.emplace(MakeWalletTx(*m_wallet, entry.second));
}
return result;
}
@@ -550,32 +551,34 @@ public:
void setMockTime(int64_t time) override { return SetMockTime(time); }
//! WalletLoader methods
- std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) override
+ util::Result<std::unique_ptr<Wallet>> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, std::vector<bilingual_str>& warnings) override
{
- std::shared_ptr<CWallet> wallet;
DatabaseOptions options;
DatabaseStatus status;
ReadDatabaseArgs(*m_context.args, options);
options.require_create = true;
options.create_flags = wallet_creation_flags;
options.create_passphrase = passphrase;
- return MakeWallet(m_context, CreateWallet(m_context, name, true /* load_on_start */, options, status, error, warnings));
+ bilingual_str error;
+ util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, CreateWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))};
+ return wallet ? std::move(wallet) : util::Error{error};
}
- std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
+ util::Result<std::unique_ptr<Wallet>> loadWallet(const std::string& name, std::vector<bilingual_str>& warnings) override
{
DatabaseOptions options;
DatabaseStatus status;
ReadDatabaseArgs(*m_context.args, options);
options.require_existing = true;
- return MakeWallet(m_context, LoadWallet(m_context, name, true /* load_on_start */, options, status, error, warnings));
+ bilingual_str error;
+ util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, LoadWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))};
+ return wallet ? std::move(wallet) : util::Error{error};
}
- BResult<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) override
+ util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) override
{
DatabaseStatus status;
bilingual_str error;
- BResult<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))};
- if (!wallet) return error;
- return wallet;
+ util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))};
+ return wallet ? std::move(wallet) : util::Error{error};
}
std::string getWalletDir() override
{
diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp
index c3aeef4209..db169aad12 100644
--- a/src/wallet/receive.cpp
+++ b/src/wallet/receive.cpp
@@ -9,15 +9,12 @@
#include <wallet/wallet.h>
namespace wallet {
-isminetype InputIsMine(const CWallet& wallet, const CTxIn &txin)
+isminetype InputIsMine(const CWallet& wallet, const CTxIn& txin)
{
AssertLockHeld(wallet.cs_wallet);
- std::map<uint256, CWalletTx>::const_iterator mi = wallet.mapWallet.find(txin.prevout.hash);
- if (mi != wallet.mapWallet.end())
- {
- const CWalletTx& prev = (*mi).second;
- if (txin.prevout.n < prev.tx->vout.size())
- return wallet.IsMine(prev.tx->vout[txin.prevout.n]);
+ const CWalletTx* prev = wallet.GetWalletTx(txin.prevout.hash);
+ if (prev && txin.prevout.n < prev->tx->vout.size()) {
+ return wallet.IsMine(prev->tx->vout[txin.prevout.n]);
}
return ISMINE_NO;
}
@@ -25,20 +22,8 @@ isminetype InputIsMine(const CWallet& wallet, const CTxIn &txin)
bool AllInputsMine(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter)
{
LOCK(wallet.cs_wallet);
-
- for (const CTxIn& txin : tx.vin)
- {
- auto mi = wallet.mapWallet.find(txin.prevout.hash);
- if (mi == wallet.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 (!(wallet.IsMine(prev.tx->vout[txin.prevout.n]) & filter))
- return false;
+ for (const CTxIn& txin : tx.vin) {
+ if (!(InputIsMine(wallet, txin) & filter)) return false;
}
return true;
}
@@ -111,10 +96,10 @@ CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx)
return nChange;
}
-static CAmount GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, const isminefilter& filter, bool recalculate = false)
+static CAmount GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, const isminefilter& filter)
{
auto& amount = wtx.m_amounts[type];
- if (recalculate || !amount.m_cached[filter]) {
+ if (!amount.m_cached[filter]) {
amount.Set(filter, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx, filter) : TxGetCredit(wallet, *wtx.tx, filter));
wtx.m_is_cache_empty = false;
}
@@ -130,12 +115,10 @@ CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const ism
return 0;
CAmount credit = 0;
- if (filter & ISMINE_SPENDABLE) {
+ const isminefilter get_amount_filter{filter & ISMINE_ALL};
+ if (get_amount_filter) {
// GetBalance can assume transactions in mapWallet won't change
- credit += GetCachableAmount(wallet, wtx, CWalletTx::CREDIT, ISMINE_SPENDABLE);
- }
- if (filter & ISMINE_WATCH_ONLY) {
- credit += GetCachableAmount(wallet, wtx, CWalletTx::CREDIT, ISMINE_WATCH_ONLY);
+ credit += GetCachableAmount(wallet, wtx, CWalletTx::CREDIT, get_amount_filter);
}
return credit;
}
@@ -146,11 +129,9 @@ CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const ismi
return 0;
CAmount debit = 0;
- if (filter & ISMINE_SPENDABLE) {
- debit += GetCachableAmount(wallet, wtx, CWalletTx::DEBIT, ISMINE_SPENDABLE);
- }
- if (filter & ISMINE_WATCH_ONLY) {
- debit += GetCachableAmount(wallet, wtx, CWalletTx::DEBIT, ISMINE_WATCH_ONLY);
+ const isminefilter get_amount_filter{filter & ISMINE_ALL};
+ if (get_amount_filter) {
+ debit += GetCachableAmount(wallet, wtx, CWalletTx::DEBIT, get_amount_filter);
}
return debit;
}
@@ -164,29 +145,18 @@ CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx)
return wtx.nChangeCached;
}
-CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, bool fUseCache)
-{
- AssertLockHeld(wallet.cs_wallet);
-
- if (wallet.IsTxImmatureCoinBase(wtx) && wallet.IsTxInMainChain(wtx)) {
- return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, ISMINE_SPENDABLE, !fUseCache);
- }
-
- return 0;
-}
-
-CAmount CachedTxGetImmatureWatchOnlyCredit(const CWallet& wallet, const CWalletTx& wtx, const bool fUseCache)
+CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
{
AssertLockHeld(wallet.cs_wallet);
if (wallet.IsTxImmatureCoinBase(wtx) && wallet.IsTxInMainChain(wtx)) {
- return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, ISMINE_WATCH_ONLY, !fUseCache);
+ return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, filter);
}
return 0;
}
-CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, bool fUseCache, const isminefilter& filter)
+CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
{
AssertLockHeld(wallet.cs_wallet);
@@ -197,7 +167,7 @@ CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx,
if (wallet.IsTxImmatureCoinBase(wtx))
return 0;
- if (fUseCache && allow_cache && wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_cached[filter]) {
+ if (allow_cache && wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_cached[filter]) {
return wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_value[filter];
}
@@ -332,8 +302,8 @@ Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
const CWalletTx& wtx = entry.second;
const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)};
const int tx_depth{wallet.GetTxDepthInMainChain(wtx)};
- const CAmount tx_credit_mine{CachedTxGetAvailableCredit(wallet, wtx, /*fUseCache=*/true, ISMINE_SPENDABLE | reuse_filter)};
- const CAmount tx_credit_watchonly{CachedTxGetAvailableCredit(wallet, wtx, /*fUseCache=*/true, ISMINE_WATCH_ONLY | reuse_filter)};
+ const CAmount tx_credit_mine{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_SPENDABLE | reuse_filter)};
+ const CAmount tx_credit_watchonly{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_WATCH_ONLY | reuse_filter)};
if (is_trusted && tx_depth >= min_depth) {
ret.m_mine_trusted += tx_credit_mine;
ret.m_watchonly_trusted += tx_credit_watchonly;
@@ -342,8 +312,8 @@ Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
ret.m_mine_untrusted_pending += tx_credit_mine;
ret.m_watchonly_untrusted_pending += tx_credit_watchonly;
}
- ret.m_mine_immature += CachedTxGetImmatureCredit(wallet, wtx);
- ret.m_watchonly_immature += CachedTxGetImmatureWatchOnlyCredit(wallet, wtx);
+ ret.m_mine_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_SPENDABLE);
+ ret.m_watchonly_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_WATCH_ONLY);
}
}
return ret;
diff --git a/src/wallet/receive.h b/src/wallet/receive.h
index 36759059b8..9125b1e9aa 100644
--- a/src/wallet/receive.h
+++ b/src/wallet/receive.h
@@ -29,11 +29,9 @@ CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const ism
//! filter decides which addresses will count towards the debit
CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter);
CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx);
-CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, bool fUseCache = true)
+CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
-CAmount CachedTxGetImmatureWatchOnlyCredit(const CWallet& wallet, const CWalletTx& wtx, const bool fUseCache = true)
- EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
-CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, bool fUseCache = true, const isminefilter& filter = ISMINE_SPENDABLE)
+CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter = ISMINE_SPENDABLE)
EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
struct COutputEntry
{
diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp
index 9428d049de..903a569cb9 100644
--- a/src/wallet/rpc/addresses.cpp
+++ b/src/wallet/rpc/addresses.cpp
@@ -34,7 +34,7 @@ RPCHelpMan getnewaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -60,10 +60,10 @@ RPCHelpMan getnewaddress()
auto op_dest = pwallet->GetNewDestination(output_type, label);
if (!op_dest) {
- throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, op_dest.GetError().original);
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, util::ErrorString(op_dest).original);
}
- return EncodeDestination(op_dest.GetObj());
+ return EncodeDestination(*op_dest);
},
};
}
@@ -86,7 +86,7 @@ RPCHelpMan getrawchangeaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -107,9 +107,9 @@ RPCHelpMan getrawchangeaddress()
auto op_dest = pwallet->GetNewChangeDestination(output_type);
if (!op_dest) {
- throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, op_dest.GetError().original);
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, util::ErrorString(op_dest).original);
}
- return EncodeDestination(op_dest.GetObj());
+ return EncodeDestination(*op_dest);
},
};
}
@@ -131,7 +131,7 @@ RPCHelpMan setlabel()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -148,7 +148,7 @@ RPCHelpMan setlabel()
pwallet->SetAddressBook(dest, label, "send");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -181,7 +181,7 @@ RPCHelpMan listaddressgroupings()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -252,7 +252,7 @@ RPCHelpMan addmultisigaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet);
@@ -327,7 +327,7 @@ RPCHelpMan keypoolrefill()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
if (pwallet->IsLegacy() && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
@@ -350,7 +350,7 @@ RPCHelpMan keypoolrefill()
throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -374,14 +374,14 @@ RPCHelpMan newkeypool()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
spk_man.NewKeyPool();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -548,7 +548,7 @@ RPCHelpMan getaddressinfo()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -578,7 +578,7 @@ RPCHelpMan getaddressinfo()
if (provider) {
auto inferred = InferDescriptor(scriptPubKey, *provider);
- bool solvable = inferred->IsSolvable() || IsSolvable(*provider, scriptPubKey);
+ bool solvable = inferred->IsSolvable();
ret.pushKV("solvable", solvable);
if (solvable) {
ret.pushKV("desc", inferred->ToString());
@@ -658,7 +658,7 @@ RPCHelpMan getaddressesbylabel()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -721,7 +721,7 @@ RPCHelpMan listlabels()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -763,7 +763,7 @@ RPCHelpMan walletdisplayaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- if (!wallet) return NullUniValue;
+ if (!wallet) return UniValue::VNULL;
CWallet* const pwallet = wallet.get();
LOCK(pwallet->cs_wallet);
diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp
index 5f1673fb12..306053fd0c 100644
--- a/src/wallet/rpc/backup.cpp
+++ b/src/wallet/rpc/backup.cpp
@@ -100,11 +100,13 @@ RPCHelpMan importprivkey()
"Hint: use importmulti to import more than one private key.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
+ "The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
+ "but the key was used to create transactions, rescanwallet needs to be called with the appropriate block range.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key (see dumpprivkey)"},
{"label", RPCArg::Type::STR, RPCArg::DefaultHint{"current label if address exists, otherwise \"\""}, "An optional label"},
- {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Rescan the wallet for transactions"},
+ {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Scan the chain and mempool for wallet transactions."},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
@@ -122,7 +124,7 @@ RPCHelpMan importprivkey()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
@@ -138,7 +140,7 @@ RPCHelpMan importprivkey()
EnsureWalletIsUnlocked(*pwallet);
std::string strSecret = request.params[0].get_str();
- std::string strLabel = "";
+ std::string strLabel;
if (!request.params[1].isNull())
strLabel = request.params[1].get_str();
@@ -190,7 +192,7 @@ RPCHelpMan importprivkey()
RescanWallet(*pwallet, reserver);
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -201,6 +203,8 @@ RPCHelpMan importaddress()
"\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
+ "The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
+ "but the key was used to create transactions, rescanwallet needs to be called with the appropriate block range.\n"
"If you have the full public key, you should call importpubkey instead of this.\n"
"Hint: use importmulti to import more than one address.\n"
"\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
@@ -210,7 +214,7 @@ RPCHelpMan importaddress()
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Bitcoin address (or hex-encoded script)"},
{"label", RPCArg::Type::STR, RPCArg::Default{""}, "An optional label"},
- {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Rescan the wallet for transactions"},
+ {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Scan the chain and mempool for wallet transactions."},
{"p2sh", RPCArg::Type::BOOL, RPCArg::Default{false}, "Add the P2SH version of the script as well"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
@@ -225,7 +229,7 @@ RPCHelpMan importaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
EnsureLegacyScriptPubKeyMan(*pwallet, true);
@@ -295,7 +299,7 @@ RPCHelpMan importaddress()
}
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -313,7 +317,7 @@ RPCHelpMan importprunedfunds()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
CMutableTransaction tx;
if (!DecodeHexTx(tx, request.params[0].get_str())) {
@@ -348,7 +352,7 @@ RPCHelpMan importprunedfunds()
CTransactionRef tx_ref = MakeTransactionRef(tx);
if (pwallet->IsMine(*tx_ref)) {
pwallet->AddToWallet(std::move(tx_ref), TxStateConfirmed{merkleBlock.header.GetHash(), height, static_cast<int>(txnIndex)});
- return NullUniValue;
+ return UniValue::VNULL;
}
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction");
@@ -372,7 +376,7 @@ RPCHelpMan removeprunedfunds()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -389,7 +393,7 @@ RPCHelpMan removeprunedfunds()
throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet.");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -401,11 +405,13 @@ RPCHelpMan importpubkey()
"Hint: use importmulti to import more than one public key.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
+ "The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
+ "but the key was used to create transactions, rescanwallet needs to be called with the appropriate block range.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"pubkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The hex-encoded public key"},
{"label", RPCArg::Type::STR, RPCArg::Default{""}, "An optional label"},
- {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Rescan the wallet for transactions"},
+ {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Scan the chain and mempool for wallet transactions."},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
@@ -419,7 +425,7 @@ RPCHelpMan importpubkey()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
EnsureLegacyScriptPubKeyMan(*pwallet, true);
@@ -474,7 +480,7 @@ RPCHelpMan importpubkey()
}
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -484,7 +490,7 @@ RPCHelpMan importwallet()
{
return RPCHelpMan{"importwallet",
"\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
- "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
+ "Note: Blockchain and Mempool will be rescanned after a successful import. Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet file"},
},
@@ -500,7 +506,7 @@ RPCHelpMan importwallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
EnsureLegacyScriptPubKeyMan(*pwallet, true);
@@ -631,7 +637,7 @@ RPCHelpMan importwallet()
if (!fGood)
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys/scripts to wallet");
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -655,7 +661,7 @@ RPCHelpMan dumpprivkey()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
const LegacyScriptPubKeyMan& spk_man = EnsureConstLegacyScriptPubKeyMan(*pwallet);
@@ -705,7 +711,7 @@ RPCHelpMan dumpwallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
const CWallet& wallet = *pwallet;
const LegacyScriptPubKeyMan& spk_man = EnsureConstLegacyScriptPubKeyMan(wallet);
@@ -1250,6 +1256,8 @@ RPCHelpMan importmulti()
"Conversely, if all the private keys are provided and the address/script is spendable, the watchonly option must be set to false, or a warning will be returned.\n"
"\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
"may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
+ "The rescan parameter can be set to false if the key was never used to create transactions. If it is set to false,\n"
+ "but the key was used to create transactions, rescanwallet needs to be called with the appropriate block range.\n"
"Note: Use \"getwalletinfo\" to query the scanning progress.\n",
{
{"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported",
@@ -1291,7 +1299,7 @@ RPCHelpMan importmulti()
"\"requests\""},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
{
- {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Stating if should rescan the blockchain after all imports"},
+ {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true}, "Scan the chain and mempool for wallet transactions after all imports."},
},
"\"options\""},
},
@@ -1320,7 +1328,7 @@ RPCHelpMan importmulti()
[&](const RPCHelpMan& self, const JSONRPCRequest& mainRequest) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(mainRequest);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
CWallet& wallet{*pwallet};
// Make sure the results are valid at least up to the most recent block
@@ -1593,7 +1601,7 @@ RPCHelpMan importdescriptors()
" Use the string \"now\" to substitute the current synced blockchain time.\n"
" \"now\" can be specified to bypass scanning, for outputs which are known to never have been used, and\n"
" 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest timestamp\n"
- " of all descriptors being imported will be scanned.",
+ "of all descriptors being imported will be scanned as well as the mempool.",
/*oneline_description=*/"", {"timestamp | \"now\"", "integer / string"}
},
{"internal", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether matching outputs should be treated as not incoming payments (e.g. change)"},
@@ -1628,7 +1636,7 @@ RPCHelpMan importdescriptors()
[&](const RPCHelpMan& self, const JSONRPCRequest& main_request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(main_request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
CWallet& wallet{*pwallet};
// Make sure the results are valid at least up to the most recent block
@@ -1763,7 +1771,7 @@ RPCHelpMan listdescriptors()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
- if (!wallet) return NullUniValue;
+ if (!wallet) return UniValue::VNULL;
if (!wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "listdescriptors is not available for non-descriptor wallets");
@@ -1832,7 +1840,7 @@ RPCHelpMan backupwallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -1845,7 +1853,7 @@ RPCHelpMan backupwallet()
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp
index 0dd514175d..c01ca28290 100644
--- a/src/wallet/rpc/coins.cpp
+++ b/src/wallet/rpc/coins.cpp
@@ -103,7 +103,7 @@ RPCHelpMan getreceivedbyaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -144,7 +144,7 @@ RPCHelpMan getreceivedbylabel()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -184,7 +184,7 @@ RPCHelpMan getbalance()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -223,7 +223,7 @@ RPCHelpMan getunconfirmedbalance()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -282,7 +282,7 @@ RPCHelpMan lockunspent()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -407,7 +407,7 @@ RPCHelpMan listlockunspent()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -459,7 +459,7 @@ RPCHelpMan getbalances()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
- if (!rpc_wallet) return NullUniValue;
+ if (!rpc_wallet) return UniValue::VNULL;
const CWallet& wallet = *rpc_wallet;
// Make sure the results are valid at least up to the most recent block
@@ -562,7 +562,7 @@ RPCHelpMan listunspent()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
int nMinDepth = 1;
if (!request.params[0].isNull()) {
@@ -641,7 +641,7 @@ RPCHelpMan listunspent()
cctl.m_max_depth = nMaxDepth;
cctl.m_include_unsafe_inputs = include_unsafe;
LOCK(pwallet->cs_wallet);
- vecOutputs = AvailableCoinsListUnspent(*pwallet, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount).coins;
+ vecOutputs = AvailableCoinsListUnspent(*pwallet, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount).all();
}
LOCK(pwallet->cs_wallet);
diff --git a/src/wallet/rpc/encrypt.cpp b/src/wallet/rpc/encrypt.cpp
index 931c64ca06..a68f52a718 100644
--- a/src/wallet/rpc/encrypt.cpp
+++ b/src/wallet/rpc/encrypt.cpp
@@ -32,7 +32,7 @@ RPCHelpMan walletpassphrase()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
- if (!wallet) return NullUniValue;
+ if (!wallet) return UniValue::VNULL;
CWallet* const pwallet = wallet.get();
int64_t nSleepTime;
@@ -98,7 +98,7 @@ RPCHelpMan walletpassphrase()
}
}, nSleepTime);
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -120,7 +120,7 @@ RPCHelpMan walletpassphrasechange()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -146,7 +146,7 @@ RPCHelpMan walletpassphrasechange()
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -173,7 +173,7 @@ RPCHelpMan walletlock()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -184,7 +184,7 @@ RPCHelpMan walletlock()
pwallet->Lock();
pwallet->nRelockTime = 0;
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -217,7 +217,7 @@ RPCHelpMan encryptwallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
diff --git a/src/wallet/rpc/signmessage.cpp b/src/wallet/rpc/signmessage.cpp
index 438d290030..ae4bd4fbc5 100644
--- a/src/wallet/rpc/signmessage.cpp
+++ b/src/wallet/rpc/signmessage.cpp
@@ -36,7 +36,7 @@ RPCHelpMan signmessage()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp
index 22c1f2bdc2..da0615ed1c 100644
--- a/src/wallet/rpc/spend.cpp
+++ b/src/wallet/rpc/spend.cpp
@@ -158,14 +158,14 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto
constexpr int RANDOM_CHANGE_POSITION = -1;
auto res = CreateTransaction(wallet, recipients, RANDOM_CHANGE_POSITION, coin_control, true);
if (!res) {
- throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, res.GetError().original);
+ throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, util::ErrorString(res).original);
}
- const CTransactionRef& tx = res.GetObj().tx;
+ const CTransactionRef& tx = res->tx;
wallet.CommitTransaction(tx, std::move(map_value), {} /* orderForm */);
if (verbose) {
UniValue entry(UniValue::VOBJ);
entry.pushKV("txid", tx->GetHash().GetHex());
- entry.pushKV("fee_reason", StringForFeeReason(res.GetObj().fee_calc.reason));
+ entry.pushKV("fee_reason", StringForFeeReason(res->fee_calc.reason));
return entry;
}
return tx->GetHash().GetHex();
@@ -226,8 +226,8 @@ RPCHelpMan sendtoaddress()
"The recipient will receive less bitcoins than you enter in the amount field."},
{"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
- " \"" + FeeModes("\"\n\"") + "\""},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
+ "\"" + FeeModes("\"\n\"") + "\""},
{"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
"dirty if they have previously been used in a transaction. If true, this also activates avoidpartialspends, grouping outputs by their addresses."},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
@@ -261,7 +261,7 @@ RPCHelpMan sendtoaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -335,8 +335,8 @@ RPCHelpMan sendmany()
},
{"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
- " \"" + FeeModes("\"\n\"") + "\""},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
+ "\"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
{"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra infomration about the transaction."},
},
@@ -367,7 +367,7 @@ RPCHelpMan sendmany()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -422,7 +422,7 @@ RPCHelpMan settxfee()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LOCK(pwallet->cs_wallet);
@@ -451,8 +451,8 @@ static std::vector<RPCArg> FundTxDoc(bool solving_data = true)
{
std::vector<RPCArg> args = {
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
- " \"" + FeeModes("\"\n\"") + "\""},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
+ "\"" + FeeModes("\"\n\"") + "\""},
{
"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125-replaceable.\n"
"Allows this transaction to be replaced by a transaction with higher fees"
@@ -805,7 +805,7 @@ RPCHelpMan fundrawtransaction()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
@@ -895,7 +895,7 @@ RPCHelpMan signrawtransactionwithwallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
@@ -967,7 +967,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
"still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
"are replaceable).\n"},
{"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
- "\"" + FeeModes("\"\n\"") + "\""},
+ "\"" + FeeModes("\"\n\"") + "\""},
},
"options"},
},
@@ -992,7 +992,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
[want_psbt](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) {
throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
@@ -1131,8 +1131,8 @@ RPCHelpMan send()
},
},
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
- " \"" + FeeModes("\"\n\"") + "\""},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
+ "\"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
Cat<std::vector<RPCArg>>(
@@ -1209,7 +1209,7 @@ RPCHelpMan send()
);
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
UniValue options{request.params[4].isNull() ? UniValue::VOBJ : request.params[4]};
InterpretFeeEstimationInstructions(/*conf_target=*/request.params[1], /*estimate_mode=*/request.params[2], /*fee_rate=*/request.params[3], options);
@@ -1252,8 +1252,8 @@ RPCHelpMan sendall()
},
},
{"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
- " \"" + FeeModes("\"\n\"") + "\""},
+ {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
+ "\"" + FeeModes("\"\n\"") + "\""},
{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
{
"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
@@ -1314,7 +1314,7 @@ RPCHelpMan sendall()
);
std::shared_ptr<CWallet> const pwallet{GetWalletForJSONRPCRequest(request)};
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
@@ -1382,7 +1382,7 @@ RPCHelpMan sendall()
total_input_value += tx->tx->vout[input.prevout.n].nValue;
}
} else {
- for (const COutput& output : AvailableCoins(*pwallet, &coin_control, fee_rate, /*nMinimumAmount=*/0).coins) {
+ for (const COutput& output : AvailableCoins(*pwallet, &coin_control, fee_rate, /*nMinimumAmount=*/0).all()) {
CHECK_NONFATAL(output.input_bytes > 0);
if (send_max && fee_rate.GetFee(output.input_bytes) > output.txout.nValue) {
continue;
@@ -1490,7 +1490,7 @@ RPCHelpMan walletprocesspsbt()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
const CWallet& wallet{*pwallet};
// Make sure the results are valid at least up to the most recent block
@@ -1617,7 +1617,7 @@ RPCHelpMan walletcreatefundedpsbt()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
CWallet& wallet{*pwallet};
// Make sure the results are valid at least up to the most recent block
@@ -1633,7 +1633,7 @@ RPCHelpMan walletcreatefundedpsbt()
}, true
);
- UniValue options = request.params[3];
+ UniValue options{request.params[3].isNull() ? UniValue::VOBJ : request.params[3]};
CAmount fee;
int change_position;
diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp
index aed9f0d5c1..a0769d3ecb 100644
--- a/src/wallet/rpc/transactions.cpp
+++ b/src/wallet/rpc/transactions.cpp
@@ -236,7 +236,7 @@ RPCHelpMan listreceivedbyaddress()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -281,7 +281,7 @@ RPCHelpMan listreceivedbylabel()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -479,7 +479,7 @@ RPCHelpMan listtransactions()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -595,7 +595,7 @@ RPCHelpMan listsinceblock()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
const CWallet& wallet = *pwallet;
// Make sure the results are valid at least up to the most recent block
@@ -740,7 +740,7 @@ RPCHelpMan gettransaction()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -813,7 +813,7 @@ RPCHelpMan abandontransaction()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -830,7 +830,7 @@ RPCHelpMan abandontransaction()
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
}
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -858,7 +858,7 @@ RPCHelpMan rescanblockchain()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
CWallet& wallet{*pwallet};
// Make sure the results are valid at least up to the most recent block
@@ -938,7 +938,7 @@ RPCHelpMan abortrescan()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
pwallet->AbortRescan();
diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp
index 4c44c333a6..eb275f9951 100644
--- a/src/wallet/rpc/wallet.cpp
+++ b/src/wallet/rpc/wallet.cpp
@@ -68,7 +68,7 @@ static RPCHelpMan getwalletinfo()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@@ -241,7 +241,7 @@ static RPCHelpMan loadwallet()
static RPCHelpMan setwalletflag()
{
- std::string flags = "";
+ std::string flags;
for (auto& it : WALLET_FLAG_MAP)
if (it.second & MUTABLE_WALLET_FLAGS)
flags += (flags == "" ? "" : ", ") + it.first;
@@ -267,7 +267,7 @@ static RPCHelpMan setwalletflag()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
std::string flag_str = request.params[0].get_str();
bool value = request.params[1].isNull() || request.params[1].get_bool();
@@ -480,7 +480,7 @@ static RPCHelpMan sethdseed()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
@@ -521,7 +521,7 @@ static RPCHelpMan sethdseed()
spk_man.SetHDSeed(master_pub_key);
if (flush_key_pool) spk_man.NewKeyPool();
- return NullUniValue;
+ return UniValue::VNULL;
},
};
}
@@ -532,7 +532,7 @@ static RPCHelpMan upgradewallet()
"\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n"
"New keys may be generated and a new wallet backup will need to be made.",
{
- {"version", RPCArg::Type::NUM, RPCArg::Default{FEATURE_LATEST}, "The version number to upgrade to. Default is the latest wallet version."}
+ {"version", RPCArg::Type::NUM, RPCArg::Default{int{FEATURE_LATEST}}, "The version number to upgrade to. Default is the latest wallet version."}
},
RPCResult{
RPCResult::Type::OBJ, "", "",
@@ -551,7 +551,7 @@ static RPCHelpMan upgradewallet()
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
- if (!pwallet) return NullUniValue;
+ if (!pwallet) return UniValue::VNULL;
RPCTypeCheck(request.params, {UniValue::VNUM}, true);
@@ -590,6 +590,117 @@ static RPCHelpMan upgradewallet()
};
}
+RPCHelpMan simulaterawtransaction()
+{
+ return RPCHelpMan{"simulaterawtransaction",
+ "\nCalculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
+ {
+ {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "An array of hex strings of raw transactions.\n",
+ {
+ {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
+ },
+ },
+ {"options", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED_NAMED_ARG, "Options",
+ {
+ {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see RPC importaddress)"},
+ },
+ },
+ },
+ RPCResult{
+ RPCResult::Type::OBJ, "", "",
+ {
+ {RPCResult::Type::STR_AMOUNT, "balance_change", "The wallet balance change (negative means decrease)."},
+ }
+ },
+ RPCExamples{
+ HelpExampleCli("simulaterawtransaction", "[\"myhex\"]")
+ + HelpExampleRpc("simulaterawtransaction", "[\"myhex\"]")
+ },
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
+{
+ const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
+ if (!rpc_wallet) return UniValue::VNULL;
+ const CWallet& wallet = *rpc_wallet;
+
+ RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VOBJ}, true);
+
+ LOCK(wallet.cs_wallet);
+
+ UniValue include_watchonly(UniValue::VNULL);
+ if (request.params[1].isObject()) {
+ UniValue options = request.params[1];
+ RPCTypeCheckObj(options,
+ {
+ {"include_watchonly", UniValueType(UniValue::VBOOL)},
+ },
+ true, true);
+
+ include_watchonly = options["include_watchonly"];
+ }
+
+ isminefilter filter = ISMINE_SPENDABLE;
+ if (ParseIncludeWatchonly(include_watchonly, wallet)) {
+ filter |= ISMINE_WATCH_ONLY;
+ }
+
+ const auto& txs = request.params[0].get_array();
+ CAmount changes{0};
+ std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array
+ std::set<COutPoint> spent;
+
+ for (size_t i = 0; i < txs.size(); ++i) {
+ CMutableTransaction mtx;
+ if (!DecodeHexTx(mtx, txs[i].get_str(), /* try_no_witness */ true, /* try_witness */ true)) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction hex string decoding failure.");
+ }
+
+ // Fetch previous transactions (inputs)
+ std::map<COutPoint, Coin> coins;
+ for (const CTxIn& txin : mtx.vin) {
+ coins[txin.prevout]; // Create empty map entry keyed by prevout.
+ }
+ wallet.chain().findCoins(coins);
+
+ // Fetch debit; we are *spending* these; if the transaction is signed and
+ // broadcast, we will lose everything in these
+ for (const auto& txin : mtx.vin) {
+ const auto& outpoint = txin.prevout;
+ if (spent.count(outpoint)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction(s) are spending the same output more than once");
+ }
+ if (new_utxos.count(outpoint)) {
+ changes -= new_utxos.at(outpoint);
+ new_utxos.erase(outpoint);
+ } else {
+ if (coins.at(outpoint).IsSpent()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");
+ }
+ changes -= wallet.GetDebit(txin, filter);
+ }
+ spent.insert(outpoint);
+ }
+
+ // Iterate over outputs; we are *receiving* these, if the wallet considers
+ // them "mine"; if the transaction is signed and broadcast, we will receive
+ // everything in these
+ // Also populate new_utxos in case these are spent in later transactions
+
+ const auto& hash = mtx.GetHash();
+ for (size_t i = 0; i < mtx.vout.size(); ++i) {
+ const auto& txout = mtx.vout[i];
+ bool is_mine = 0 < (wallet.IsMine(txout) & filter);
+ changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
+ }
+ }
+
+ UniValue result(UniValue::VOBJ);
+ result.pushKV("balance_change", ValueFromAmount(changes));
+
+ return result;
+}
+ };
+}
+
// addresses
RPCHelpMan getaddressinfo();
RPCHelpMan getnewaddress();
@@ -721,6 +832,7 @@ Span<const CRPCCommand> GetWalletRPCCommands()
{"wallet", &setwalletflag},
{"wallet", &signmessage},
{"wallet", &signrawtransactionwithwallet},
+ {"wallet", &simulaterawtransaction},
{"wallet", &sendall},
{"wallet", &unloadwallet},
{"wallet", &upgradewallet},
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index bba31dfe0b..7ff017775e 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -21,10 +21,10 @@ namespace wallet {
//! Value for the first BIP 32 hardened derivation. Can be used as a bit mask and as a value. See BIP 32 for more details.
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000;
-BResult<CTxDestination> LegacyScriptPubKeyMan::GetNewDestination(const OutputType type)
+util::Result<CTxDestination> LegacyScriptPubKeyMan::GetNewDestination(const OutputType type)
{
if (LEGACY_OUTPUT_TYPES.count(type) == 0) {
- return _("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types");;
+ return util::Error{_("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types")};
}
assert(type != OutputType::BECH32M);
@@ -33,7 +33,7 @@ BResult<CTxDestination> LegacyScriptPubKeyMan::GetNewDestination(const OutputTyp
// Generate a new key that is added to wallet
CPubKey new_key;
if (!GetKeyFromPool(new_key, type)) {
- return _("Error: Keypool ran out, please call keypoolrefill first");
+ return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
LearnRelatedScripts(new_key, type);
return GetDestinationForKey(new_key, type);
@@ -292,26 +292,22 @@ bool LegacyScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, WalletBat
return true;
}
-bool LegacyScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, bilingual_str& error)
+util::Result<CTxDestination> LegacyScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool)
{
if (LEGACY_OUTPUT_TYPES.count(type) == 0) {
- error = _("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types");
- return false;
+ return util::Error{_("Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and \"bech32\" address types")};
}
assert(type != OutputType::BECH32M);
LOCK(cs_KeyStore);
if (!CanGetAddresses(internal)) {
- error = _("Error: Keypool ran out, please call keypoolrefill first");
- return false;
+ return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
if (!ReserveKeyFromKeyPool(index, keypool, internal)) {
- error = _("Error: Keypool ran out, please call keypoolrefill first");
- return false;
+ return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
- address = GetDestinationForKey(keypool.vchPubKey, type);
- return true;
+ return GetDestinationForKey(keypool.vchPubKey, type);
}
bool LegacyScriptPubKeyMan::TopUpInactiveHDChain(const CKeyID seed_id, int64_t index, bool internal)
@@ -1084,6 +1080,13 @@ CPubKey LegacyScriptPubKeyMan::GenerateNewKey(WalletBatch &batch, CHDChain& hd_c
return pubkey;
}
+//! Try to derive an extended key, throw if it fails.
+static void DeriveExtKey(CExtKey& key_in, unsigned int index, CExtKey& key_out) {
+ if (!key_in.Derive(key_out, index)) {
+ throw std::runtime_error("Could not derive extended key");
+ }
+}
+
void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata& metadata, CKey& secret, CHDChain& hd_chain, bool internal)
{
// for now we use a fixed keypath scheme of m/0'/0'/k
@@ -1101,11 +1104,11 @@ void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata&
// derive m/0'
// use hardened derivation (child keys >= 0x80000000 are hardened after bip32)
- masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT);
+ DeriveExtKey(masterKey, BIP32_HARDENED_KEY_LIMIT, accountKey);
// derive m/0'/0' (external chain) OR m/0'/1' (internal chain)
assert(internal ? m_storage.CanSupportFeature(FEATURE_HD_SPLIT) : true);
- accountKey.Derive(chainChildKey, BIP32_HARDENED_KEY_LIMIT+(internal ? 1 : 0));
+ DeriveExtKey(accountKey, BIP32_HARDENED_KEY_LIMIT+(internal ? 1 : 0), chainChildKey);
// derive child key at next index, skip keys already known to the wallet
do {
@@ -1113,7 +1116,7 @@ void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata&
// childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range
// example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649
if (internal) {
- chainChildKey.Derive(childKey, hd_chain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
+ DeriveExtKey(chainChildKey, hd_chain.nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT, childKey);
metadata.hdKeypath = "m/0'/1'/" + ToString(hd_chain.nInternalChainCounter) + "'";
metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT);
metadata.key_origin.path.push_back(1 | BIP32_HARDENED_KEY_LIMIT);
@@ -1121,7 +1124,7 @@ void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata&
hd_chain.nInternalChainCounter++;
}
else {
- chainChildKey.Derive(childKey, hd_chain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT);
+ DeriveExtKey(chainChildKey, hd_chain.nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT, childKey);
metadata.hdKeypath = "m/0'/0'/" + ToString(hd_chain.nExternalChainCounter) + "'";
metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT);
metadata.key_origin.path.push_back(0 | BIP32_HARDENED_KEY_LIMIT);
@@ -1453,7 +1456,8 @@ void LegacyScriptPubKeyMan::LearnRelatedScripts(const CPubKey& key, OutputType t
CTxDestination witdest = WitnessV0KeyHash(key.GetID());
CScript witprog = GetScriptForDestination(witdest);
// Make sure the resulting program is solvable.
- assert(IsSolvable(*this, witprog));
+ const auto desc = InferDescriptor(witprog, *this);
+ assert(desc && desc->IsSolvable());
AddCScript(witprog);
}
}
@@ -1654,11 +1658,11 @@ std::set<CKeyID> LegacyScriptPubKeyMan::GetKeys() const
return set_address;
}
-BResult<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type)
+util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const OutputType type)
{
// Returns true if this descriptor supports getting new addresses. Conditions where we may be unable to fetch them (e.g. locked) are caught later
if (!CanGetAddresses()) {
- return _("No addresses available");
+ return util::Error{_("No addresses available")};
}
{
LOCK(cs_desc_man);
@@ -1676,11 +1680,11 @@ BResult<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const Outpu
std::vector<CScript> scripts_temp;
if (m_wallet_descriptor.range_end <= m_max_cached_index && !TopUp(1)) {
// We can't generate anymore keys
- return _("Error: Keypool ran out, please call keypoolrefill first");
+ return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
if (!m_wallet_descriptor.descriptor->ExpandFromCache(m_wallet_descriptor.next_index, m_wallet_descriptor.cache, scripts_temp, out_keys)) {
// We can't generate anymore keys
- return _("Error: Keypool ran out, please call keypoolrefill first");
+ return util::Error{_("Error: Keypool ran out, please call keypoolrefill first")};
}
CTxDestination dest;
@@ -1760,17 +1764,12 @@ bool DescriptorScriptPubKeyMan::Encrypt(const CKeyingMaterial& master_key, Walle
return true;
}
-bool DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, bilingual_str& error)
+util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool)
{
LOCK(cs_desc_man);
auto op_dest = GetNewDestination(type);
index = m_wallet_descriptor.next_index - 1;
- if (op_dest) {
- address = op_dest.GetObj();
- } else {
- error = op_dest.GetError();
- }
- return op_dest.HasRes();
+ return op_dest;
}
void DescriptorScriptPubKeyMan::ReturnDestination(int64_t index, bool internal, const CTxDestination& addr)
@@ -2075,10 +2074,21 @@ std::unique_ptr<FlatSigningProvider> DescriptorScriptPubKeyMan::GetSigningProvid
std::unique_ptr<FlatSigningProvider> DescriptorScriptPubKeyMan::GetSigningProvider(int32_t index, bool include_private) const
{
AssertLockHeld(cs_desc_man);
- // Get the scripts, keys, and key origins for this script
+
std::unique_ptr<FlatSigningProvider> out_keys = std::make_unique<FlatSigningProvider>();
- std::vector<CScript> scripts_temp;
- if (!m_wallet_descriptor.descriptor->ExpandFromCache(index, m_wallet_descriptor.cache, scripts_temp, *out_keys)) return nullptr;
+
+ // Fetch SigningProvider from cache to avoid re-deriving
+ auto it = m_map_signing_providers.find(index);
+ if (it != m_map_signing_providers.end()) {
+ *out_keys = Merge(*out_keys, it->second);
+ } else {
+ // Get the scripts, keys, and key origins for this script
+ std::vector<CScript> scripts_temp;
+ if (!m_wallet_descriptor.descriptor->ExpandFromCache(index, m_wallet_descriptor.cache, scripts_temp, *out_keys)) return nullptr;
+
+ // Cache SigningProvider so we don't need to re-derive if we need this SigningProvider again
+ m_map_signing_providers[index] = *out_keys;
+ }
if (HavePrivateKeys() && include_private) {
FlatSigningProvider master_provider;
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index eebc05330f..408d162eba 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -172,14 +172,14 @@ protected:
public:
explicit ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {}
virtual ~ScriptPubKeyMan() {};
- virtual BResult<CTxDestination> GetNewDestination(const OutputType type) { return Untranslated("Not supported"); }
+ virtual util::Result<CTxDestination> GetNewDestination(const OutputType type) { return util::Error{Untranslated("Not supported")}; }
virtual isminetype IsMine(const CScript& script) const { return ISMINE_NO; }
//! Check that the given decryption key is valid for this ScriptPubKeyMan, i.e. it decrypts all of the keys handled by it.
virtual bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) { return false; }
virtual bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) { return false; }
- virtual bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, bilingual_str& error) { return false; }
+ virtual util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) { return util::Error{Untranslated("Not supported")}; }
virtual void KeepDestination(int64_t index, const OutputType& type) {}
virtual void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) {}
@@ -360,13 +360,13 @@ private:
public:
using ScriptPubKeyMan::ScriptPubKeyMan;
- BResult<CTxDestination> GetNewDestination(const OutputType type) override;
+ util::Result<CTxDestination> GetNewDestination(const OutputType type) override;
isminetype IsMine(const CScript& script) const override;
bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) override;
bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;
- bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, bilingual_str& error) override;
+ util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) override;
void KeepDestination(int64_t index, const OutputType& type) override;
void ReturnDestination(int64_t index, bool internal, const CTxDestination&) override;
@@ -547,6 +547,8 @@ private:
KeyMap GetKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man);
+ // Cached FlatSigningProviders to avoid regenerating them each time they are needed.
+ mutable std::map<int32_t, FlatSigningProvider> m_map_signing_providers;
// Fetch the SigningProvider for the given script and optionally include private keys
std::unique_ptr<FlatSigningProvider> GetSigningProvider(const CScript& script, bool include_private = false) const;
// Fetch the SigningProvider for the given pubkey and always include private keys. This should only be called by signing code.
@@ -568,13 +570,13 @@ public:
mutable RecursiveMutex cs_desc_man;
- BResult<CTxDestination> GetNewDestination(const OutputType type) override;
+ util::Result<CTxDestination> GetNewDestination(const OutputType type) override;
isminetype IsMine(const CScript& script) const override;
bool CheckDecryptionKey(const CKeyingMaterial& master_key, bool accept_no_keys = false) override;
bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;
- bool GetReservedDestination(const OutputType type, bool internal, CTxDestination& address, int64_t& index, CKeyPool& keypool, bilingual_str& error) override;
+ util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index, CKeyPool& keypool) override;
void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) override;
// Tops up the descriptor cache and m_map_script_pub_keys. The cache is stored in the wallet file
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 9be29c4709..61d86844df 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -79,6 +79,32 @@ TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *walle
return CalculateMaximumSignedTxSize(tx, wallet, txouts, coin_control);
}
+uint64_t CoinsResult::size() const
+{
+ return bech32m.size() + bech32.size() + P2SH_segwit.size() + legacy.size() + other.size();
+}
+
+std::vector<COutput> CoinsResult::all() const
+{
+ std::vector<COutput> all;
+ all.reserve(this->size());
+ all.insert(all.end(), bech32m.begin(), bech32m.end());
+ all.insert(all.end(), bech32.begin(), bech32.end());
+ all.insert(all.end(), P2SH_segwit.begin(), P2SH_segwit.end());
+ all.insert(all.end(), legacy.begin(), legacy.end());
+ all.insert(all.end(), other.begin(), other.end());
+ return all;
+}
+
+void CoinsResult::clear()
+{
+ bech32m.clear();
+ bech32.clear();
+ P2SH_segwit.clear();
+ legacy.clear();
+ other.clear();
+}
+
CoinsResult AvailableCoins(const CWallet& wallet,
const CCoinControl* coinControl,
std::optional<CFeeRate> feerate,
@@ -187,16 +213,63 @@ CoinsResult AvailableCoins(const CWallet& wallet,
std::unique_ptr<SigningProvider> provider = wallet.GetSolvingProvider(output.scriptPubKey);
- bool solvable = provider ? IsSolvable(*provider, output.scriptPubKey) : false;
+ int input_bytes = CalculateMaximumSignedInputSize(output, COutPoint(), provider.get(), coinControl);
+ // Because CalculateMaximumSignedInputSize just uses ProduceSignature and makes a dummy signature,
+ // it is safe to assume that this input is solvable if input_bytes is greater -1.
+ bool solvable = input_bytes > -1;
bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
// Filter by spendable outputs only
if (!spendable && only_spendable) continue;
- int input_bytes = CalculateMaximumSignedInputSize(output, COutPoint(), provider.get(), coinControl);
- result.coins.emplace_back(outpoint, output, nDepth, input_bytes, spendable, solvable, safeTx, wtx.GetTxTime(), tx_from_me, feerate);
- result.total_amount += output.nValue;
+ // When parsing a scriptPubKey, Solver returns the parsed pubkeys or hashes (depending on the script)
+ // We don't need those here, so we are leaving them in return_values_unused
+ std::vector<std::vector<uint8_t>> return_values_unused;
+ TxoutType type;
+ bool is_from_p2sh{false};
+
+ // If the Output is P2SH and spendable, we want to know if it is
+ // a P2SH (legacy) or one of P2SH-P2WPKH, P2SH-P2WSH (P2SH-Segwit). We can determine
+ // this from the redeemScript. If the Output is not spendable, it will be classified
+ // as a P2SH (legacy), since we have no way of knowing otherwise without the redeemScript
+ if (output.scriptPubKey.IsPayToScriptHash() && solvable) {
+ CScript redeemScript;
+ CTxDestination destination;
+ if (!ExtractDestination(output.scriptPubKey, destination))
+ continue;
+ const CScriptID& hash = CScriptID(std::get<ScriptHash>(destination));
+ if (!provider->GetCScript(hash, redeemScript))
+ continue;
+ type = Solver(redeemScript, return_values_unused);
+ is_from_p2sh = true;
+ } else {
+ type = Solver(output.scriptPubKey, return_values_unused);
+ }
+ COutput coin(outpoint, output, nDepth, input_bytes, spendable, solvable, safeTx, wtx.GetTxTime(), tx_from_me, feerate);
+ switch (type) {
+ case TxoutType::WITNESS_UNKNOWN:
+ case TxoutType::WITNESS_V1_TAPROOT:
+ result.bech32m.push_back(coin);
+ break;
+ case TxoutType::WITNESS_V0_KEYHASH:
+ case TxoutType::WITNESS_V0_SCRIPTHASH:
+ if (is_from_p2sh) {
+ result.P2SH_segwit.push_back(coin);
+ break;
+ }
+ result.bech32.push_back(coin);
+ break;
+ case TxoutType::SCRIPTHASH:
+ case TxoutType::PUBKEYHASH:
+ result.legacy.push_back(coin);
+ break;
+ default:
+ result.other.push_back(coin);
+ };
+
+ // Cache total amount as we go
+ result.total_amount += output.nValue;
// Checks the sum amount of all UTXO's.
if (nMinimumSumAmount != MAX_MONEY) {
if (result.total_amount >= nMinimumSumAmount) {
@@ -205,7 +278,7 @@ CoinsResult AvailableCoins(const CWallet& wallet,
}
// Checks the maximum number of UTXO's.
- if (nMaximumCount > 0 && result.coins.size() >= nMaximumCount) {
+ if (nMaximumCount > 0 && result.size() >= nMaximumCount) {
return result;
}
}
@@ -261,7 +334,7 @@ std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet)
std::map<CTxDestination, std::vector<COutput>> result;
- for (const COutput& coin : AvailableCoinsListUnspent(wallet).coins) {
+ for (const COutput& coin : AvailableCoinsListUnspent(wallet).all()) {
CTxDestination address;
if ((coin.spendable || (wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && coin.solvable)) &&
ExtractDestination(FindNonChangeParentOutput(wallet, coin.outpoint).scriptPubKey, address)) {
@@ -379,20 +452,51 @@ std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<C
return groups_out;
}
-std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins,
- const CoinSelectionParams& coin_selection_params)
+std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins,
+ const CoinSelectionParams& coin_selection_params, bool allow_mixed_output_types)
+{
+ // Run coin selection on each OutputType and compute the Waste Metric
+ std::vector<SelectionResult> results;
+ if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, available_coins.legacy, coin_selection_params)}) {
+ results.push_back(*result);
+ }
+ if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, available_coins.P2SH_segwit, coin_selection_params)}) {
+ results.push_back(*result);
+ }
+ if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, available_coins.bech32, coin_selection_params)}) {
+ results.push_back(*result);
+ }
+ if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, available_coins.bech32m, coin_selection_params)}) {
+ results.push_back(*result);
+ }
+
+ // If we can't fund the transaction from any individual OutputType, run coin selection
+ // over all available coins, else pick the best solution from the results
+ if (results.size() == 0) {
+ if (allow_mixed_output_types) {
+ if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, available_coins.all(), coin_selection_params)}) {
+ return result;
+ }
+ }
+ return std::optional<SelectionResult>();
+ };
+ std::optional<SelectionResult> result{*std::min_element(results.begin(), results.end())};
+ return result;
+};
+
+std::optional<SelectionResult> ChooseSelectionResult(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins, const CoinSelectionParams& coin_selection_params)
{
// Vector of results. We will choose the best one based on waste.
std::vector<SelectionResult> results;
// Note that unlike KnapsackSolver, we do not include the fee for creating a change output as BnB will not create a change output.
- std::vector<OutputGroup> positive_groups = GroupOutputs(wallet, coins, coin_selection_params, eligibility_filter, true /* positive_only */);
+ std::vector<OutputGroup> positive_groups = GroupOutputs(wallet, available_coins, coin_selection_params, eligibility_filter, true /* positive_only */);
if (auto bnb_result{SelectCoinsBnB(positive_groups, nTargetValue, coin_selection_params.m_cost_of_change)}) {
results.push_back(*bnb_result);
}
// The knapsack solver has some legacy behavior where it will spend dust outputs. We retain this behavior, so don't filter for positive only here.
- std::vector<OutputGroup> all_groups = GroupOutputs(wallet, coins, coin_selection_params, eligibility_filter, false /* positive_only */);
+ std::vector<OutputGroup> all_groups = GroupOutputs(wallet, available_coins, coin_selection_params, eligibility_filter, false /* positive_only */);
CAmount target_with_change = nTargetValue;
// While nTargetValue includes the transaction fees for non-input things, it does not include the fee for creating a change output.
// So we need to include that for KnapsackSolver and SRD as well, as we are expecting to create a change output.
@@ -425,9 +529,8 @@ std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAm
return best_result;
}
-std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params)
+std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params)
{
- std::vector<COutput> vCoins(vAvailableCoins);
CAmount value_to_select = nTargetValue;
OutputGroup preset_inputs(coin_selection_params);
@@ -487,13 +590,13 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
return result;
}
- // remove preset inputs from vCoins so that Coin Selection doesn't pick them.
- for (std::vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coin_control.HasSelected();)
- {
- if (preset_coins.count(it->outpoint))
- it = vCoins.erase(it);
- else
- ++it;
+ // remove preset inputs from coins so that Coin Selection doesn't pick them.
+ if (coin_control.HasSelected()) {
+ available_coins.legacy.erase(remove_if(available_coins.legacy.begin(), available_coins.legacy.end(), [&](const COutput& c) { return preset_coins.count(c.outpoint); }), available_coins.legacy.end());
+ available_coins.P2SH_segwit.erase(remove_if(available_coins.P2SH_segwit.begin(), available_coins.P2SH_segwit.end(), [&](const COutput& c) { return preset_coins.count(c.outpoint); }), available_coins.P2SH_segwit.end());
+ available_coins.bech32.erase(remove_if(available_coins.bech32.begin(), available_coins.bech32.end(), [&](const COutput& c) { return preset_coins.count(c.outpoint); }), available_coins.bech32.end());
+ available_coins.bech32m.erase(remove_if(available_coins.bech32m.begin(), available_coins.bech32m.end(), [&](const COutput& c) { return preset_coins.count(c.outpoint); }), available_coins.bech32m.end());
+ available_coins.other.erase(remove_if(available_coins.other.begin(), available_coins.other.end(), [&](const COutput& c) { return preset_coins.count(c.outpoint); }), available_coins.other.end());
}
unsigned int limit_ancestor_count = 0;
@@ -505,11 +608,15 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
// form groups from remaining coins; note that preset coins will not
// automatically have their associated (same address) coins included
- if (coin_control.m_avoid_partial_spends && vCoins.size() > OUTPUT_GROUP_MAX_ENTRIES) {
+ if (coin_control.m_avoid_partial_spends && available_coins.size() > OUTPUT_GROUP_MAX_ENTRIES) {
// Cases where we have 101+ outputs all pointing to the same destination may result in
// privacy leaks as they will potentially be deterministically sorted. We solve that by
// explicitly shuffling the outputs before processing
- Shuffle(vCoins.begin(), vCoins.end(), coin_selection_params.rng_fast);
+ Shuffle(available_coins.legacy.begin(), available_coins.legacy.end(), coin_selection_params.rng_fast);
+ Shuffle(available_coins.P2SH_segwit.begin(), available_coins.P2SH_segwit.end(), coin_selection_params.rng_fast);
+ Shuffle(available_coins.bech32.begin(), available_coins.bech32.end(), coin_selection_params.rng_fast);
+ Shuffle(available_coins.bech32m.begin(), available_coins.bech32m.end(), coin_selection_params.rng_fast);
+ Shuffle(available_coins.other.begin(), available_coins.other.end(), coin_selection_params.rng_fast);
}
// Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the
@@ -521,26 +628,27 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
// If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
// confirmations on outputs received from other wallets and only spend confirmed change.
- if (auto r1{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(1, 6, 0), vCoins, coin_selection_params)}) return r1;
- if (auto r2{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(1, 1, 0), vCoins, coin_selection_params)}) return r2;
+ if (auto r1{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(1, 6, 0), available_coins, coin_selection_params, /*allow_mixed_output_types=*/false)}) return r1;
+ // Allow mixing only if no solution from any single output type can be found
+ if (auto r2{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(1, 1, 0), available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) return r2;
// Fall back to using zero confirmation change (but with as few ancestors in the mempool as
// possible) if we cannot fund the transaction otherwise.
if (wallet.m_spend_zero_conf_change) {
- if (auto r3{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, 2), vCoins, coin_selection_params)}) return r3;
+ if (auto r3{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, 2), available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) return r3;
if (auto r4{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)),
- vCoins, coin_selection_params)}) {
+ available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) {
return r4;
}
if (auto r5{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2),
- vCoins, coin_selection_params)}) {
+ available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) {
return r5;
}
// If partial groups are allowed, relax the requirement of spending OutputGroups (groups
// of UTXOs sent to the same address, which are obviously controlled by a single wallet)
// in their entirety.
if (auto r6{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
- vCoins, coin_selection_params)}) {
+ available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) {
return r6;
}
// Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
@@ -548,7 +656,7 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
if (coin_control.m_include_unsafe_inputs) {
if (auto r7{AttemptSelection(wallet, value_to_select,
CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
- vCoins, coin_selection_params)}) {
+ available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) {
return r7;
}
}
@@ -558,7 +666,7 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
if (!fRejectLongChains) {
if (auto r8{AttemptSelection(wallet, value_to_select,
CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max(), true /* include_partial_groups */),
- vCoins, coin_selection_params)}) {
+ available_coins, coin_selection_params, /*allow_mixed_output_types=*/true)}) {
return r8;
}
}
@@ -652,7 +760,7 @@ static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng
}
}
-static BResult<CreatedTransactionResult> CreateTransactionInternal(
+static util::Result<CreatedTransactionResult> CreateTransactionInternal(
CWallet& wallet,
const std::vector<CRecipient>& vecSend,
int change_pos,
@@ -686,7 +794,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
coin_selection_params.m_subtract_fee_outputs = true;
}
}
- coin_selection_params.m_change_target = GenerateChangeTarget(std::floor(recipients_sum / vecSend.size()), rng_fast);
+ coin_selection_params.m_min_change_target = GenerateChangeTarget(std::floor(recipients_sum / vecSend.size()), rng_fast);
// Create change script that will be used if we need change
CScript scriptChange;
@@ -706,11 +814,13 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Reserve a new key pair from key pool. If it fails, provide a dummy
// destination in case we don't need change.
CTxDestination dest;
- bilingual_str dest_err;
- if (!reservedest.GetReservedDestination(dest, true, dest_err)) {
- error = _("Transaction needs a change address, but we can't generate it.") + Untranslated(" ") + dest_err;
+ auto op_dest = reservedest.GetReservedDestination(true);
+ if (!op_dest) {
+ error = _("Transaction needs a change address, but we can't generate it.") + Untranslated(" ") + util::ErrorString(op_dest);
+ } else {
+ dest = *op_dest;
+ scriptChange = GetScriptForDestination(dest);
}
- scriptChange = GetScriptForDestination(dest);
// A valid destination implies a change script (and
// vice-versa). An empty change script will abort later, if the
// change keypool ran out, but change is required.
@@ -738,11 +848,11 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
// provided one
if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate) {
- return strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::SAT_VB));
+ return util::Error{strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::SAT_VB))};
}
if (feeCalc.reason == FeeReason::FALLBACK && !wallet.m_allow_fallback_fee) {
// eventually allow a fallback fee
- return _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
+ return util::Error{_("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.")};
}
// Calculate the cost of change
@@ -768,7 +878,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
}
if (IsDust(txout, wallet.chain().relayDustFee())) {
- return _("Transaction amount too small");
+ return util::Error{_("Transaction amount too small")};
}
txNew.vout.push_back(txout);
}
@@ -778,7 +888,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
CAmount selection_target = recipients_sum + not_input_fees;
// Get available coins
- auto res_available_coins = AvailableCoins(wallet,
+ auto available_coins = AvailableCoins(wallet,
&coin_control,
coin_selection_params.m_effective_feerate,
1, /*nMinimumAmount*/
@@ -787,9 +897,9 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
0); /*nMaximumCount*/
// Choose coins to use
- std::optional<SelectionResult> result = SelectCoins(wallet, res_available_coins.coins, /*nTargetValue=*/selection_target, coin_control, coin_selection_params);
+ std::optional<SelectionResult> result = SelectCoins(wallet, available_coins, /*nTargetValue=*/selection_target, coin_control, coin_selection_params);
if (!result) {
- return _("Insufficient funds");
+ return util::Error{_("Insufficient funds")};
}
TRACE5(coin_selection, selected_coins, wallet.GetName().c_str(), GetAlgorithmName(result->m_algo).c_str(), result->m_target, result->GetWaste(), result->GetSelectedValue());
@@ -804,7 +914,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
nChangePosInOut = rng_fast.randrange(txNew.vout.size() + 1);
}
else if ((unsigned int)nChangePosInOut > txNew.vout.size()) {
- return _("Transaction change output index out of range");
+ return util::Error{_("Transaction change output index out of range")};
}
assert(nChangePosInOut != -1);
@@ -831,7 +941,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
TxSize tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), &wallet, &coin_control);
int nBytes = tx_sizes.vsize;
if (nBytes == -1) {
- return _("Missing solving data for estimating transaction size");
+ return util::Error{_("Missing solving data for estimating transaction size")};
}
nFeeRet = coin_selection_params.m_effective_feerate.GetFee(nBytes);
@@ -891,9 +1001,9 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Error if this output is reduced to be below dust
if (IsDust(txout, wallet.chain().relayDustFee())) {
if (txout.nValue < 0) {
- return _("The transaction amount is too small to pay the fee");
+ return util::Error{_("The transaction amount is too small to pay the fee")};
} else {
- return _("The transaction amount is too small to send after the fee has been deducted");
+ return util::Error{_("The transaction amount is too small to send after the fee has been deducted")};
}
}
}
@@ -904,11 +1014,11 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
// Give up if change keypool ran out and change is required
if (scriptChange.empty() && nChangePosInOut != -1) {
- return error;
+ return util::Error{error};
}
if (sign && !wallet.SignTransaction(txNew)) {
- return _("Signing transaction failed");
+ return util::Error{_("Signing transaction failed")};
}
// Return the constructed transaction data.
@@ -918,17 +1028,17 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
if ((sign && GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT) ||
(!sign && tx_sizes.weight > MAX_STANDARD_TX_WEIGHT))
{
- return _("Transaction too large");
+ return util::Error{_("Transaction too large")};
}
if (nFeeRet > wallet.m_default_max_tx_fee) {
- return TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
+ return util::Error{TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED)};
}
if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits
if (!wallet.chain().checkChainLimits(tx)) {
- return _("Transaction has too long of a mempool chain");
+ return util::Error{_("Transaction has too long of a mempool chain")};
}
}
@@ -947,7 +1057,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut, feeCalc);
}
-BResult<CreatedTransactionResult> CreateTransaction(
+util::Result<CreatedTransactionResult> CreateTransaction(
CWallet& wallet,
const std::vector<CRecipient>& vecSend,
int change_pos,
@@ -955,28 +1065,26 @@ BResult<CreatedTransactionResult> CreateTransaction(
bool sign)
{
if (vecSend.empty()) {
- return _("Transaction must have at least one recipient");
+ return util::Error{_("Transaction must have at least one recipient")};
}
if (std::any_of(vecSend.cbegin(), vecSend.cend(), [](const auto& recipient){ return recipient.nAmount < 0; })) {
- return _("Transaction amounts must not be negative");
+ return util::Error{_("Transaction amounts must not be negative")};
}
LOCK(wallet.cs_wallet);
auto res = CreateTransactionInternal(wallet, vecSend, change_pos, coin_control, sign);
- TRACE4(coin_selection, normal_create_tx_internal, wallet.GetName().c_str(), res.HasRes(),
- res ? res.GetObj().fee : 0, res ? res.GetObj().change_pos : 0);
+ TRACE4(coin_selection, normal_create_tx_internal, wallet.GetName().c_str(), bool(res),
+ res ? res->fee : 0, res ? res->change_pos : 0);
if (!res) return res;
- const auto& txr_ungrouped = res.GetObj();
+ const auto& txr_ungrouped = *res;
// try with avoidpartialspends unless it's enabled already
if (txr_ungrouped.fee > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends) {
TRACE1(coin_selection, attempting_aps_create_tx, wallet.GetName().c_str());
CCoinControl tmp_cc = coin_control;
tmp_cc.m_avoid_partial_spends = true;
- auto res_tx_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
- // Helper optional class for now
- std::optional<CreatedTransactionResult> txr_grouped{res_tx_grouped.HasRes() ? std::make_optional(res_tx_grouped.GetObj()) : std::nullopt};
+ auto txr_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign);
// if fee of this alternative one is within the range of the max fee, we use this one
const bool use_aps{txr_grouped.has_value() ? (txr_grouped->fee <= txr_ungrouped.fee + wallet.m_max_aps_fee) : false};
TRACE5(coin_selection, aps_create_tx_internal, wallet.GetName().c_str(), use_aps, txr_grouped.has_value(),
@@ -984,7 +1092,7 @@ BResult<CreatedTransactionResult> CreateTransaction(
if (txr_grouped) {
wallet.WalletLogPrintf("Fee non-grouped = %lld, grouped = %lld, using %s\n",
txr_ungrouped.fee, txr_grouped->fee, use_aps ? "grouped" : "non-grouped");
- if (use_aps) return res_tx_grouped;
+ if (use_aps) return txr_grouped;
}
}
return res;
@@ -1025,10 +1133,10 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet,
auto res = CreateTransaction(wallet, vecSend, nChangePosInOut, coinControl, false);
if (!res) {
- error = res.GetError();
+ error = util::ErrorString(res);
return false;
}
- const auto& txr = res.GetObj();
+ const auto& txr = *res;
CTransactionRef tx_new = txr.tx;
nFeeRet = txr.fee;
nChangePosInOut = txr.change_pos;
diff --git a/src/wallet/spend.h b/src/wallet/spend.h
index ab0ff1ee58..fdb5113ba4 100644
--- a/src/wallet/spend.h
+++ b/src/wallet/spend.h
@@ -29,14 +29,38 @@ struct TxSize {
TxSize CalculateMaximumSignedTxSize(const CTransaction& tx, const CWallet* wallet, const std::vector<CTxOut>& txouts, const CCoinControl* coin_control = nullptr);
TxSize CalculateMaximumSignedTxSize(const CTransaction& tx, const CWallet* wallet, const CCoinControl* coin_control = nullptr) EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet);
+/**
+ * COutputs available for spending, stored by OutputType.
+ * This struct is really just a wrapper around OutputType vectors with a convenient
+ * method for concatenating and returning all COutputs as one vector.
+ *
+ * clear(), size() methods are implemented so that one can interact with
+ * the CoinsResult struct as if it was a vector
+ */
struct CoinsResult {
- std::vector<COutput> coins;
- // Sum of all the coins amounts
+ /** Vectors for each OutputType */
+ std::vector<COutput> legacy;
+ std::vector<COutput> P2SH_segwit;
+ std::vector<COutput> bech32;
+ std::vector<COutput> bech32m;
+
+ /** Other is a catch-all for anything that doesn't match the known OutputTypes */
+ std::vector<COutput> other;
+
+ /** Concatenate and return all COutputs as one vector */
+ std::vector<COutput> all() const;
+
+ /** The following methods are provided so that CoinsResult can mimic a vector,
+ * i.e., methods can work with individual OutputType vectors or on the entire object */
+ uint64_t size() const;
+ void clear();
+
+ /** Sum of all available coins */
CAmount total_amount{0};
};
+
/**
- * Return vector of available COutputs.
- * By default, returns only the spendable coins.
+ * Populate the CoinsResult struct with vectors of available COutputs, organized by OutputType.
*/
CoinsResult AvailableCoins(const CWallet& wallet,
const CCoinControl* coinControl = nullptr,
@@ -67,35 +91,52 @@ const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint&
std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<COutput>& outputs, const CoinSelectionParams& coin_sel_params, const CoinEligibilityFilter& filter, bool positive_only);
+/**
+ * Attempt to find a valid input set that preserves privacy by not mixing OutputTypes.
+ * `ChooseSelectionResult()` will be called on each OutputType individually and the best
+ * the solution (according to the waste metric) will be chosen. If a valid input cannot be found from any
+ * single OutputType, fallback to running `ChooseSelectionResult()` over all available coins.
+ *
+ * param@[in] wallet The wallet which provides solving data for the coins
+ * param@[in] nTargetValue The target value
+ * param@[in] eligilibity_filter A filter containing rules for which coins are allowed to be included in this selection
+ * param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
+ * param@[in] coin_selection_params Parameters for the coin selection
+ * param@[in] allow_mixed_output_types Relax restriction that SelectionResults must be of the same OutputType
+ * returns If successful, a SelectionResult containing the input set
+ * If failed, a nullopt
+ */
+std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins,
+ const CoinSelectionParams& coin_selection_params, bool allow_mixed_output_types);
/**
* Attempt to find a valid input set that meets the provided eligibility filter and target.
* Multiple coin selection algorithms will be run and the input set that produces the least waste
* (according to the waste metric) will be chosen.
*
- * param@[in] wallet The wallet which provides solving data for the coins
- * param@[in] nTargetValue The target value
- * param@[in] eligilibity_filter A filter containing rules for which coins are allowed to be included in this selection
- * param@[in] coins The vector of coins available for selection prior to filtering
- * param@[in] coin_selection_params Parameters for the coin selection
- * returns If successful, a SelectionResult containing the input set
- * If failed, a nullopt
+ * param@[in] wallet The wallet which provides solving data for the coins
+ * param@[in] nTargetValue The target value
+ * param@[in] eligilibity_filter A filter containing rules for which coins are allowed to be included in this selection
+ * param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
+ * param@[in] coin_selection_params Parameters for the coin selection
+ * returns If successful, a SelectionResult containing the input set
+ * If failed, a nullopt
*/
-std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins,
+std::optional<SelectionResult> ChooseSelectionResult(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins,
const CoinSelectionParams& coin_selection_params);
/**
* Select a set of coins such that nTargetValue is met and at least
* all coins from coin_control are selected; never select unconfirmed coins if they are not ours
* param@[in] wallet The wallet which provides data necessary to spend the selected coins
- * param@[in] vAvailableCoins The vector of coins available to be spent
+ * param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
* param@[in] nTargetValue The target value
* param@[in] coin_selection_params Parameters for this coin selection such as feerates, whether to avoid partial spends,
* and whether to subtract the fee from the outputs.
* returns If successful, a SelectionResult containing the selected coins
* If failed, a nullopt.
*/
-std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, const CCoinControl& coin_control,
+std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue, const CCoinControl& coin_control,
const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
struct CreatedTransactionResult
@@ -114,7 +155,7 @@ struct CreatedTransactionResult
* selected by SelectCoins(); Also create the change output, when needed
* @note passing change_pos as -1 will result in setting a random position
*/
-BResult<CreatedTransactionResult> CreateTransaction(CWallet& wallet, const std::vector<CRecipient>& vecSend, int change_pos, const CCoinControl& coin_control, bool sign = true);
+util::Result<CreatedTransactionResult> CreateTransaction(CWallet& wallet, const std::vector<CRecipient>& vecSend, int change_pos, const CCoinControl& coin_control, bool sign = true);
/**
* Insert additional inputs into the transaction by
diff --git a/src/wallet/test/availablecoins_tests.cpp b/src/wallet/test/availablecoins_tests.cpp
new file mode 100644
index 0000000000..3356128112
--- /dev/null
+++ b/src/wallet/test/availablecoins_tests.cpp
@@ -0,0 +1,105 @@
+// Copyright (c) 2022 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or https://www.opensource.org/licenses/mit-license.php.
+
+#include <validation.h>
+#include <wallet/coincontrol.h>
+#include <wallet/spend.h>
+#include <wallet/test/util.h>
+#include <wallet/test/wallet_test_fixture.h>
+
+#include <boost/test/unit_test.hpp>
+
+namespace wallet {
+BOOST_FIXTURE_TEST_SUITE(availablecoins_tests, WalletTestingSetup)
+class AvailableCoinsTestingSetup : public TestChain100Setup
+{
+public:
+ AvailableCoinsTestingSetup()
+ {
+ CreateAndProcessBlock({}, {});
+ wallet = CreateSyncedWallet(*m_node.chain, m_node.chainman->ActiveChain(), m_args, coinbaseKey);
+ }
+
+ ~AvailableCoinsTestingSetup()
+ {
+ wallet.reset();
+ }
+ CWalletTx& AddTx(CRecipient recipient)
+ {
+ CTransactionRef tx;
+ CCoinControl dummy;
+ {
+ constexpr int RANDOM_CHANGE_POSITION = -1;
+ auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, dummy);
+ BOOST_CHECK(res);
+ tx = res->tx;
+ }
+ wallet->CommitTransaction(tx, {}, {});
+ CMutableTransaction blocktx;
+ {
+ LOCK(wallet->cs_wallet);
+ blocktx = CMutableTransaction(*wallet->mapWallet.at(tx->GetHash()).tx);
+ }
+ CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+
+ LOCK(wallet->cs_wallet);
+ wallet->SetLastBlockProcessed(wallet->GetLastBlockHeight() + 1, m_node.chainman->ActiveChain().Tip()->GetBlockHash());
+ auto it = wallet->mapWallet.find(tx->GetHash());
+ BOOST_CHECK(it != wallet->mapWallet.end());
+ it->second.m_state = TxStateConfirmed{m_node.chainman->ActiveChain().Tip()->GetBlockHash(), m_node.chainman->ActiveChain().Height(), /*index=*/1};
+ return it->second;
+ }
+
+ std::unique_ptr<CWallet> wallet;
+};
+
+BOOST_FIXTURE_TEST_CASE(BasicOutputTypesTest, AvailableCoinsTestingSetup)
+{
+ CoinsResult available_coins;
+ util::Result<CTxDestination> dest{util::Error{}};
+ LOCK(wallet->cs_wallet);
+
+ // Verify our wallet has one usable coinbase UTXO before starting
+ // This UTXO is a P2PK, so it should show up in the Other bucket
+ available_coins = AvailableCoins(*wallet);
+ BOOST_CHECK_EQUAL(available_coins.size(), 1U);
+ BOOST_CHECK_EQUAL(available_coins.other.size(), 1U);
+
+ // We will create a self transfer for each of the OutputTypes and
+ // verify it is put in the correct bucket after running GetAvailablecoins
+ //
+ // For each OutputType, We expect 2 UTXOs in our wallet following the self transfer:
+ // 1. One UTXO as the recipient
+ // 2. One UTXO from the change, due to payment address matching logic
+
+ // Bech32m
+ dest = wallet->GetNewDestination(OutputType::BECH32M, "");
+ BOOST_ASSERT(dest);
+ AddTx(CRecipient{{GetScriptForDestination(*dest)}, 1 * COIN, /*fSubtractFeeFromAmount=*/true});
+ available_coins = AvailableCoins(*wallet);
+ BOOST_CHECK_EQUAL(available_coins.bech32m.size(), 2U);
+
+ // Bech32
+ dest = wallet->GetNewDestination(OutputType::BECH32, "");
+ BOOST_ASSERT(dest);
+ AddTx(CRecipient{{GetScriptForDestination(*dest)}, 2 * COIN, /*fSubtractFeeFromAmount=*/true});
+ available_coins = AvailableCoins(*wallet);
+ BOOST_CHECK_EQUAL(available_coins.bech32.size(), 2U);
+
+ // P2SH-SEGWIT
+ dest = wallet->GetNewDestination(OutputType::P2SH_SEGWIT, "");
+ AddTx(CRecipient{{GetScriptForDestination(*dest)}, 3 * COIN, /*fSubtractFeeFromAmount=*/true});
+ available_coins = AvailableCoins(*wallet);
+ BOOST_CHECK_EQUAL(available_coins.P2SH_segwit.size(), 2U);
+
+ // Legacy (P2PKH)
+ dest = wallet->GetNewDestination(OutputType::LEGACY, "");
+ BOOST_ASSERT(dest);
+ AddTx(CRecipient{{GetScriptForDestination(*dest)}, 4 * COIN, /*fSubtractFeeFromAmount=*/true});
+ available_coins = AvailableCoins(*wallet);
+ BOOST_CHECK_EQUAL(available_coins.legacy.size(), 2U);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+} // namespace wallet
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index a418105ee1..a4a7216436 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -67,16 +67,14 @@ static void add_coin(const CAmount& nValue, int nInput, CoinSet& set, CAmount fe
set.insert(coin);
}
-static void add_coin(std::vector<COutput>& coins, CWallet& wallet, const CAmount& nValue, CFeeRate feerate = CFeeRate(0), int nAge = 6*24, bool fIsFromMe = false, int nInput=0, bool spendable = false)
+static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmount& nValue, CFeeRate feerate = CFeeRate(0), int nAge = 6*24, bool fIsFromMe = false, int nInput =0, bool spendable = false)
{
CMutableTransaction tx;
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
tx.vout.resize(nInput + 1);
tx.vout[nInput].nValue = nValue;
if (spendable) {
- auto op_dest = wallet.GetNewDestination(OutputType::BECH32, "");
- assert(op_dest.HasRes());
- tx.vout[nInput].scriptPubKey = GetScriptForDestination(op_dest.GetObj());
+ tx.vout[nInput].scriptPubKey = GetScriptForDestination(*Assert(wallet.GetNewDestination(OutputType::BECH32, "")));
}
uint256 txid = tx.GetHash();
@@ -85,7 +83,7 @@ static void add_coin(std::vector<COutput>& coins, CWallet& wallet, const CAmount
assert(ret.second);
CWalletTx& wtx = (*ret.first).second;
const auto& txout = wtx.tx->vout.at(nInput);
- coins.emplace_back(COutPoint(wtx.GetHash(), nInput), txout, nAge, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, wtx.GetTxTime(), fIsFromMe, feerate);
+ available_coins.bech32.emplace_back(COutPoint(wtx.GetHash(), nInput), txout, nAge, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, wtx.GetTxTime(), fIsFromMe, feerate);
}
/** Check if SelectionResult a is equivalent to SelectionResult b.
@@ -129,18 +127,18 @@ static CAmount make_hard_case(int utxos, std::vector<COutput>& utxo_pool)
return target;
}
-inline std::vector<OutputGroup>& GroupCoins(const std::vector<COutput>& coins)
+inline std::vector<OutputGroup>& GroupCoins(const std::vector<COutput>& available_coins)
{
static std::vector<OutputGroup> static_groups;
static_groups.clear();
- for (auto& coin : coins) {
+ for (auto& coin : available_coins) {
static_groups.emplace_back();
static_groups.back().Insert(coin, /*ancestors=*/ 0, /*descendants=*/ 0, /*positive_only=*/ false);
}
return static_groups;
}
-inline std::vector<OutputGroup>& KnapsackGroupOutputs(const std::vector<COutput>& coins, CWallet& wallet, const CoinEligibilityFilter& filter)
+inline std::vector<OutputGroup>& KnapsackGroupOutputs(const std::vector<COutput>& available_coins, CWallet& wallet, const CoinEligibilityFilter& filter)
{
FastRandomContext rand{};
CoinSelectionParams coin_selection_params{
@@ -155,7 +153,7 @@ inline std::vector<OutputGroup>& KnapsackGroupOutputs(const std::vector<COutput>
/*avoid_partial=*/ false,
};
static std::vector<OutputGroup> static_groups;
- static_groups = GroupOutputs(wallet, coins, coin_selection_params, filter, /*positive_only=*/false);
+ static_groups = GroupOutputs(wallet, available_coins, coin_selection_params, filter, /*positive_only=*/false);
return static_groups;
}
@@ -307,18 +305,18 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet->SetupDescriptorScriptPubKeyMans();
- std::vector<COutput> coins;
+ CoinsResult available_coins;
- add_coin(coins, *wallet, 1, coin_selection_params_bnb.m_effective_feerate);
- coins.at(0).input_bytes = 40; // Make sure that it has a negative effective value. The next check should assert if this somehow got through. Otherwise it will fail
- BOOST_CHECK(!SelectCoinsBnB(GroupCoins(coins), 1 * CENT, coin_selection_params_bnb.m_cost_of_change));
+ add_coin(available_coins, *wallet, 1, coin_selection_params_bnb.m_effective_feerate);
+ available_coins.all().at(0).input_bytes = 40; // Make sure that it has a negative effective value. The next check should assert if this somehow got through. Otherwise it will fail
+ BOOST_CHECK(!SelectCoinsBnB(GroupCoins(available_coins.all()), 1 * CENT, coin_selection_params_bnb.m_cost_of_change));
// Test fees subtracted from output:
- coins.clear();
- add_coin(coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate);
- coins.at(0).input_bytes = 40;
+ available_coins.clear();
+ add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate);
+ available_coins.all().at(0).input_bytes = 40;
coin_selection_params_bnb.m_subtract_fee_outputs = true;
- const auto result9 = SelectCoinsBnB(GroupCoins(coins), 1 * CENT, coin_selection_params_bnb.m_cost_of_change);
+ const auto result9 = SelectCoinsBnB(GroupCoins(available_coins.all()), 1 * CENT, coin_selection_params_bnb.m_cost_of_change);
BOOST_CHECK(result9);
BOOST_CHECK_EQUAL(result9->GetSelectedValue(), 1 * CENT);
}
@@ -330,16 +328,16 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet->SetupDescriptorScriptPubKeyMans();
- std::vector<COutput> coins;
+ CoinsResult available_coins;
- add_coin(coins, *wallet, 5 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(coins, *wallet, 3 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(coins, *wallet, 2 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 5 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 3 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 2 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
CCoinControl coin_control;
coin_control.m_allow_other_inputs = true;
- coin_control.Select(coins.at(0).outpoint);
+ coin_control.Select(available_coins.all().at(0).outpoint);
coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
- const auto result10 = SelectCoins(*wallet, coins, 10 * CENT, coin_control, coin_selection_params_bnb);
+ const auto result10 = SelectCoins(*wallet, available_coins, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(result10);
}
{
@@ -349,52 +347,52 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet->SetupDescriptorScriptPubKeyMans();
- std::vector<COutput> coins;
+ CoinsResult available_coins;
// single coin should be selected when effective fee > long term fee
coin_selection_params_bnb.m_effective_feerate = CFeeRate(5000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(3000);
- add_coin(coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
add_coin(10 * CENT, 2, expected_result);
CCoinControl coin_control;
- const auto result11 = SelectCoins(*wallet, coins, 10 * CENT, coin_control, coin_selection_params_bnb);
+ const auto result11 = SelectCoins(*wallet, available_coins, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result11));
- coins.clear();
+ available_coins.clear();
// more coins should be selected when effective fee < long term fee
coin_selection_params_bnb.m_effective_feerate = CFeeRate(3000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(5000);
- add_coin(coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
add_coin(9 * CENT, 2, expected_result);
add_coin(1 * CENT, 2, expected_result);
- const auto result12 = SelectCoins(*wallet, coins, 10 * CENT, coin_control, coin_selection_params_bnb);
+ const auto result12 = SelectCoins(*wallet, available_coins, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result12));
- coins.clear();
+ available_coins.clear();
// pre selected coin should be selected even if disadvantageous
coin_selection_params_bnb.m_effective_feerate = CFeeRate(5000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(3000);
- add_coin(coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
add_coin(9 * CENT, 2, expected_result);
add_coin(1 * CENT, 2, expected_result);
coin_control.m_allow_other_inputs = true;
- coin_control.Select(coins.at(1).outpoint); // pre select 9 coin
- const auto result13 = SelectCoins(*wallet, coins, 10 * CENT, coin_control, coin_selection_params_bnb);
+ coin_control.Select(available_coins.all().at(1).outpoint); // pre select 9 coin
+ const auto result13 = SelectCoins(*wallet, available_coins, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result13));
}
}
@@ -410,175 +408,175 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet->SetupDescriptorScriptPubKeyMans();
- std::vector<COutput> coins;
+ CoinsResult available_coins;
// test multiple times to allow for differences in the shuffle order
for (int i = 0; i < RUN_TESTS; i++)
{
- coins.clear();
+ available_coins.clear();
// with an empty wallet we can't even pay one cent
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_standard), 1 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_standard), 1 * CENT, CENT));
- add_coin(coins, *wallet, 1*CENT, CFeeRate(0), 4); // add a new 1 cent coin
+ add_coin(available_coins, *wallet, 1*CENT, CFeeRate(0), 4); // add a new 1 cent coin
// with a new 1 cent coin, we still can't find a mature 1 cent
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_standard), 1 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_standard), 1 * CENT, CENT));
// but we can find a new 1 cent
- const auto result1 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 1 * CENT, CENT);
+ const auto result1 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 1 * CENT, CENT);
BOOST_CHECK(result1);
BOOST_CHECK_EQUAL(result1->GetSelectedValue(), 1 * CENT);
- add_coin(coins, *wallet, 2*CENT); // add a mature 2 cent coin
+ add_coin(available_coins, *wallet, 2*CENT); // add a mature 2 cent coin
// we can't make 3 cents of mature coins
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_standard), 3 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_standard), 3 * CENT, CENT));
// we can make 3 cents of new coins
- const auto result2 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 3 * CENT, CENT);
+ const auto result2 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 3 * CENT, CENT);
BOOST_CHECK(result2);
BOOST_CHECK_EQUAL(result2->GetSelectedValue(), 3 * CENT);
- add_coin(coins, *wallet, 5*CENT); // add a mature 5 cent coin,
- add_coin(coins, *wallet, 10*CENT, CFeeRate(0), 3, true); // a new 10 cent coin sent from one of our own addresses
- add_coin(coins, *wallet, 20*CENT); // and a mature 20 cent coin
+ add_coin(available_coins, *wallet, 5*CENT); // add a mature 5 cent coin,
+ add_coin(available_coins, *wallet, 10*CENT, CFeeRate(0), 3, true); // a new 10 cent coin sent from one of our own addresses
+ add_coin(available_coins, *wallet, 20*CENT); // and a mature 20 cent coin
// now we have new: 1+10=11 (of which 10 was self-sent), and mature: 2+5+20=27. total = 38
// we can't make 38 cents only if we disallow new coins:
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_standard), 38 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_standard), 38 * CENT, CENT));
// we can't even make 37 cents if we don't allow new coins even if they're from us
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_standard_extra), 38 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_standard_extra), 38 * CENT, CENT));
// but we can make 37 cents if we accept new coins from ourself
- const auto result3 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_standard), 37 * CENT, CENT);
+ const auto result3 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_standard), 37 * CENT, CENT);
BOOST_CHECK(result3);
BOOST_CHECK_EQUAL(result3->GetSelectedValue(), 37 * CENT);
// and we can make 38 cents if we accept all new coins
- const auto result4 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 38 * CENT, CENT);
+ const auto result4 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 38 * CENT, CENT);
BOOST_CHECK(result4);
BOOST_CHECK_EQUAL(result4->GetSelectedValue(), 38 * CENT);
// try making 34 cents from 1,2,5,10,20 - we can't do it exactly
- const auto result5 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 34 * CENT, CENT);
+ const auto result5 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 34 * CENT, CENT);
BOOST_CHECK(result5);
BOOST_CHECK_EQUAL(result5->GetSelectedValue(), 35 * CENT); // but 35 cents is closest
BOOST_CHECK_EQUAL(result5->GetInputSet().size(), 3U); // the best should be 20+10+5. it's incredibly unlikely the 1 or 2 got included (but possible)
// when we try making 7 cents, the smaller coins (1,2,5) are enough. We should see just 2+5
- const auto result6 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 7 * CENT, CENT);
+ const auto result6 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 7 * CENT, CENT);
BOOST_CHECK(result6);
BOOST_CHECK_EQUAL(result6->GetSelectedValue(), 7 * CENT);
BOOST_CHECK_EQUAL(result6->GetInputSet().size(), 2U);
// when we try making 8 cents, the smaller coins (1,2,5) are exactly enough.
- const auto result7 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 8 * CENT, CENT);
+ const auto result7 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 8 * CENT, CENT);
BOOST_CHECK(result7);
BOOST_CHECK(result7->GetSelectedValue() == 8 * CENT);
BOOST_CHECK_EQUAL(result7->GetInputSet().size(), 3U);
// when we try making 9 cents, no subset of smaller coins is enough, and we get the next bigger coin (10)
- const auto result8 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 9 * CENT, CENT);
+ const auto result8 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 9 * CENT, CENT);
BOOST_CHECK(result8);
BOOST_CHECK_EQUAL(result8->GetSelectedValue(), 10 * CENT);
BOOST_CHECK_EQUAL(result8->GetInputSet().size(), 1U);
// now clear out the wallet and start again to test choosing between subsets of smaller coins and the next biggest coin
- coins.clear();
+ available_coins.clear();
- add_coin(coins, *wallet, 6*CENT);
- add_coin(coins, *wallet, 7*CENT);
- add_coin(coins, *wallet, 8*CENT);
- add_coin(coins, *wallet, 20*CENT);
- add_coin(coins, *wallet, 30*CENT); // now we have 6+7+8+20+30 = 71 cents total
+ add_coin(available_coins, *wallet, 6*CENT);
+ add_coin(available_coins, *wallet, 7*CENT);
+ add_coin(available_coins, *wallet, 8*CENT);
+ add_coin(available_coins, *wallet, 20*CENT);
+ add_coin(available_coins, *wallet, 30*CENT); // now we have 6+7+8+20+30 = 71 cents total
// check that we have 71 and not 72
- const auto result9 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 71 * CENT, CENT);
+ const auto result9 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 71 * CENT, CENT);
BOOST_CHECK(result9);
- BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 72 * CENT, CENT));
+ BOOST_CHECK(!KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 72 * CENT, CENT));
// now try making 16 cents. the best smaller coins can do is 6+7+8 = 21; not as good at the next biggest coin, 20
- const auto result10 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 16 * CENT, CENT);
+ const auto result10 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 16 * CENT, CENT);
BOOST_CHECK(result10);
BOOST_CHECK_EQUAL(result10->GetSelectedValue(), 20 * CENT); // we should get 20 in one coin
BOOST_CHECK_EQUAL(result10->GetInputSet().size(), 1U);
- add_coin(coins, *wallet, 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
+ add_coin(available_coins, *wallet, 5*CENT); // now we have 5+6+7+8+20+30 = 75 cents total
// now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, better than the next biggest coin, 20
- const auto result11 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 16 * CENT, CENT);
+ const auto result11 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 16 * CENT, CENT);
BOOST_CHECK(result11);
BOOST_CHECK_EQUAL(result11->GetSelectedValue(), 18 * CENT); // we should get 18 in 3 coins
BOOST_CHECK_EQUAL(result11->GetInputSet().size(), 3U);
- add_coin(coins, *wallet, 18*CENT); // now we have 5+6+7+8+18+20+30
+ add_coin(available_coins, *wallet, 18*CENT); // now we have 5+6+7+8+18+20+30
// and now if we try making 16 cents again, the smaller coins can make 5+6+7 = 18 cents, the same as the next biggest coin, 18
- const auto result12 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 16 * CENT, CENT);
+ const auto result12 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 16 * CENT, CENT);
BOOST_CHECK(result12);
BOOST_CHECK_EQUAL(result12->GetSelectedValue(), 18 * CENT); // we should get 18 in 1 coin
BOOST_CHECK_EQUAL(result12->GetInputSet().size(), 1U); // because in the event of a tie, the biggest coin wins
// now try making 11 cents. we should get 5+6
- const auto result13 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 11 * CENT, CENT);
+ const auto result13 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 11 * CENT, CENT);
BOOST_CHECK(result13);
BOOST_CHECK_EQUAL(result13->GetSelectedValue(), 11 * CENT);
BOOST_CHECK_EQUAL(result13->GetInputSet().size(), 2U);
// check that the smallest bigger coin is used
- add_coin(coins, *wallet, 1*COIN);
- add_coin(coins, *wallet, 2*COIN);
- add_coin(coins, *wallet, 3*COIN);
- add_coin(coins, *wallet, 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
- const auto result14 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 95 * CENT, CENT);
+ add_coin(available_coins, *wallet, 1*COIN);
+ add_coin(available_coins, *wallet, 2*COIN);
+ add_coin(available_coins, *wallet, 3*COIN);
+ add_coin(available_coins, *wallet, 4*COIN); // now we have 5+6+7+8+18+20+30+100+200+300+400 = 1094 cents
+ const auto result14 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 95 * CENT, CENT);
BOOST_CHECK(result14);
BOOST_CHECK_EQUAL(result14->GetSelectedValue(), 1 * COIN); // we should get 1 BTC in 1 coin
BOOST_CHECK_EQUAL(result14->GetInputSet().size(), 1U);
- const auto result15 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 195 * CENT, CENT);
+ const auto result15 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 195 * CENT, CENT);
BOOST_CHECK(result15);
BOOST_CHECK_EQUAL(result15->GetSelectedValue(), 2 * COIN); // we should get 2 BTC in 1 coin
BOOST_CHECK_EQUAL(result15->GetInputSet().size(), 1U);
// empty the wallet and start again, now with fractions of a cent, to test small change avoidance
- coins.clear();
- add_coin(coins, *wallet, CENT * 1 / 10);
- add_coin(coins, *wallet, CENT * 2 / 10);
- add_coin(coins, *wallet, CENT * 3 / 10);
- add_coin(coins, *wallet, CENT * 4 / 10);
- add_coin(coins, *wallet, CENT * 5 / 10);
+ available_coins.clear();
+ add_coin(available_coins, *wallet, CENT * 1 / 10);
+ add_coin(available_coins, *wallet, CENT * 2 / 10);
+ add_coin(available_coins, *wallet, CENT * 3 / 10);
+ add_coin(available_coins, *wallet, CENT * 4 / 10);
+ add_coin(available_coins, *wallet, CENT * 5 / 10);
// try making 1 * CENT from the 1.5 * CENT
// we'll get change smaller than CENT whatever happens, so can expect CENT exactly
- const auto result16 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), CENT, CENT);
+ const auto result16 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), CENT, CENT);
BOOST_CHECK(result16);
BOOST_CHECK_EQUAL(result16->GetSelectedValue(), CENT);
// but if we add a bigger coin, small change is avoided
- add_coin(coins, *wallet, 1111*CENT);
+ add_coin(available_coins, *wallet, 1111*CENT);
// try making 1 from 0.1 + 0.2 + 0.3 + 0.4 + 0.5 + 1111 = 1112.5
- const auto result17 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 1 * CENT, CENT);
+ const auto result17 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 1 * CENT, CENT);
BOOST_CHECK(result17);
BOOST_CHECK_EQUAL(result17->GetSelectedValue(), 1 * CENT); // we should get the exact amount
// if we add more small coins:
- add_coin(coins, *wallet, CENT * 6 / 10);
- add_coin(coins, *wallet, CENT * 7 / 10);
+ add_coin(available_coins, *wallet, CENT * 6 / 10);
+ add_coin(available_coins, *wallet, CENT * 7 / 10);
// and try again to make 1.0 * CENT
- const auto result18 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 1 * CENT, CENT);
+ const auto result18 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 1 * CENT, CENT);
BOOST_CHECK(result18);
BOOST_CHECK_EQUAL(result18->GetSelectedValue(), 1 * CENT); // we should get the exact amount
// run the 'mtgox' test (see https://blockexplorer.com/tx/29a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf)
// they tried to consolidate 10 50k coins into one 500k coin, and ended up with 50k in change
- coins.clear();
+ available_coins.clear();
for (int j = 0; j < 20; j++)
- add_coin(coins, *wallet, 50000 * COIN);
+ add_coin(available_coins, *wallet, 50000 * COIN);
- const auto result19 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 500000 * COIN, CENT);
+ const auto result19 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 500000 * COIN, CENT);
BOOST_CHECK(result19);
BOOST_CHECK_EQUAL(result19->GetSelectedValue(), 500000 * COIN); // we should get the exact amount
BOOST_CHECK_EQUAL(result19->GetInputSet().size(), 10U); // in ten coins
@@ -587,41 +585,41 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// we need to try finding an exact subset anyway
// sometimes it will fail, and so we use the next biggest coin:
- coins.clear();
- add_coin(coins, *wallet, CENT * 5 / 10);
- add_coin(coins, *wallet, CENT * 6 / 10);
- add_coin(coins, *wallet, CENT * 7 / 10);
- add_coin(coins, *wallet, 1111 * CENT);
- const auto result20 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 1 * CENT, CENT);
+ available_coins.clear();
+ add_coin(available_coins, *wallet, CENT * 5 / 10);
+ add_coin(available_coins, *wallet, CENT * 6 / 10);
+ add_coin(available_coins, *wallet, CENT * 7 / 10);
+ add_coin(available_coins, *wallet, 1111 * CENT);
+ const auto result20 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 1 * CENT, CENT);
BOOST_CHECK(result20);
BOOST_CHECK_EQUAL(result20->GetSelectedValue(), 1111 * CENT); // we get the bigger coin
BOOST_CHECK_EQUAL(result20->GetInputSet().size(), 1U);
// but sometimes it's possible, and we use an exact subset (0.4 + 0.6 = 1.0)
- coins.clear();
- add_coin(coins, *wallet, CENT * 4 / 10);
- add_coin(coins, *wallet, CENT * 6 / 10);
- add_coin(coins, *wallet, CENT * 8 / 10);
- add_coin(coins, *wallet, 1111 * CENT);
- const auto result21 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), CENT, CENT);
+ available_coins.clear();
+ add_coin(available_coins, *wallet, CENT * 4 / 10);
+ add_coin(available_coins, *wallet, CENT * 6 / 10);
+ add_coin(available_coins, *wallet, CENT * 8 / 10);
+ add_coin(available_coins, *wallet, 1111 * CENT);
+ const auto result21 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), CENT, CENT);
BOOST_CHECK(result21);
BOOST_CHECK_EQUAL(result21->GetSelectedValue(), CENT); // we should get the exact amount
BOOST_CHECK_EQUAL(result21->GetInputSet().size(), 2U); // in two coins 0.4+0.6
// test avoiding small change
- coins.clear();
- add_coin(coins, *wallet, CENT * 5 / 100);
- add_coin(coins, *wallet, CENT * 1);
- add_coin(coins, *wallet, CENT * 100);
+ available_coins.clear();
+ add_coin(available_coins, *wallet, CENT * 5 / 100);
+ add_coin(available_coins, *wallet, CENT * 1);
+ add_coin(available_coins, *wallet, CENT * 100);
// trying to make 100.01 from these three coins
- const auto result22 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), CENT * 10001 / 100, CENT);
+ const auto result22 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), CENT * 10001 / 100, CENT);
BOOST_CHECK(result22);
BOOST_CHECK_EQUAL(result22->GetSelectedValue(), CENT * 10105 / 100); // we should get all coins
BOOST_CHECK_EQUAL(result22->GetInputSet().size(), 3U);
// but if we try to make 99.9, we should take the bigger of the two small coins to avoid small change
- const auto result23 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), CENT * 9990 / 100, CENT);
+ const auto result23 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), CENT * 9990 / 100, CENT);
BOOST_CHECK(result23);
BOOST_CHECK_EQUAL(result23->GetSelectedValue(), 101 * CENT);
BOOST_CHECK_EQUAL(result23->GetInputSet().size(), 2U);
@@ -629,14 +627,14 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// test with many inputs
for (CAmount amt=1500; amt < COIN; amt*=10) {
- coins.clear();
+ available_coins.clear();
// Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 bytes per input)
for (uint16_t j = 0; j < 676; j++)
- add_coin(coins, *wallet, amt);
+ add_coin(available_coins, *wallet, amt);
// We only create the wallet once to save time, but we still run the coin selection RUN_TESTS times.
for (int i = 0; i < RUN_TESTS; i++) {
- const auto result24 = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_confirmed), 2000, CENT);
+ const auto result24 = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_confirmed), 2000, CENT);
BOOST_CHECK(result24);
if (amt - 2000 < CENT) {
@@ -655,17 +653,17 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// test randomness
{
- coins.clear();
+ available_coins.clear();
for (int i2 = 0; i2 < 100; i2++)
- add_coin(coins, *wallet, COIN);
+ add_coin(available_coins, *wallet, COIN);
// Again, we only create the wallet once to save time, but we still run the coin selection RUN_TESTS times.
for (int i = 0; i < RUN_TESTS; i++) {
// picking 50 from 100 coins doesn't depend on the shuffle,
// but does depend on randomness in the stochastic approximation code
- const auto result25 = KnapsackSolver(GroupCoins(coins), 50 * COIN, CENT);
+ const auto result25 = KnapsackSolver(GroupCoins(available_coins.all()), 50 * COIN, CENT);
BOOST_CHECK(result25);
- const auto result26 = KnapsackSolver(GroupCoins(coins), 50 * COIN, CENT);
+ const auto result26 = KnapsackSolver(GroupCoins(available_coins.all()), 50 * COIN, CENT);
BOOST_CHECK(result26);
BOOST_CHECK(!EqualResult(*result25, *result26));
@@ -676,9 +674,9 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// When choosing 1 from 100 identical coins, 1% of the time, this test will choose the same coin twice
// which will cause it to fail.
// To avoid that issue, run the test RANDOM_REPEATS times and only complain if all of them fail
- const auto result27 = KnapsackSolver(GroupCoins(coins), COIN, CENT);
+ const auto result27 = KnapsackSolver(GroupCoins(available_coins.all()), COIN, CENT);
BOOST_CHECK(result27);
- const auto result28 = KnapsackSolver(GroupCoins(coins), COIN, CENT);
+ const auto result28 = KnapsackSolver(GroupCoins(available_coins.all()), COIN, CENT);
BOOST_CHECK(result28);
if (EqualResult(*result27, *result28))
fails++;
@@ -689,19 +687,19 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
// add 75 cents in small change. not enough to make 90 cents,
// then try making 90 cents. there are multiple competing "smallest bigger" coins,
// one of which should be picked at random
- add_coin(coins, *wallet, 5 * CENT);
- add_coin(coins, *wallet, 10 * CENT);
- add_coin(coins, *wallet, 15 * CENT);
- add_coin(coins, *wallet, 20 * CENT);
- add_coin(coins, *wallet, 25 * CENT);
+ add_coin(available_coins, *wallet, 5 * CENT);
+ add_coin(available_coins, *wallet, 10 * CENT);
+ add_coin(available_coins, *wallet, 15 * CENT);
+ add_coin(available_coins, *wallet, 20 * CENT);
+ add_coin(available_coins, *wallet, 25 * CENT);
for (int i = 0; i < RUN_TESTS; i++) {
int fails = 0;
for (int j = 0; j < RANDOM_REPEATS; j++)
{
- const auto result29 = KnapsackSolver(GroupCoins(coins), 90 * CENT, CENT);
+ const auto result29 = KnapsackSolver(GroupCoins(available_coins.all()), 90 * CENT, CENT);
BOOST_CHECK(result29);
- const auto result30 = KnapsackSolver(GroupCoins(coins), 90 * CENT, CENT);
+ const auto result30 = KnapsackSolver(GroupCoins(available_coins.all()), 90 * CENT, CENT);
BOOST_CHECK(result30);
if (EqualResult(*result29, *result30))
fails++;
@@ -720,14 +718,14 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet->SetupDescriptorScriptPubKeyMans();
- std::vector<COutput> coins;
+ CoinsResult available_coins;
// Test vValue sort order
for (int i = 0; i < 1000; i++)
- add_coin(coins, *wallet, 1000 * COIN);
- add_coin(coins, *wallet, 3 * COIN);
+ add_coin(available_coins, *wallet, 1000 * COIN);
+ add_coin(available_coins, *wallet, 3 * COIN);
- const auto result = KnapsackSolver(KnapsackGroupOutputs(coins, *wallet, filter_standard), 1003 * COIN, CENT, rand);
+ const auto result = KnapsackSolver(KnapsackGroupOutputs(available_coins.all(), *wallet, filter_standard), 1003 * COIN, CENT, rand);
BOOST_CHECK(result);
BOOST_CHECK_EQUAL(result->GetSelectedValue(), 1003 * COIN);
BOOST_CHECK_EQUAL(result->GetInputSet().size(), 2U);
@@ -750,14 +748,14 @@ BOOST_AUTO_TEST_CASE(SelectCoins_test)
// Run this test 100 times
for (int i = 0; i < 100; ++i)
{
- std::vector<COutput> coins;
+ CoinsResult available_coins;
CAmount balance{0};
// Make a wallet with 1000 exponentially distributed random inputs
for (int j = 0; j < 1000; ++j)
{
CAmount val = distribution(generator)*10000000;
- add_coin(coins, *wallet, val);
+ add_coin(available_coins, *wallet, val);
balance += val;
}
@@ -780,7 +778,7 @@ BOOST_AUTO_TEST_CASE(SelectCoins_test)
/*avoid_partial=*/ false,
};
CCoinControl cc;
- const auto result = SelectCoins(*wallet, coins, target, cc, cs_params);
+ const auto result = SelectCoins(*wallet, available_coins, target, cc, cs_params);
BOOST_CHECK(result);
BOOST_CHECK_GE(result->GetSelectedValue(), target);
}
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
index 816bef6148..5e9cd4001b 100644
--- a/src/wallet/test/fuzz/notifications.cpp
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -69,14 +69,13 @@ struct FuzzedWallet {
CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider)
{
auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)};
- BResult<CTxDestination> op_dest;
+ util::Result<CTxDestination> op_dest{util::Error{}};
if (fuzzed_data_provider.ConsumeBool()) {
op_dest = wallet->GetNewDestination(type, "");
} else {
op_dest = wallet->GetNewChangeDestination(type);
}
- assert(op_dest.HasRes());
- return GetScriptForDestination(op_dest.GetObj());
+ return GetScriptForDestination(*Assert(op_dest));
}
};
@@ -137,8 +136,13 @@ FUZZ_TARGET_INIT(wallet_notifications, initialize_setup)
block.vtx.emplace_back(MakeTransactionRef(tx));
}
// Mine block
- a.wallet->blockConnected(block, chain.size());
- b.wallet->blockConnected(block, chain.size());
+ const uint256& hash = block.GetHash();
+ interfaces::BlockInfo info{hash};
+ info.prev_hash = &block.hashPrevBlock;
+ info.height = chain.size();
+ info.data = &block;
+ a.wallet->blockConnected(info);
+ b.wallet->blockConnected(info);
// Store the coins for the next block
Coins coins_new;
for (const auto& tx : block.vtx) {
@@ -154,8 +158,13 @@ FUZZ_TARGET_INIT(wallet_notifications, initialize_setup)
auto& [coins, block]{chain.back()};
if (block.vtx.empty()) return; // Can only disconnect if the block was submitted first
// Disconnect block
- a.wallet->blockDisconnected(block, chain.size() - 1);
- b.wallet->blockDisconnected(block, chain.size() - 1);
+ const uint256& hash = block.GetHash();
+ interfaces::BlockInfo info{hash};
+ info.prev_hash = &block.hashPrevBlock;
+ info.height = chain.size() - 1;
+ info.data = &block;
+ a.wallet->blockDisconnected(info);
+ b.wallet->blockDisconnected(info);
chain.pop_back();
});
auto& [coins, first_block]{chain.front()};
diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp
index 53c3b5d2ae..dc935a1a04 100644
--- a/src/wallet/test/spend_tests.cpp
+++ b/src/wallet/test/spend_tests.cpp
@@ -35,7 +35,7 @@ BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
coin_control.m_change_type = OutputType::LEGACY;
auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, coin_control);
BOOST_CHECK(res);
- const auto& txr = res.GetObj();
+ const auto& txr = *res;
BOOST_CHECK_EQUAL(txr.tx->vout.size(), 1);
BOOST_CHECK_EQUAL(txr.tx->vout[0].nValue, recipient.nAmount + leftover_input_amount - txr.fee);
BOOST_CHECK_GT(txr.fee, 0);
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 81c01e5023..093f510945 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -53,9 +53,6 @@ static const std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
auto database = MakeWalletDatabase("", options, status, error);
auto wallet = CWallet::Create(context, "", std::move(database), options.create_flags, error, warnings);
NotifyWalletLoaded(context, wallet);
- if (context.chain) {
- wallet->postInitProcess();
- }
return wallet;
}
@@ -363,13 +360,13 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
// Call GetImmatureCredit() once before adding the key to the wallet to
// cache the current immature credit amount, which is 0.
- BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 0);
+ BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx, ISMINE_SPENDABLE), 0);
// Invalidate the cached value, add the key, and make sure a new immature
// credit amount is calculated.
wtx.MarkDirty();
AddKey(wallet, coinbaseKey);
- BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 50*COIN);
+ BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx, ISMINE_SPENDABLE), 50*COIN);
}
static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
@@ -539,7 +536,7 @@ public:
constexpr int RANDOM_CHANGE_POSITION = -1;
auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, dummy);
BOOST_CHECK(res);
- tx = res.GetObj().tx;
+ tx = res->tx;
}
wallet->CommitTransaction(tx, {}, {});
CMutableTransaction blocktx;
@@ -594,7 +591,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
// Lock both coins. Confirm number of available coins drops to 0.
{
LOCK(wallet->cs_wallet);
- BOOST_CHECK_EQUAL(AvailableCoinsListUnspent(*wallet).coins.size(), 2U);
+ BOOST_CHECK_EQUAL(AvailableCoinsListUnspent(*wallet).size(), 2U);
}
for (const auto& group : list) {
for (const auto& coin : group.second) {
@@ -604,7 +601,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
}
{
LOCK(wallet->cs_wallet);
- BOOST_CHECK_EQUAL(AvailableCoinsListUnspent(*wallet).coins.size(), 0U);
+ BOOST_CHECK_EQUAL(AvailableCoinsListUnspent(*wallet).size(), 0U);
}
// Confirm ListCoins still returns same result as before, despite coins
// being locked.
@@ -768,6 +765,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
// being blocked
wallet = TestLoadWallet(context);
BOOST_CHECK(rescan_completed);
+ // AddToWallet events for block_tx and mempool_tx
BOOST_CHECK_EQUAL(addtx_count, 2);
{
LOCK(wallet->cs_wallet);
@@ -780,6 +778,8 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
// transactionAddedToMempool events are processed
promise.set_value();
SyncWithValidationInterfaceQueue();
+ // AddToWallet events for block_tx and mempool_tx events are counted a
+ // second time as the notification queue is processed
BOOST_CHECK_EQUAL(addtx_count, 4);
@@ -803,7 +803,7 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
SyncWithValidationInterfaceQueue();
});
wallet = TestLoadWallet(context);
- BOOST_CHECK_EQUAL(addtx_count, 4);
+ BOOST_CHECK_EQUAL(addtx_count, 2);
{
LOCK(wallet->cs_wallet);
BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_tx.GetHash()), 1U);
@@ -843,21 +843,126 @@ BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup)
{
auto block_hash = block_tx.GetHash();
- auto prev_hash = m_coinbase_txns[0]->GetHash();
+ auto prev_tx = m_coinbase_txns[0];
LOCK(wallet->cs_wallet);
- BOOST_CHECK(wallet->HasWalletSpend(prev_hash));
+ BOOST_CHECK(wallet->HasWalletSpend(prev_tx));
BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 1u);
std::vector<uint256> vHashIn{ block_hash }, vHashOut;
BOOST_CHECK_EQUAL(wallet->ZapSelectTx(vHashIn, vHashOut), DBErrors::LOAD_OK);
- BOOST_CHECK(!wallet->HasWalletSpend(prev_hash));
+ BOOST_CHECK(!wallet->HasWalletSpend(prev_tx));
BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 0u);
}
TestUnloadWallet(std::move(wallet));
}
+/** RAII class that provides access to a FailDatabase. Which fails if needed. */
+class FailBatch : public DatabaseBatch
+{
+private:
+ bool m_pass{true};
+ bool ReadKey(CDataStream&& key, CDataStream& value) override { return m_pass; }
+ bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite=true) override { return m_pass; }
+ bool EraseKey(CDataStream&& key) override { return m_pass; }
+ bool HasKey(CDataStream&& key) override { return m_pass; }
+
+public:
+ explicit FailBatch(bool pass) : m_pass(pass) {}
+ void Flush() override {}
+ void Close() override {}
+
+ bool StartCursor() override { return true; }
+ bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) override { return false; }
+ void CloseCursor() override {}
+ bool TxnBegin() override { return false; }
+ bool TxnCommit() override { return false; }
+ bool TxnAbort() override { return false; }
+};
+
+/** A dummy WalletDatabase that does nothing, only fails if needed.**/
+class FailDatabase : public WalletDatabase
+{
+public:
+ bool m_pass{true}; // false when this db should fail
+
+ void Open() override {};
+ void AddRef() override {}
+ void RemoveRef() override {}
+ bool Rewrite(const char* pszSkip=nullptr) override { return true; }
+ bool Backup(const std::string& strDest) const override { return true; }
+ void Close() override {}
+ void Flush() override {}
+ bool PeriodicFlush() override { return true; }
+ void IncrementUpdateCounter() override { ++nUpdateCounter; }
+ void ReloadDbEnv() override {}
+ std::string Filename() override { return "faildb"; }
+ std::string Format() override { return "faildb"; }
+ std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return std::make_unique<FailBatch>(m_pass); }
+};
+
+/**
+ * Checks a wallet invalid state where the inputs (prev-txs) of a new arriving transaction are not marked dirty,
+ * while the transaction that spends them exist inside the in-memory wallet tx map (not stored on db due a db write failure).
+ */
+BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
+{
+ CWallet wallet(m_node.chain.get(), "", m_args, std::make_unique<FailDatabase>());
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet.SetupDescriptorScriptPubKeyMans();
+ }
+
+ // Add tx to wallet
+ const auto& op_dest = wallet.GetNewDestination(OutputType::BECH32M, "");
+ BOOST_ASSERT(op_dest);
+
+ CMutableTransaction mtx;
+ mtx.vout.push_back({COIN, GetScriptForDestination(*op_dest)});
+ mtx.vin.push_back(CTxIn(g_insecure_rand_ctx.rand256(), 0));
+ const auto& tx_id_to_spend = wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInMempool{})->GetHash();
+
+ {
+ // Cache and verify available balance for the wtx
+ LOCK(wallet.cs_wallet);
+ const CWalletTx* wtx_to_spend = wallet.GetWalletTx(tx_id_to_spend);
+ BOOST_CHECK_EQUAL(CachedTxGetAvailableCredit(wallet, *wtx_to_spend), 1 * COIN);
+ }
+
+ // Now the good case:
+ // 1) Add a transaction that spends the previously created transaction
+ // 2) Verify that the available balance of this new tx and the old one is updated (prev tx is marked dirty)
+
+ mtx.vin.clear();
+ mtx.vin.push_back(CTxIn(tx_id_to_spend, 0));
+ wallet.transactionAddedToMempool(MakeTransactionRef(mtx), 0);
+ const uint256& good_tx_id = mtx.GetHash();
+
+ {
+ // Verify balance update for the new tx and the old one
+ LOCK(wallet.cs_wallet);
+ const CWalletTx* new_wtx = wallet.GetWalletTx(good_tx_id);
+ BOOST_CHECK_EQUAL(CachedTxGetAvailableCredit(wallet, *new_wtx), 1 * COIN);
+
+ // Now the old wtx
+ const CWalletTx* wtx_to_spend = wallet.GetWalletTx(tx_id_to_spend);
+ BOOST_CHECK_EQUAL(CachedTxGetAvailableCredit(wallet, *wtx_to_spend), 0 * COIN);
+ }
+
+ // Now the bad case:
+ // 1) Make db always fail
+ // 2) Try to add a transaction that spends the previously created transaction and
+ // verify that we are not moving forward if the wallet cannot store it
+ static_cast<FailDatabase&>(wallet.GetDatabase()).m_pass = false;
+ mtx.vin.clear();
+ mtx.vin.push_back(CTxIn(good_tx_id, 0));
+ BOOST_CHECK_EXCEPTION(wallet.transactionAddedToMempool(MakeTransactionRef(mtx), 0),
+ std::runtime_error,
+ HasReason("DB error adding transaction to wallet, write failed"));
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace wallet
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 18ca630312..e0a794dbe6 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -414,7 +414,7 @@ std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& b
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
{
AssertLockHeld(cs_wallet);
- std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
+ const auto it = mapWallet.find(hash);
if (it == mapWallet.end())
return nullptr;
return &(it->second);
@@ -551,7 +551,7 @@ std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
std::set<uint256> result;
AssertLockHeld(cs_wallet);
- std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);
+ const auto it = mapWallet.find(txid);
if (it == mapWallet.end())
return result;
const CWalletTx& wtx = it->second;
@@ -569,11 +569,17 @@ std::set<uint256> CWallet::GetConflicts(const uint256& txid) const
return result;
}
-bool CWallet::HasWalletSpend(const uint256& txid) const
+bool CWallet::HasWalletSpend(const CTransactionRef& tx) const
{
AssertLockHeld(cs_wallet);
- auto iter = mapTxSpends.lower_bound(COutPoint(txid, 0));
- return (iter != mapTxSpends.end() && iter->first.hash == txid);
+ const uint256& txid = tx->GetHash();
+ for (unsigned int i = 0; i < tx->vout.size(); ++i) {
+ auto iter = mapTxSpends.find(COutPoint(txid, i));
+ if (iter != mapTxSpends.end()) {
+ return true;
+ }
+ }
+ return false;
}
void CWallet::Flush()
@@ -636,7 +642,7 @@ bool CWallet::IsSpent(const COutPoint& outpoint) const
for (TxSpends::const_iterator it = range.first; it != range.second; ++it) {
const uint256& wtxid = it->second;
- std::map<uint256, CWalletTx>::const_iterator mit = mapWallet.find(wtxid);
+ const auto mit = mapWallet.find(wtxid);
if (mit != mapWallet.end()) {
int depth = GetTxDepthInMainChain(mit->second);
if (depth > 0 || (depth == 0 && !mit->second.isAbandoned()))
@@ -1130,7 +1136,13 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const SyncTxS
// Block disconnection override an abandoned tx as unconfirmed
// which means user may have to call abandontransaction again
TxState tx_state = std::visit([](auto&& s) -> TxState { return s; }, state);
- return AddToWallet(MakeTransactionRef(tx), tx_state, /*update_wtx=*/nullptr, /*fFlushOnClose=*/false, rescanning_old_block);
+ CWalletTx* wtx = AddToWallet(MakeTransactionRef(tx), tx_state, /*update_wtx=*/nullptr, /*fFlushOnClose=*/false, rescanning_old_block);
+ if (!wtx) {
+ // Can only be nullptr if there was a db write error (missing db, read-only db or a db engine internal writing error).
+ // As we only store arriving transaction in this process, and we don't want an inconsistent state, let's throw an error.
+ throw std::runtime_error("DB error adding transaction to wallet, write failed");
+ }
+ return true;
}
}
return false;
@@ -1191,12 +1203,13 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
batch.WriteTx(wtx);
NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
- TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
- while (iter != mapTxSpends.end() && iter->first.hash == now) {
- if (!done.count(iter->second)) {
- todo.insert(iter->second);
+ for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
+ std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(now, i));
+ for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
+ if (!done.count(iter->second)) {
+ todo.insert(iter->second);
+ }
}
- iter++;
}
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be recomputed
@@ -1242,12 +1255,13 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
wtx.MarkDirty();
batch.WriteTx(wtx);
// Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
- TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
- while (iter != mapTxSpends.end() && iter->first.hash == now) {
- if (!done.count(iter->second)) {
- todo.insert(iter->second);
- }
- iter++;
+ for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
+ std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(COutPoint(now, i));
+ for (TxSpends::const_iterator iter = range.first; iter != range.second; ++iter) {
+ if (!done.count(iter->second)) {
+ todo.insert(iter->second);
+ }
+ }
}
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be recomputed
@@ -1314,30 +1328,31 @@ void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRe
}
}
-void CWallet::blockConnected(const CBlock& block, int height)
+void CWallet::blockConnected(const interfaces::BlockInfo& block)
{
- const uint256& block_hash = block.GetHash();
+ assert(block.data);
LOCK(cs_wallet);
- m_last_block_processed_height = height;
- m_last_block_processed = block_hash;
- for (size_t index = 0; index < block.vtx.size(); index++) {
- SyncTransaction(block.vtx[index], TxStateConfirmed{block_hash, height, static_cast<int>(index)});
- transactionRemovedFromMempool(block.vtx[index], MemPoolRemovalReason::BLOCK, 0 /* mempool_sequence */);
+ m_last_block_processed_height = block.height;
+ m_last_block_processed = block.hash;
+ for (size_t index = 0; index < block.data->vtx.size(); index++) {
+ SyncTransaction(block.data->vtx[index], TxStateConfirmed{block.hash, block.height, static_cast<int>(index)});
+ transactionRemovedFromMempool(block.data->vtx[index], MemPoolRemovalReason::BLOCK, 0 /* mempool_sequence */);
}
}
-void CWallet::blockDisconnected(const CBlock& block, int height)
+void CWallet::blockDisconnected(const interfaces::BlockInfo& block)
{
+ assert(block.data);
LOCK(cs_wallet);
// At block disconnection, this will change an abandoned transaction to
// be unconfirmed, whether or not the transaction is added back to the mempool.
// User may have to call abandontransaction again. It may be addressed in the
// future with a stickier abandoned state or even removing abandontransaction call.
- m_last_block_processed_height = height - 1;
- m_last_block_processed = block.hashPrevBlock;
- for (const CTransactionRef& ptx : block.vtx) {
+ m_last_block_processed_height = block.height - 1;
+ m_last_block_processed = *Assert(block.prev_hash);
+ for (const CTransactionRef& ptx : Assert(block.data)->vtx) {
SyncTransaction(ptx, TxStateInactive{});
}
}
@@ -1363,7 +1378,7 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
{
{
LOCK(cs_wallet);
- std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
+ const auto mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
@@ -1678,7 +1693,8 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
/**
* Scan the block chain (starting in start_block) for transactions
* from or to us. If fUpdate is true, found transactions that already
- * exist in the wallet will be updated.
+ * exist in the wallet will be updated. If max_height is not set, the
+ * mempool will be scanned as well.
*
* @param[in] start_block Scan starting block. If block is not on the active
* chain, the scan will return SUCCESS immediately.
@@ -1799,6 +1815,10 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
}
}
}
+ if (!max_height) {
+ WalletLogPrintf("Scanning current mempool transactions.\n");
+ WITH_LOCK(cs_wallet, chain().requestMempoolTransactions(*this));
+ }
ShowProgress(strprintf("%s " + _("Rescanning…").translated, GetDisplayName()), 100); // hide progress dialog in GUI
if (block_height && fAbortRescan) {
WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", block_height, progress_current);
@@ -1947,7 +1967,7 @@ bool CWallet::SignTransaction(CMutableTransaction& tx) const
// Build coins map
std::map<COutPoint, Coin> coins;
for (auto& input : tx.vin) {
- std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(input.prevout.hash);
+ const auto mi = mapWallet.find(input.prevout.hash);
if(mi == mapWallet.end() || input.prevout.n >= mi->second.tx->vout.size()) {
return false;
}
@@ -1979,7 +1999,6 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp
if (n_signed) {
*n_signed = 0;
}
- const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
LOCK(cs_wallet);
// Get all of the previous transactions
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
@@ -2003,6 +2022,8 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp
}
}
+ const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
+
// Fill in information from ScriptPubKeyMans
for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
int n_signed_this_spkm = 0;
@@ -2317,36 +2338,32 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
return res;
}
-BResult<CTxDestination> CWallet::GetNewDestination(const OutputType type, const std::string label)
+util::Result<CTxDestination> CWallet::GetNewDestination(const OutputType type, const std::string label)
{
LOCK(cs_wallet);
auto spk_man = GetScriptPubKeyMan(type, false /* internal */);
if (!spk_man) {
- return strprintf(_("Error: No %s addresses available."), FormatOutputType(type));
+ return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))};
}
spk_man->TopUp();
auto op_dest = spk_man->GetNewDestination(type);
if (op_dest) {
- SetAddressBook(op_dest.GetObj(), label, "receive");
+ SetAddressBook(*op_dest, label, "receive");
}
return op_dest;
}
-BResult<CTxDestination> CWallet::GetNewChangeDestination(const OutputType type)
+util::Result<CTxDestination> CWallet::GetNewChangeDestination(const OutputType type)
{
LOCK(cs_wallet);
- CTxDestination dest;
- bilingual_str error;
ReserveDestination reservedest(this, type);
- if (!reservedest.GetReservedDestination(dest, true, error)) {
- return error;
- }
+ auto op_dest = reservedest.GetReservedDestination(true);
+ if (op_dest) reservedest.KeepDestination();
- reservedest.KeepDestination();
- return dest;
+ return op_dest;
}
std::optional<int64_t> CWallet::GetOldestKeyPoolTime() const
@@ -2416,27 +2433,24 @@ std::set<std::string> CWallet::ListAddrBookLabels(const std::string& purpose) co
return label_set;
}
-bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool internal, bilingual_str& error)
+util::Result<CTxDestination> ReserveDestination::GetReservedDestination(bool internal)
{
m_spk_man = pwallet->GetScriptPubKeyMan(type, internal);
if (!m_spk_man) {
- error = strprintf(_("Error: No %s addresses available."), FormatOutputType(type));
- return false;
+ return util::Error{strprintf(_("Error: No %s addresses available."), FormatOutputType(type))};
}
-
if (nIndex == -1)
{
m_spk_man->TopUp();
CKeyPool keypool;
- if (!m_spk_man->GetReservedDestination(type, internal, address, nIndex, keypool, error)) {
- return false;
- }
+ auto op_address = m_spk_man->GetReservedDestination(type, internal, nIndex, keypool);
+ if (!op_address) return op_address;
+ address = *op_address;
fInternal = keypool.fInternal;
}
- dest = address;
- return true;
+ return address;
}
void ReserveDestination::KeepDestination()
@@ -3044,20 +3058,31 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf
if (tip_height && *tip_height != rescan_height)
{
- if (chain.havePruned()) {
+ // Technically we could execute the code below in any case, but performing the
+ // `while` loop below can make startup very slow, so only check blocks on disk
+ // if necessary.
+ if (chain.havePruned() || chain.hasAssumedValidChain()) {
int block_height = *tip_height;
while (block_height > 0 && chain.haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
--block_height;
}
if (rescan_height != block_height) {
- // We can't rescan beyond non-pruned blocks, stop and throw an error.
+ // We can't rescan beyond blocks we don't have data for, stop and throw an error.
// This might happen if a user uses an old wallet within a pruned node
// or if they ran -disablewallet for a longer time, then decided to re-enable
// Exit early and print an error.
+ // It also may happen if an assumed-valid chain is in use and therefore not
+ // all block data is available.
// If a block is pruned after this check, we will load the wallet,
// but fail the rescan with a generic error.
- error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");
+
+ error = chain.hasAssumedValidChain() ?
+ _(
+ "Assumed-valid: last wallet synchronisation goes beyond "
+ "available block data. You need to wait for the background "
+ "validation chain to download more blocks.") :
+ _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");
return false;
}
}
@@ -3464,7 +3489,7 @@ void CWallet::LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool intern
// Legacy wallets have only one ScriptPubKeyManager and it's active for all output and change types.
Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
- WalletLogPrintf("Setting spkMan to active: id = %s, type = %d, internal = %d\n", id.ToString(), static_cast<int>(type), static_cast<int>(internal));
+ WalletLogPrintf("Setting spkMan to active: id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(type), internal ? "true" : "false");
auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
auto& spk_mans_other = internal ? m_external_spk_managers : m_internal_spk_managers;
auto spk_man = m_spk_managers.at(id).get();
@@ -3482,7 +3507,7 @@ void CWallet::DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool intern
{
auto spk_man = GetScriptPubKeyMan(type, internal);
if (spk_man != nullptr && spk_man->GetID() == id) {
- WalletLogPrintf("Deactivate spkMan: id = %s, type = %d, internal = %d\n", id.ToString(), static_cast<int>(type), static_cast<int>(internal));
+ WalletLogPrintf("Deactivate spkMan: id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(type), internal ? "true" : "false");
WalletBatch batch(GetDatabase());
if (!batch.EraseActiveScriptPubKeyMan(static_cast<uint8_t>(type), internal)) {
throw std::runtime_error(std::string(__func__) + ": erasing active ScriptPubKeyMan id failed");
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index b08b491ef1..247c172da3 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -14,6 +14,7 @@
#include <policy/feerate.h>
#include <psbt.h>
#include <tinyformat.h>
+#include <util/hasher.h>
#include <util/message.h>
#include <util/result.h>
#include <util/strencodings.h>
@@ -37,6 +38,7 @@
#include <stdint.h>
#include <string>
#include <utility>
+#include <unordered_map>
#include <vector>
#include <boost/signals2/signal.hpp>
@@ -99,7 +101,7 @@ static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS{true};
//! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
//! -walletrbf default
-static const bool DEFAULT_WALLET_RBF = false;
+static const bool DEFAULT_WALLET_RBF = true;
static const bool DEFAULT_WALLETBROADCAST = true;
static const bool DEFAULT_DISABLE_WALLET = false;
static const bool DEFAULT_WALLETCROSSCHAIN = false;
@@ -189,7 +191,7 @@ public:
}
//! Reserve an address
- bool GetReservedDestination(CTxDestination& pubkey, bool internal, bilingual_str& error);
+ util::Result<CTxDestination> GetReservedDestination(bool internal);
//! Return reserved address
void ReturnDestination();
//! Keep the address. Do not return it's key to the keypool when this object goes out of scope
@@ -259,7 +261,7 @@ private:
* detect and report conflicts (double-spends or
* mutated transactions where the mutant gets mined).
*/
- typedef std::multimap<COutPoint, uint256> TxSpends;
+ typedef std::unordered_multimap<COutPoint, uint256, SaltedOutpointHasher> TxSpends;
TxSpends mapTxSpends GUARDED_BY(cs_wallet);
void AddToSpends(const COutPoint& outpoint, const uint256& wtxid, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void AddToSpends(const CWalletTx& wtx, WalletBatch* batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -390,7 +392,7 @@ public:
/** Map from txid to CWalletTx for all transactions this wallet is
* interested in, including received and sent transactions. */
- std::map<uint256, CWalletTx> mapWallet GUARDED_BY(cs_wallet);
+ std::unordered_map<uint256, CWalletTx, SaltedTxidHasher> mapWallet GUARDED_BY(cs_wallet);
typedef std::multimap<int64_t, CWalletTx*> TxItems;
TxItems wtxOrdered;
@@ -505,11 +507,15 @@ public:
//! @return true if wtx is changed and needs to be saved to disk, otherwise false
using UpdateWalletTxFn = std::function<bool(CWalletTx& wtx, bool new_tx)>;
+ /**
+ * Add the transaction to the wallet, wrapping it up inside a CWalletTx
+ * @return the recently added wtx pointer or nullptr if there was a db write error.
+ */
CWalletTx* AddToWallet(CTransactionRef tx, const TxState& state, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block = false);
bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override;
- void blockConnected(const CBlock& block, int height) override;
- void blockDisconnected(const CBlock& block, int height) override;
+ void blockConnected(const interfaces::BlockInfo& block) override;
+ void blockDisconnected(const interfaces::BlockInfo& block) override;
void updatedBlockTip() override;
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver& reserver, bool update);
@@ -666,8 +672,8 @@ public:
*/
void MarkDestinationsDirty(const std::set<CTxDestination>& destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
- BResult<CTxDestination> GetNewDestination(const OutputType type, const std::string label);
- BResult<CTxDestination> GetNewChangeDestination(const OutputType type);
+ util::Result<CTxDestination> GetNewDestination(const OutputType type, const std::string label);
+ util::Result<CTxDestination> GetNewChangeDestination(const OutputType type);
isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
@@ -708,7 +714,7 @@ public:
std::set<uint256> GetConflicts(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Check if a given transaction has any of its outputs spent by another transaction in the wallet
- bool HasWalletSpend(const uint256& txid) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
+ bool HasWalletSpend(const CTransactionRef& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
//! Flush wallet (bitdb flush)
void Flush();