diff options
Diffstat (limited to 'src')
600 files changed, 9014 insertions, 5565 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 4199f7e89d..417a611181 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,7 +17,7 @@ EXTRA_LIBRARIES = BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/$(MINISKETCH_INCLUDE_DIR_INT) -I$(srcdir)/secp256k1/include -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) -LIBBITCOIN_SERVER=libbitcoin_server.a +LIBBITCOIN_NODE=libbitcoin_node.a LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CONSENSUS=libbitcoin_consensus.a LIBBITCOIN_CLI=libbitcoin_cli.a @@ -46,9 +46,13 @@ if ENABLE_AVX2 LIBBITCOIN_CRYPTO_AVX2 = crypto/libbitcoin_crypto_avx2.a LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_AVX2) endif -if ENABLE_SHANI -LIBBITCOIN_CRYPTO_SHANI = crypto/libbitcoin_crypto_shani.a -LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_SHANI) +if ENABLE_X86_SHANI +LIBBITCOIN_CRYPTO_X86_SHANI = crypto/libbitcoin_crypto_x86_shani.a +LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_X86_SHANI) +endif +if ENABLE_ARM_SHANI +LIBBITCOIN_CRYPTO_ARM_SHANI = crypto/libbitcoin_crypto_arm_shani.a +LIBBITCOIN_CRYPTO += $(LIBBITCOIN_CRYPTO_ARM_SHANI) endif $(LIBSECP256K1): $(wildcard secp256k1/src/*.h) $(wildcard secp256k1/src/*.c) $(wildcard secp256k1/include/*) @@ -61,7 +65,7 @@ EXTRA_LIBRARIES += \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_CONSENSUS) \ - $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_NODE) \ $(LIBBITCOIN_CLI) \ $(LIBBITCOIN_IPC) \ $(LIBBITCOIN_WALLET) \ @@ -240,6 +244,7 @@ BITCOIN_CORE_H = \ util/check.h \ util/epochguard.h \ util/error.h \ + util/fastrange.h \ util/fees.h \ util/getuniquepath.h \ util/golombrice.h \ @@ -248,6 +253,7 @@ BITCOIN_CORE_H = \ util/macros.h \ util/message.h \ util/moneystr.h \ + util/overflow.h \ util/overloaded.h \ util/rbf.h \ util/readwritefile.h \ @@ -316,9 +322,9 @@ ipc/capnp/libbitcoin_ipc_a-ipc.$(OBJEXT): $(libbitcoin_ipc_mpgen_input:=.h) # Contains code accessing mempool and chain state that is meant to be separated # from wallet and gui code (see node/README.md). Shared code should go in # libbitcoin_common or libbitcoin_util libraries, instead. -libbitcoin_server_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -libbitcoin_server_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -libbitcoin_server_a_SOURCES = \ +libbitcoin_node_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libbitcoin_node_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +libbitcoin_node_a_SOURCES = \ addrdb.cpp \ addrman.cpp \ banman.cpp \ @@ -381,10 +387,10 @@ libbitcoin_server_a_SOURCES = \ $(BITCOIN_CORE_H) if ENABLE_WALLET -libbitcoin_server_a_SOURCES += wallet/init.cpp +libbitcoin_node_a_SOURCES += wallet/init.cpp endif if !ENABLE_WALLET -libbitcoin_server_a_SOURCES += dummywallet.cpp +libbitcoin_node_a_SOURCES += dummywallet.cpp endif if ENABLE_ZMQ @@ -496,11 +502,17 @@ crypto_libbitcoin_crypto_avx2_a_CXXFLAGS += $(AVX2_CXXFLAGS) crypto_libbitcoin_crypto_avx2_a_CPPFLAGS += -DENABLE_AVX2 crypto_libbitcoin_crypto_avx2_a_SOURCES = crypto/sha256_avx2.cpp -crypto_libbitcoin_crypto_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) -crypto_libbitcoin_crypto_shani_a_CPPFLAGS = $(AM_CPPFLAGS) -crypto_libbitcoin_crypto_shani_a_CXXFLAGS += $(SHANI_CXXFLAGS) -crypto_libbitcoin_crypto_shani_a_CPPFLAGS += -DENABLE_SHANI -crypto_libbitcoin_crypto_shani_a_SOURCES = crypto/sha256_shani.cpp +crypto_libbitcoin_crypto_x86_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +crypto_libbitcoin_crypto_x86_shani_a_CPPFLAGS = $(AM_CPPFLAGS) +crypto_libbitcoin_crypto_x86_shani_a_CXXFLAGS += $(X86_SHANI_CXXFLAGS) +crypto_libbitcoin_crypto_x86_shani_a_CPPFLAGS += -DENABLE_X86_SHANI +crypto_libbitcoin_crypto_x86_shani_a_SOURCES = crypto/sha256_x86_shani.cpp + +crypto_libbitcoin_crypto_arm_shani_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +crypto_libbitcoin_crypto_arm_shani_a_CPPFLAGS = $(AM_CPPFLAGS) +crypto_libbitcoin_crypto_arm_shani_a_CXXFLAGS += $(ARM_SHANI_CXXFLAGS) +crypto_libbitcoin_crypto_arm_shani_a_CPPFLAGS += -DENABLE_ARM_SHANI +crypto_libbitcoin_crypto_arm_shani_a_SOURCES = crypto/sha256_arm_shani.cpp # consensus: shared between all executables that validate any consensus rules. libbitcoin_consensus_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) @@ -663,19 +675,19 @@ bitcoin_bin_ldadd = \ $(LIBMEMENV) \ $(LIBSECP256K1) -bitcoin_bin_ldadd += $(BOOST_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS) +bitcoin_bin_ldadd += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(ZMQ_LIBS) $(SQLITE_LIBS) bitcoind_SOURCES = $(bitcoin_daemon_sources) init/bitcoind.cpp bitcoind_CPPFLAGS = $(bitcoin_bin_cppflags) bitcoind_CXXFLAGS = $(bitcoin_bin_cxxflags) bitcoind_LDFLAGS = $(bitcoin_bin_ldflags) -bitcoind_LDADD = $(LIBBITCOIN_SERVER) $(bitcoin_bin_ldadd) +bitcoind_LDADD = $(LIBBITCOIN_NODE) $(bitcoin_bin_ldadd) bitcoin_node_SOURCES = $(bitcoin_daemon_sources) init/bitcoin-node.cpp bitcoin_node_CPPFLAGS = $(bitcoin_bin_cppflags) bitcoin_node_CXXFLAGS = $(bitcoin_bin_cxxflags) bitcoin_node_LDFLAGS = $(bitcoin_bin_ldflags) -bitcoin_node_LDADD = $(LIBBITCOIN_SERVER) $(bitcoin_bin_ldadd) $(LIBBITCOIN_IPC) $(LIBMULTIPROCESS_LIBS) +bitcoin_node_LDADD = $(LIBBITCOIN_NODE) $(bitcoin_bin_ldadd) $(LIBBITCOIN_IPC) $(LIBMULTIPROCESS_LIBS) # bitcoin-cli binary # bitcoin_cli_SOURCES = bitcoin-cli.cpp @@ -693,7 +705,7 @@ bitcoin_cli_LDADD = \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) -bitcoin_cli_LDADD += $(BOOST_LIBS) $(EVENT_LIBS) +bitcoin_cli_LDADD += $(EVENT_LIBS) # # bitcoin-tx binary # @@ -713,8 +725,6 @@ bitcoin_tx_LDADD = \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) - -bitcoin_tx_LDADD += $(BOOST_LIBS) # # bitcoin-wallet binary # @@ -732,7 +742,6 @@ bitcoin_wallet_LDADD = \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) \ - $(BOOST_LIBS) \ $(BDB_LIBS) \ $(SQLITE_LIBS) @@ -758,8 +767,6 @@ bitcoin_util_LDADD = \ $(LIBBITCOIN_CONSENSUS) \ $(LIBBITCOIN_CRYPTO) \ $(LIBSECP256K1) - -bitcoin_util_LDADD += $(BOOST_LIBS) # # bitcoinconsensus library # diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 2a8e4a0aac..0bcce6ebe1 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -51,7 +51,7 @@ nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES) bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bench_bench_bitcoin_LDADD = \ - $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_NODE) \ $(LIBBITCOIN_WALLET) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ @@ -75,7 +75,7 @@ bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp bench_bench_bitcoin_SOURCES += bench/wallet_balance.cpp endif -bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) +bench_bench_bitcoin_LDADD += $(BDB_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) bench_bench_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) CLEAN_BITCOIN_BENCH = bench/*.gcda bench/*.gcno $(GENERATED_BENCH_FILES) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 6c0e6f7c6f..3491f07ee0 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -323,7 +323,7 @@ bitcoin_qt_sources = qt/main.cpp if TARGET_WINDOWS bitcoin_qt_sources += $(BITCOIN_QT_RC) endif -bitcoin_qt_ldadd = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER) +bitcoin_qt_ldadd = qt/libbitcoinqt.a $(LIBBITCOIN_NODE) if ENABLE_WALLET bitcoin_qt_ldadd += $(LIBBITCOIN_UTIL) $(LIBBITCOIN_WALLET) endif @@ -331,7 +331,7 @@ if ENABLE_ZMQ bitcoin_qt_ldadd += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif bitcoin_qt_ldadd += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \ - $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \ + $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS) bitcoin_qt_ldflags = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) bitcoin_qt_libtoolflags = $(AM_LIBTOOLFLAGS) --tag CXX @@ -357,13 +357,17 @@ SECONDARY: $(QT_QM) $(srcdir)/qt/bitcoinstrings.cpp: FORCE @test -n $(XGETTEXT) || echo "xgettext is required for updating translations" - $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" $(PYTHON) ../share/qt/extract_strings_qt.py $(libbitcoin_server_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_zmq_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) $(libbitcoin_util_a_SOURCES) + $(AM_V_GEN) cd $(srcdir); XGETTEXT=$(XGETTEXT) COPYRIGHT_HOLDERS="$(COPYRIGHT_HOLDERS)" $(PYTHON) ../share/qt/extract_strings_qt.py $(libbitcoin_node_a_SOURCES) $(libbitcoin_wallet_a_SOURCES) $(libbitcoin_common_a_SOURCES) $(libbitcoin_zmq_a_SOURCES) $(libbitcoin_consensus_a_SOURCES) $(libbitcoin_util_a_SOURCES) +# The resulted bitcoin_en.xlf source file should follow Transifex requirements. +# See: https://docs.transifex.com/formats/xliff#how-to-distinguish-between-a-source-file-and-a-translation-file translate: $(srcdir)/qt/bitcoinstrings.cpp $(QT_FORMS_UI) $(QT_FORMS_UI) $(BITCOIN_QT_BASE_CPP) qt/bitcoin.cpp $(BITCOIN_QT_WINDOWS_CPP) $(BITCOIN_QT_WALLET_CPP) $(BITCOIN_QT_H) $(BITCOIN_MM) @test -n $(LUPDATE) || echo "lupdate is required for updating translations" $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LUPDATE) -no-obsolete -I $(srcdir) -locations relative $^ -ts $(srcdir)/qt/locale/bitcoin_en.ts @test -n $(LCONVERT) || echo "lconvert is required for updating translations" - $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LCONVERT) -o $(srcdir)/qt/locale/bitcoin_en.xlf -i $(srcdir)/qt/locale/bitcoin_en.ts + $(AM_V_GEN) QT_SELECT=$(QT_SELECT) $(LCONVERT) -drop-translations -o $(srcdir)/qt/locale/bitcoin_en.xlf -i $(srcdir)/qt/locale/bitcoin_en.ts + @$(SED) -i.old -e 's|source-language="en" target-language="en"|source-language="en"|' -e '/<target xml:space="preserve"><\/target>/d' $(srcdir)/qt/locale/bitcoin_en.xlf + @rm -f $(srcdir)/qt/locale/bitcoin_en.xlf.old $(QT_QRC_LOCALE_CPP): $(QT_QRC_LOCALE) $(QT_QM) @test -f $(RCC) diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index a0900f2691..8e6fa2eb0d 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -44,7 +44,7 @@ endif # ENABLE_WALLET nodist_qt_test_test_bitcoin_qt_SOURCES = $(TEST_QT_MOC_CPP) -qt_test_test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER) $(LIBTEST_UTIL) +qt_test_test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_NODE) $(LIBTEST_UTIL) if ENABLE_WALLET qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_UTIL) $(LIBBITCOIN_WALLET) endif @@ -52,7 +52,7 @@ if ENABLE_ZMQ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) \ - $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) \ + $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(QT_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) \ $(QR_LIBS) $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) $(SQLITE_LIBS) qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 9fe2a3cf8a..1763dcb562 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -38,7 +38,7 @@ BITCOIN_TEST_SUITE = \ FUZZ_SUITE_LD_COMMON = \ $(LIBTEST_UTIL) \ $(LIBTEST_FUZZ) \ - $(LIBBITCOIN_SERVER) \ + $(LIBBITCOIN_NODE) \ $(LIBBITCOIN_WALLET) \ $(LIBBITCOIN_COMMON) \ $(LIBBITCOIN_UTIL) \ @@ -48,7 +48,6 @@ FUZZ_SUITE_LD_COMMON = \ $(LIBUNIVALUE) \ $(LIBLEVELDB) \ $(LIBLEVELDB_SSE42) \ - $(BOOST_LIBS) \ $(LIBMEMENV) \ $(LIBSECP256K1) \ $(MINISKETCH_LIBS) \ @@ -197,8 +196,8 @@ if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif -test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \ - $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) $(MINISKETCH_LIBS) +test_test_bitcoin_LDADD += $(LIBBITCOIN_NODE) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \ + $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) $(MINISKETCH_LIBS) test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_test_bitcoin_LDADD += $(BDB_LIBS) $(MINIUPNPC_LIBS) $(NATPMP_LIBS) $(SQLITE_LIBS) diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include index 2d772f2fca..9574454fd2 100644 --- a/src/Makefile.test_fuzz.include +++ b/src/Makefile.test_fuzz.include @@ -19,7 +19,7 @@ libtest_fuzz_a_SOURCES = \ test/fuzz/util.cpp \ $(TEST_FUZZ_H) -LIBTEST_FUZZ += $(LIBBITCOIN_SERVER) +LIBTEST_FUZZ += $(LIBBITCOIN_NODE) LIBTEST_FUZZ += $(LIBBITCOIN_COMMON) LIBTEST_FUZZ += $(LIBBITCOIN_UTIL) LIBTEST_FUZZ += $(LIBBITCOIN_CRYPTO_BASE) diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include index 0a3b99e7d2..92cb8a5ce6 100644 --- a/src/Makefile.test_util.include +++ b/src/Makefile.test_util.include @@ -35,7 +35,7 @@ libtest_util_a_SOURCES = \ test/util/wallet.cpp \ $(TEST_UTIL_H) -LIBTEST_UTIL += $(LIBBITCOIN_SERVER) +LIBTEST_UTIL += $(LIBBITCOIN_NODE) LIBTEST_UTIL += $(LIBBITCOIN_COMMON) LIBTEST_UTIL += $(LIBBITCOIN_UTIL) LIBTEST_UTIL += $(LIBBITCOIN_CRYPTO_BASE) diff --git a/src/addrdb.cpp b/src/addrdb.cpp index bdb1fc6b2b..4f22e688db 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -9,6 +9,7 @@ #include <chainparams.h> #include <clientversion.h> #include <cstdint> +#include <fs.h> #include <hash.h> #include <logging/timer.h> #include <netbase.h> diff --git a/src/addrdb.h b/src/addrdb.h index 19be4b5bb4..4bdafb64e4 100644 --- a/src/addrdb.h +++ b/src/addrdb.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/addrman.cpp b/src/addrman.cpp index 4d785043b8..3a845b5b6e 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2012 Pieter Wuille -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -930,6 +930,29 @@ std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_() return {info_old, info_old.nLastTry}; } +std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& addr) +{ + AssertLockHeld(cs); + + AddrInfo* addr_info = Find(addr); + + if (!addr_info) return std::nullopt; + + if(addr_info->fInTried) { + int bucket{addr_info->GetTriedBucket(nKey, m_asmap)}; + return AddressPosition(/*tried=*/true, + /*multiplicity=*/1, + /*bucket=*/bucket, + /*position=*/addr_info->GetBucketPosition(nKey, false, bucket)); + } else { + int bucket{addr_info->GetNewBucket(nKey, m_asmap)}; + return AddressPosition(/*tried=*/false, + /*multiplicity=*/addr_info->nRefCount, + /*bucket=*/bucket, + /*position=*/addr_info->GetBucketPosition(nKey, true, bucket)); + } +} + void AddrManImpl::Check() const { AssertLockHeld(cs); @@ -1116,6 +1139,15 @@ void AddrManImpl::SetServices(const CService& addr, ServiceFlags nServices) Check(); } +std::optional<AddressPosition> AddrManImpl::FindAddressEntry(const CAddress& addr) +{ + LOCK(cs); + Check(); + auto entry = FindAddressEntry_(addr); + Check(); + return entry; +} + const std::vector<bool>& AddrManImpl::GetAsmap() const { return m_asmap; @@ -1201,3 +1233,8 @@ const std::vector<bool>& AddrMan::GetAsmap() const { return m_impl->GetAsmap(); } + +std::optional<AddressPosition> AddrMan::FindAddressEntry(const CAddress& addr) +{ + return m_impl->FindAddressEntry(addr); +} diff --git a/src/addrman.h b/src/addrman.h index e9bc372380..0646ef368d 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -1,5 +1,5 @@ // Copyright (c) 2012 Pieter Wuille -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -22,6 +22,31 @@ class AddrManImpl; /** Default for -checkaddrman */ static constexpr int32_t DEFAULT_ADDRMAN_CONSISTENCY_CHECKS{0}; +/** Test-only struct, capturing info about an address in AddrMan */ +struct AddressPosition { + // Whether the address is in the new or tried table + const bool tried; + + // Addresses in the tried table should always have a multiplicity of 1. + // Addresses in the new table can have multiplicity between 1 and + // ADDRMAN_NEW_BUCKETS_PER_ADDRESS + const int multiplicity; + + // If the address is in the new table, the bucket and position are + // populated based on the first source who sent the address. + // In certain edge cases, this may not be where the address is currently + // located. + const int bucket; + const int position; + + bool operator==(AddressPosition other) { + return std::tie(tried, multiplicity, bucket, position) == + std::tie(other.tried, other.multiplicity, other.bucket, other.position); + } + explicit AddressPosition(bool tried_in, int multiplicity_in, int bucket_in, int position_in) + : tried{tried_in}, multiplicity{multiplicity_in}, bucket{bucket_in}, position{position_in} {} +}; + /** Stochastic address manager * * Design goals: @@ -142,6 +167,15 @@ public: void SetServices(const CService& addr, ServiceFlags nServices); const std::vector<bool>& GetAsmap() const; + + /** Test-only function + * Find the address record in AddrMan and return information about its + * position. + * @param[in] addr The address record to look up. + * @return Information about the address record in AddrMan + * or nullopt if address is not found. + */ + std::optional<AddressPosition> FindAddressEntry(const CAddress& addr); }; #endif // BITCOIN_ADDRMAN_H diff --git a/src/addrman_impl.h b/src/addrman_impl.h index bd7caf473b..5e76f72342 100644 --- a/src/addrman_impl.h +++ b/src/addrman_impl.h @@ -137,9 +137,11 @@ public: void SetServices(const CService& addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(!cs); + std::optional<AddressPosition> FindAddressEntry(const CAddress& addr) + EXCLUSIVE_LOCKS_REQUIRED(!cs); + const std::vector<bool>& GetAsmap() const; - friend class AddrManTest; friend class AddrManDeterministic; private: @@ -266,6 +268,8 @@ private: std::pair<CAddress, int64_t> SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs); + std::optional<AddressPosition> FindAddressEntry_(const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(cs); + //! Consistency check, taking into account m_consistency_check_ratio. //! Will std::abort if an inconsistency is detected. void Check() const EXCLUSIVE_LOCKS_REQUIRED(cs); diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 0bebb0cf54..f7f62dfc68 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -96,7 +96,7 @@ base_uint<BITS>& base_uint<BITS>::operator/=(const base_uint& b) while (shift >= 0) { if (num >= div) { num -= div; - pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result. + pn[shift / 32] |= (1U << (shift & 31)); // set a bit of the result. } div >>= 1; // shift back. shift--; @@ -236,7 +236,7 @@ uint32_t arith_uint256::GetCompact(bool fNegative) const nCompact >>= 8; nSize++; } - assert((nCompact & ~0x007fffff) == 0); + assert((nCompact & ~0x007fffffU) == 0); assert(nSize < 256); nCompact |= nSize << 24; nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0); diff --git a/src/banman.cpp b/src/banman.cpp index c64a48a05a..b28e3f7f7c 100644 --- a/src/banman.cpp +++ b/src/banman.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -7,6 +7,7 @@ #include <netaddress.h> #include <node/ui_interface.h> +#include <sync.h> #include <util/system.h> #include <util/time.h> #include <util/translation.h> @@ -39,18 +40,23 @@ BanMan::~BanMan() void BanMan::DumpBanlist() { - SweepBanned(); // clean unused entries (if bantime has expired) - - if (!BannedSetIsDirty()) return; - - int64_t n_start = GetTimeMillis(); + static Mutex dump_mutex; + LOCK(dump_mutex); banmap_t banmap; - GetBanned(banmap); - if (m_ban_db.Write(banmap)) { + { + LOCK(m_cs_banned); + SweepBanned(); + if (!BannedSetIsDirty()) return; + banmap = m_banned; SetBannedSetDirty(false); } + int64_t n_start = GetTimeMillis(); + if (!m_ban_db.Write(banmap)) { + SetBannedSetDirty(true); + } + LogPrint(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(), GetTimeMillis() - n_start); } diff --git a/src/banman.h b/src/banman.h index 6cb6304744..f268fffa5a 100644 --- a/src/banman.h +++ b/src/banman.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. #ifndef BITCOIN_BANMAN_H diff --git a/src/base58.cpp b/src/base58.cpp index b122e0055e..dfa2e8db55 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020 The Bitcoin Core developers +// Copyright (c) 2014-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. diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp index d6834a239b..3ca58b923e 100644 --- a/src/bench/addrman.cpp +++ b/src/bench/addrman.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -16,6 +16,9 @@ static constexpr size_t NUM_SOURCES = 64; static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256; +static const std::vector<bool> EMPTY_ASMAP; +static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0}; + static std::vector<CAddress> g_sources; static std::vector<std::vector<CAddress>> g_addresses; @@ -74,14 +77,14 @@ static void AddrManAdd(benchmark::Bench& bench) CreateAddresses(); bench.run([&] { - AddrMan addrman{/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0}; + AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; AddAddressesToAddrMan(addrman); }); } static void AddrManSelect(benchmark::Bench& bench) { - AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); + AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; FillAddrMan(addrman); @@ -93,7 +96,7 @@ static void AddrManSelect(benchmark::Bench& bench) static void AddrManGetAddr(benchmark::Bench& bench) { - AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); + AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; FillAddrMan(addrman); @@ -122,7 +125,7 @@ static void AddrManAddThenGood(benchmark::Bench& bench) // // This has some overhead (exactly the result of AddrManAdd benchmark), but that overhead is constant so improvements in // AddrMan::Good() will still be noticeable. - AddrMan addrman(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); + AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; AddAddressesToAddrMan(addrman); markSomeAsGood(addrman); diff --git a/src/bench/bech32.cpp b/src/bench/bech32.cpp index bc3685818e..0f89a8e2b5 100644 --- a/src/bench/bech32.cpp +++ b/src/bench/bech32.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 030bc43396..033d319750 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -1,9 +1,10 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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 <bench/bench.h> +#include <fs.h> #include <test/util/setup_common.h> #include <chrono> @@ -19,22 +20,23 @@ using namespace std::chrono_literals; const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; +const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{}; + namespace { -void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const std::string& filename, const char* tpl) +void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const fs::path& file, const char* tpl) { - if (benchmarkResults.empty() || filename.empty()) { + if (benchmarkResults.empty() || file.empty()) { // nothing to write, bail out return; } - std::ofstream fout(filename); + std::ofstream fout{file}; if (fout.is_open()) { ankerl::nanobench::render(tpl, benchmarkResults, fout); + std::cout << "Created " << file << std::endl; } else { - std::cout << "Could write to file '" << filename << "'" << std::endl; + std::cout << "Could not write to file " << file << std::endl; } - - std::cout << "Created '" << filename << "'" << std::endl; } } // namespace diff --git a/src/bench/bench.h b/src/bench/bench.h index b0e4006ee3..6634138beb 100644 --- a/src/bench/bench.h +++ b/src/bench/bench.h @@ -1,10 +1,11 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. #ifndef BITCOIN_BENCH_BENCH_H #define BITCOIN_BENCH_BENCH_H +#include <fs.h> #include <util/macros.h> #include <chrono> @@ -44,8 +45,8 @@ struct Args { bool is_list_only; std::chrono::milliseconds min_time; std::vector<double> asymptote; - std::string output_csv; - std::string output_json; + fs::path output_csv; + fs::path output_json; std::string regex_filter; }; diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index 83609d2787..3f8bff4bcf 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. @@ -6,6 +6,7 @@ #include <clientversion.h> #include <crypto/sha256.h> +#include <fs.h> #include <util/strencodings.h> #include <util/system.h> @@ -108,8 +109,8 @@ int main(int argc, char** argv) args.asymptote = parseAsymptote(argsman.GetArg("-asymptote", "")); args.is_list_only = argsman.GetBoolArg("-list", false); args.min_time = std::chrono::milliseconds(argsman.GetIntArg("-min_time", DEFAULT_MIN_TIME_MS)); - args.output_csv = argsman.GetArg("-output_csv", ""); - args.output_json = argsman.GetArg("-output_json", ""); + args.output_csv = fs::PathFromString(argsman.GetArg("-output_csv", "")); + args.output_json = fs::PathFromString(argsman.GetArg("-output_json", "")); args.regex_filter = argsman.GetArg("-filter", DEFAULT_BENCH_FILTER); benchmark::BenchRunner::RunAll(args); diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp index 0577ab80e3..4ed5397330 100644 --- a/src/bench/block_assemble.cpp +++ b/src/bench/block_assemble.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp index dae3a47cd7..22dfb7aa5b 100644 --- a/src/bench/ccoins_caching.cpp +++ b/src/bench/ccoins_caching.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index a9f3f5f84d..52e5cb743f 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -17,8 +17,8 @@ static void DeserializeBlockTest(benchmark::Bench& bench) { CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION); - char a = '\0'; - stream.write(&a, 1); // Prevent compaction + std::byte a{0}; + stream.write({&a, 1}); // Prevent compaction bench.unit("block").run([&] { CBlock block; @@ -31,8 +31,8 @@ static void DeserializeBlockTest(benchmark::Bench& bench) static void DeserializeAndCheckBlockTest(benchmark::Bench& bench) { CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION); - char a = '\0'; - stream.write(&a, 1); // Prevent compaction + std::byte a{0}; + stream.write({&a, 1}); // Prevent compaction ArgsManager bench_args; const auto chainParams = CreateChainParams(bench_args, CBaseChainParams::MAIN); diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index f97bf8028a..609c592d20 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -11,6 +11,19 @@ #include <set> +using node::NodeContext; +using wallet::AttemptSelection; +using wallet::CInputCoin; +using wallet::COutput; +using wallet::CWallet; +using wallet::CWalletTx; +using wallet::CoinEligibilityFilter; +using wallet::CoinSelectionParams; +using wallet::CreateDummyWalletDatabase; +using wallet::OutputGroup; +using wallet::SelectCoinsBnB; +using wallet::TxStateInactive; + static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<std::unique_ptr<CWalletTx>>& wtxs) { static int nextLockTime = 0; diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp index d36e504bfc..d17ec503e7 100644 --- a/src/bench/crypto_hash.cpp +++ b/src/bench/crypto_hash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/bench/data.cpp b/src/bench/data.cpp index 481e372105..35558b3aa7 100644 --- a/src/bench/data.cpp +++ b/src/bench/data.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp index 8703a1cf94..02a2e689b1 100644 --- a/src/bench/duplicate_inputs.cpp +++ b/src/bench/duplicate_inputs.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp index 4f49fba7b7..e80b9e1ac2 100644 --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp index a0a82ea359..afa4618e1b 100644 --- a/src/bench/mempool_stress.cpp +++ b/src/bench/mempool_stress.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp index f4fabedab6..6343ed7848 100644 --- a/src/bench/prevector.cpp +++ b/src/bench/prevector.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp index 30bc1d5fdf..9f1679aa84 100644 --- a/src/bench/rollingbloom.cpp +++ b/src/bench/rollingbloom.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 3bef64f720..2143bcf950 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. @@ -23,8 +23,8 @@ struct TestBlockAndIndex { TestBlockAndIndex() { CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION); - char a = '\0'; - stream.write(&a, 1); // Prevent compaction + std::byte a{0}; + stream.write({&a, 1}); // Prevent compaction stream >> block; diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp index 67c827d0d3..12dcff5844 100644 --- a/src/bench/rpc_mempool.cpp +++ b/src/bench/rpc_mempool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp index 928aa7573c..8e4708f260 100644 --- a/src/bench/verify_script.cpp +++ b/src/bench/verify_script.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/bench/wallet_balance.cpp b/src/bench/wallet_balance.cpp index 8e3ca59496..d4b8794c6d 100644 --- a/src/bench/wallet_balance.cpp +++ b/src/bench/wallet_balance.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -14,6 +14,12 @@ #include <optional> +using wallet::CWallet; +using wallet::CreateMockWalletDatabase; +using wallet::DBErrors; +using wallet::GetBalance; +using wallet::WALLET_FLAG_DESCRIPTORS; + static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const bool add_mine) { const auto test_setup = MakeNoLogFileContext<const TestingSetup>(); diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 279521a761..6557360a71 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index eb97cfc6f6..ec07114d6e 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -12,6 +12,7 @@ #include <consensus/consensus.h> #include <core_io.h> #include <key_io.h> +#include <fs.h> #include <policy/policy.h> #include <policy/rbf.h> #include <primitives/transaction.h> @@ -158,7 +159,7 @@ static void RegisterLoad(const std::string& strInput) std::string key = strInput.substr(0, pos); std::string filename = strInput.substr(pos + 1, std::string::npos); - FILE *f = fopen(filename.c_str(), "r"); + FILE *f = fsbridge::fopen(filename.c_str(), "r"); if (!f) { std::string strErr = "Cannot open file " + filename; throw std::runtime_error(strErr); @@ -433,13 +434,16 @@ static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strIn if (pos==0) throw std::runtime_error("TX output value not specified"); - if (pos != std::string::npos) { + if (pos == std::string::npos) { + pos = 0; + } else { // Extract and validate VALUE value = ExtractAndValidateValue(strInput.substr(0, pos)); + ++pos; } // extract and validate DATA - std::string strData = strInput.substr(pos + 1, std::string::npos); + const std::string strData{strInput.substr(pos, std::string::npos)}; if (!IsHex(strData)) throw std::runtime_error("invalid TX output data"); @@ -630,7 +634,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) } Coin newcoin; newcoin.out.scriptPubKey = scriptPubKey; - newcoin.out.nValue = 0; + newcoin.out.nValue = MAX_MONEY; if (prevOut.exists("amount")) { newcoin.out.nValue = AmountFromValue(prevOut["amount"]); } @@ -669,6 +673,10 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) if (!fHashSingle || (i < mergedTx.vout.size())) ProduceSignature(keystore, MutableTransactionSignatureCreator(&mergedTx, i, amount, nHashType), prevPubKey, sigdata); + if (amount == MAX_MONEY && !sigdata.scriptWitness.IsNull()) { + throw std::runtime_error(strprintf("Missing amount for CTxOut with scriptPubKey=%s", HexStr(prevPubKey))); + } + UpdateInput(txin, sigdata); } diff --git a/src/bitcoin-util.cpp b/src/bitcoin-util.cpp index f534aecc19..973f4f2883 100644 --- a/src/bitcoin-util.cpp +++ b/src/bitcoin-util.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index 3c8dbeaa21..65c37f182f 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. @@ -123,7 +123,7 @@ int main(int argc, char* argv[]) ECCVerifyHandle globalVerifyHandle; ECC_Start(); - if (!WalletTool::ExecuteWalletToolFunc(args, command->command)) { + if (!wallet::WalletTool::ExecuteWalletToolFunc(args, command->command)) { return EXIT_FAILURE; } ECC_Stop(); diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 25ec2809e9..6432e8849d 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -30,6 +30,8 @@ #include <functional> #include <optional> +using node::NodeContext; + const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; UrlDecodeFn* const URL_DECODE = urlDecode; diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp index 69d4eacd87..63a9ba498f 100644 --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -24,43 +24,12 @@ static const std::map<BlockFilterType, std::string> g_filter_types = { {BlockFilterType::BASIC, "basic"}, }; -// Map a value x that is uniformly distributed in the range [0, 2^64) to a -// value uniformly distributed in [0, n) by returning the upper 64 bits of -// x * n. -// -// See: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ -static uint64_t MapIntoRange(uint64_t x, uint64_t n) -{ -#ifdef __SIZEOF_INT128__ - return (static_cast<unsigned __int128>(x) * static_cast<unsigned __int128>(n)) >> 64; -#else - // To perform the calculation on 64-bit numbers without losing the - // result to overflow, split the numbers into the most significant and - // least significant 32 bits and perform multiplication piece-wise. - // - // See: https://stackoverflow.com/a/26855440 - uint64_t x_hi = x >> 32; - uint64_t x_lo = x & 0xFFFFFFFF; - uint64_t n_hi = n >> 32; - uint64_t n_lo = n & 0xFFFFFFFF; - - uint64_t ac = x_hi * n_hi; - uint64_t ad = x_hi * n_lo; - uint64_t bc = x_lo * n_hi; - uint64_t bd = x_lo * n_lo; - - uint64_t mid34 = (bd >> 32) + (bc & 0xFFFFFFFF) + (ad & 0xFFFFFFFF); - uint64_t upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32); - return upper64; -#endif -} - uint64_t GCSFilter::HashToRange(const Element& element) const { uint64_t hash = CSipHasher(m_params.m_siphash_k0, m_params.m_siphash_k1) .Write(element.data(), element.size()) .Finalize(); - return MapIntoRange(hash, m_F); + return FastRange64(hash, m_F); } std::vector<uint64_t> GCSFilter::BuildHashedSet(const ElementSet& elements) const diff --git a/src/chain.cpp b/src/chain.cpp index 5d182e1af8..b8158f7b0b 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -4,6 +4,12 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <chain.h> +#include <util/time.h> + +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) { @@ -145,7 +151,7 @@ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& fr if (r.bits() > 63) { return sign * std::numeric_limits<int64_t>::max(); } - return sign * r.GetLow64(); + return sign * int64_t(r.GetLow64()); } /** Find the last common ancestor two blocks have. diff --git a/src/chain.h b/src/chain.h index 8eafc5d588..24b5026aba 100644 --- a/src/chain.h +++ b/src/chain.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -10,6 +10,7 @@ #include <consensus/params.h> #include <flatfile.h> #include <primitives/block.h> +#include <sync.h> #include <tinyformat.h> #include <uint256.h> @@ -37,6 +38,8 @@ static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME; */ static constexpr int64_t MAX_BLOCK_TIME_GAP = 90 * 60; +extern RecursiveMutex cs_main; + class CBlockFileInfo { public: @@ -161,13 +164,13 @@ public: int nHeight{0}; //! Which # file this block is stored in (blk?????.dat) - int nFile{0}; + int nFile GUARDED_BY(::cs_main){0}; //! Byte offset within blk?????.dat where this block's data is stored - unsigned int nDataPos{0}; + unsigned int nDataPos GUARDED_BY(::cs_main){0}; //! Byte offset within rev?????.dat where this block's undo data is stored - unsigned int nUndoPos{0}; + unsigned int nUndoPos GUARDED_BY(::cs_main){0}; //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block arith_uint256 nChainWork{}; @@ -195,7 +198,7 @@ public: //! load to avoid the block index being spuriously rewound. //! @sa NeedsRedownload //! @sa ActivateSnapshot - uint32_t nStatus{0}; + uint32_t nStatus GUARDED_BY(::cs_main){0}; //! block header int32_t nVersion{0}; @@ -223,8 +226,9 @@ public: { } - FlatFilePos GetBlockPos() const + FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); FlatFilePos ret; if (nStatus & BLOCK_HAVE_DATA) { ret.nFile = nFile; @@ -233,8 +237,9 @@ public: return ret; } - FlatFilePos GetUndoPos() const + FlatFilePos GetUndoPos() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); FlatFilePos ret; if (nStatus & BLOCK_HAVE_UNDO) { ret.nFile = nFile; @@ -306,7 +311,9 @@ public: //! Check whether this block index entry is valid up to the passed validity level. bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const + EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. if (nStatus & BLOCK_FAILED_MASK) return false; @@ -315,12 +322,17 @@ public: //! @returns true if the block is assumed-valid; this means it is queued to be //! validated by a background chainstate. - bool IsAssumedValid() const { return nStatus & BLOCK_ASSUMED_VALID; } + bool IsAssumedValid() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) + { + AssertLockHeld(::cs_main); + return nStatus & BLOCK_ASSUMED_VALID; + } //! Raise the validity level of this block index entry. //! Returns true if the validity was changed. - bool RaiseValidity(enum BlockStatus nUpTo) + bool RaiseValidity(enum BlockStatus nUpTo) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. if (nStatus & BLOCK_FAILED_MASK) return false; @@ -370,6 +382,7 @@ public: SERIALIZE_METHODS(CDiskBlockIndex, obj) { + LOCK(::cs_main); int _nVersion = s.GetVersion(); if (!(s.GetType() & SER_GETHASH)) READWRITE(VARINT_MODE(_nVersion, VarIntMode::NONNEGATIVE_SIGNED)); @@ -462,7 +475,7 @@ public: /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */ int Height() const { - return vChain.size() - 1; + return int(vChain.size()) - 1; } /** Set/initialize a chain with a given tip. */ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 2e823c1211..99671d196d 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/chainparams.h b/src/chainparams.h index 4faa6f8d06..66592ffdda 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index f24863f419..71978081ce 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h index 953a09d5e7..2edb556a35 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -683,22 +683,19 @@ static const uint8_t chainparams_seed_main[] = { 0x04,0x20,0x98,0xc6,0x44,0x27,0x90,0x41,0xa6,0x98,0xf9,0x25,0x6c,0x59,0x0f,0x06,0x6d,0x44,0x59,0x0e,0xb2,0x46,0xb0,0xa4,0x37,0x88,0x69,0x8f,0xc1,0x32,0xcd,0x9f,0x15,0xd7,0x20,0x8d, 0x04,0x20,0xaa,0x3a,0x16,0x86,0xea,0x59,0x09,0x04,0x78,0xe5,0x10,0x92,0xe1,0x1d,0xad,0xf7,0x56,0x2b,0xac,0xb0,0x97,0x29,0x63,0x30,0xf4,0x1b,0xcf,0xde,0xf3,0x28,0x0a,0x29,0x20,0x8d, 0x04,0x20,0xbc,0x27,0xae,0x89,0xc1,0x67,0x73,0x0a,0x08,0x02,0xdf,0xb7,0xcc,0x94,0xc7,0x9f,0xf4,0x72,0x7a,0x9b,0x20,0x0c,0x5c,0x11,0x3d,0x22,0xd6,0x13,0x88,0x66,0x74,0xbf,0x20,0x8d, - 0x05,0x20,0xe1,0xd6,0xb8,0xfa,0xdd,0xeb,0x03,0x32,0x30,0x3b,0x20,0x6a,0xbc,0xaf,0x99,0x4f,0xa0,0xa2,0x72,0x48,0xfe,0x44,0xe0,0xf6,0x03,0xc1,0xbd,0xb6,0x24,0xd0,0xf6,0xb8,0x00,0x00, - 0x05,0x20,0xf4,0xb7,0xb4,0xcd,0xf5,0xb6,0x54,0x82,0x27,0x6d,0x29,0x7b,0x06,0x7f,0x52,0x59,0xa0,0xb4,0xdc,0xf7,0x6f,0xb4,0x71,0xcf,0xcc,0xfb,0x6b,0x86,0xc2,0x57,0x80,0xc6,0x00,0x00, 0x05,0x20,0x07,0x61,0x26,0xd7,0x6c,0x05,0xbf,0xf6,0x2d,0x8c,0xca,0xc4,0x65,0xd3,0xd3,0xb2,0x49,0xe9,0xcc,0x53,0x1e,0xca,0x77,0x84,0xb6,0x10,0x5e,0xc2,0x5a,0xfe,0x28,0xb3,0x00,0x00, 0x05,0x20,0x0a,0x26,0x27,0x45,0xb1,0x1e,0xfc,0x27,0x03,0x32,0x0e,0x65,0x9e,0x3c,0x64,0x0e,0x33,0x50,0x3d,0x6c,0x90,0x17,0x0e,0x29,0xee,0x5a,0x58,0xdf,0x08,0xde,0xbf,0x73,0x00,0x00, 0x05,0x20,0x17,0x0c,0x56,0xce,0x72,0xa5,0xa0,0xe6,0x23,0x06,0xa3,0xc7,0x08,0x43,0x18,0xee,0x3a,0x46,0x35,0x5d,0x17,0xf6,0x78,0x96,0xa0,0x9c,0x51,0xef,0xbe,0x23,0xfd,0x71,0x00,0x00, 0x05,0x20,0x19,0xe7,0x0d,0x3f,0xfe,0x9e,0x0e,0x8e,0x73,0x40,0x40,0xc3,0xba,0x8f,0x41,0xaf,0xf1,0x7b,0xa6,0x83,0x1b,0xc3,0xa4,0xe0,0x6d,0x6c,0x57,0xa7,0x36,0x5d,0x09,0xce,0x00,0x00, - 0x05,0x20,0x31,0x0f,0x30,0x0b,0x9d,0x70,0x0c,0x7c,0xf7,0x98,0x7e,0x1c,0xf4,0x33,0xdc,0x64,0x17,0xf7,0x00,0x7a,0x0c,0x04,0xb5,0x83,0xfc,0x5f,0xa6,0x52,0x39,0x79,0x63,0x87,0x00,0x00, 0x05,0x20,0x3e,0xe3,0xe0,0xa9,0xbc,0xf4,0x2e,0x59,0xd9,0x20,0xee,0xdf,0x74,0x61,0x4d,0x99,0x0c,0x5c,0x15,0x30,0x9b,0x72,0x16,0x79,0x15,0xf4,0x7a,0xca,0x34,0xcc,0x81,0x99,0x00,0x00, 0x05,0x20,0x3b,0x42,0x1c,0x25,0xf7,0xbf,0x79,0xed,0x6d,0x7d,0xef,0x65,0x30,0x7d,0xee,0x16,0x37,0x22,0x72,0x43,0x33,0x28,0x40,0xa3,0xaa,0xf4,0x48,0x49,0x67,0xb1,0x4b,0xfd,0x00,0x00, - 0x05,0x20,0x46,0xce,0x21,0x81,0x48,0xce,0xa7,0x8a,0x98,0xca,0xb1,0x0b,0x51,0xa5,0xc8,0xff,0x39,0xc5,0x1a,0xa3,0xd3,0x02,0x32,0xa3,0x29,0xad,0x79,0xb8,0x7f,0x34,0x51,0x33,0x00,0x00, 0x05,0x20,0x4e,0x77,0x2e,0x12,0x91,0x67,0x6b,0x94,0xc4,0x92,0x2f,0x19,0x67,0x7d,0xcd,0x47,0x02,0xad,0xf8,0x60,0x72,0xed,0x73,0xf1,0x10,0x99,0x2c,0x05,0x61,0x66,0x55,0xd9,0x00,0x00, 0x05,0x20,0x53,0x94,0xa6,0x3e,0x14,0x82,0xd4,0xf9,0xd3,0xa7,0x53,0x33,0x05,0xce,0x72,0x64,0xed,0x74,0x09,0x63,0x8f,0x24,0xef,0xda,0x12,0xa1,0x55,0xe0,0xd8,0xbb,0xd3,0x58,0x00,0x00, - 0x05,0x20,0x55,0x62,0x32,0x7d,0x82,0x32,0x4f,0x9d,0xdf,0x24,0x5c,0xed,0x8e,0x1a,0x5a,0x8d,0xc6,0x50,0xb4,0x32,0xd5,0x85,0xef,0xb0,0xfa,0x7c,0xf9,0xbb,0x25,0x89,0x6b,0x03,0x00,0x00, - 0x05,0x20,0x91,0xcf,0xa2,0x5b,0x04,0x33,0x69,0x66,0xb0,0x72,0x27,0x54,0xbe,0xcd,0xd8,0x08,0xeb,0x95,0x55,0x5a,0xc2,0x79,0x91,0x3a,0xd9,0xf2,0x2c,0x73,0x9f,0x78,0x50,0xca,0x00,0x00, + 0x05,0x20,0x91,0x06,0xd1,0x9e,0xbd,0xab,0xc4,0x61,0xb3,0x0a,0xc2,0x3b,0x29,0xf3,0x10,0x38,0xee,0xbd,0x9d,0xe3,0x99,0x97,0x30,0x70,0x6e,0xe6,0xfb,0x6a,0x3c,0x07,0x3d,0xfd,0x00,0x00, 0x05,0x20,0xb5,0x83,0x6f,0xb6,0x11,0xd8,0x0e,0xa8,0x57,0xda,0x15,0x20,0x5b,0x1a,0x6d,0x21,0x15,0x5a,0xbd,0xb4,0x17,0x11,0xc2,0xfb,0x0e,0xfc,0xde,0xe8,0x26,0x56,0xa8,0xac,0x00,0x00, 0x05,0x20,0xcc,0xaf,0x6c,0x3b,0xd0,0x13,0x76,0x23,0xc3,0x36,0xbb,0x64,0x4a,0x4a,0x06,0x93,0x69,0x6d,0xb0,0x10,0x6e,0x66,0xa4,0x61,0xf8,0x2d,0xe7,0x80,0x72,0x4d,0x53,0x94,0x00,0x00, + 0x06,0x10,0xfc,0x32,0x17,0xea,0xe4,0x15,0xc3,0xbf,0x98,0x08,0x14,0x9d,0xb5,0xa2,0xc9,0xaa,0x20,0x8d, + 0x06,0x10,0xfc,0xc7,0xbe,0x49,0xcc,0xd1,0xdc,0x91,0x31,0x25,0xf0,0xda,0x45,0x7d,0x08,0xce,0x20,0x8d, }; static const uint8_t chainparams_seed_test[] = { diff --git a/src/checkqueue.h b/src/checkqueue.h index 760dfbddc1..d0e88a3410 100644 --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/clientversion.cpp b/src/clientversion.cpp index f97e4097e8..9b65952b02 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/clientversion.h b/src/clientversion.h index a3e6233437..a39d96292d 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/coins.cpp b/src/coins.cpp index daead6055e..1abdcb54d2 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/coins.h b/src/coins.h index 3151a260d9..de297dd427 100644 --- a/src/coins.h +++ b/src/coins.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/common/bloom.cpp b/src/common/bloom.cpp index 26b70b4d14..8b32a6c94a 100644 --- a/src/common/bloom.cpp +++ b/src/common/bloom.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -11,6 +11,7 @@ #include <script/standard.h> #include <span.h> #include <streams.h> +#include <util/fastrange.h> #include <algorithm> #include <cmath> @@ -61,7 +62,7 @@ void CBloomFilter::insert(const COutPoint& outpoint) { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << outpoint; - insert(stream); + insert(MakeUCharSpan(stream)); } bool CBloomFilter::contains(Span<const unsigned char> vKey) const @@ -82,7 +83,7 @@ bool CBloomFilter::contains(const COutPoint& outpoint) const { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << outpoint; - return contains(stream); + return contains(MakeUCharSpan(stream)); } bool CBloomFilter::IsWithinSizeConstraints() const @@ -191,14 +192,6 @@ static inline uint32_t RollingBloomHash(unsigned int nHashNum, uint32_t nTweak, return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash); } - -// A replacement for x % n. This assumes that x and n are 32bit integers, and x is a uniformly random distributed 32bit value -// which should be the case for a good hash. -// See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ -static inline uint32_t FastMod(uint32_t x, size_t n) { - return ((uint64_t)x * (uint64_t)n) >> 32; -} - void CRollingBloomFilter::insert(Span<const unsigned char> vKey) { if (nEntriesThisGeneration == nEntriesPerGeneration) { @@ -223,10 +216,10 @@ void CRollingBloomFilter::insert(Span<const unsigned char> vKey) uint32_t h = RollingBloomHash(n, nTweak, vKey); int bit = h & 0x3F; /* FastMod works with the upper bits of h, so it is safe to ignore that the lower bits of h are already used for bit. */ - uint32_t pos = FastMod(h, data.size()); + uint32_t pos = FastRange32(h, data.size()); /* The lowest bit of pos is ignored, and set to zero for the first bit, and to one for the second. */ - data[pos & ~1] = (data[pos & ~1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration & 1)) << bit; - data[pos | 1] = (data[pos | 1] & ~(((uint64_t)1) << bit)) | ((uint64_t)(nGeneration >> 1)) << bit; + data[pos & ~1U] = (data[pos & ~1U] & ~(uint64_t{1} << bit)) | (uint64_t(nGeneration & 1)) << bit; + data[pos | 1] = (data[pos | 1] & ~(uint64_t{1} << bit)) | (uint64_t(nGeneration >> 1)) << bit; } } @@ -235,9 +228,9 @@ bool CRollingBloomFilter::contains(Span<const unsigned char> vKey) const for (int n = 0; n < nHashFuncs; n++) { uint32_t h = RollingBloomHash(n, nTweak, vKey); int bit = h & 0x3F; - uint32_t pos = FastMod(h, data.size()); + uint32_t pos = FastRange32(h, data.size()); /* If the relevant bit is not set in either data[pos & ~1] or data[pos | 1], the filter does not contain vKey */ - if (!(((data[pos & ~1] | data[pos | 1]) >> bit) & 1)) { + if (!(((data[pos & ~1U] | data[pos | 1]) >> bit) & 1)) { return false; } } diff --git a/src/common/bloom.h b/src/common/bloom.h index 25c16fbfe2..4f7473d8ff 100644 --- a/src/common/bloom.h +++ b/src/common/bloom.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/compat.h b/src/compat.h index 3449bc2661..237b881b11 100644 --- a/src/compat.h +++ b/src/compat.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/compat/assumptions.h b/src/compat/assumptions.h index 7a254c3b67..92615b582a 100644 --- a/src/compat/assumptions.h +++ b/src/compat/assumptions.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/compat/sanity.h b/src/compat/sanity.h index 8efa416102..8e5811f1fd 100644 --- a/src/compat/sanity.h +++ b/src/compat/sanity.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/compressor.cpp b/src/compressor.cpp index a161c42866..32af8eab49 100644 --- a/src/compressor.cpp +++ b/src/compressor.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/compressor.h b/src/compressor.h index 00b777a111..0968454679 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/consensus/amount.h b/src/consensus/amount.h index 59b8e3417a..f0eb4e0723 100644 --- a/src/consensus/amount.h +++ b/src/consensus/amount.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/consensus/params.h b/src/consensus/params.h index 77bf7fd0d8..1ed5ca469f 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/consensus/tx_check.cpp b/src/consensus/tx_check.cpp index de4824fadc..f949655909 100644 --- a/src/consensus/tx_check.cpp +++ b/src/consensus/tx_check.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-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. diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp index a07adae536..5738c333ce 100644 --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -1,18 +1,16 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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 <consensus/tx_verify.h> +#include <chain.h> +#include <coins.h> #include <consensus/amount.h> #include <consensus/consensus.h> +#include <consensus/validation.h> #include <primitives/transaction.h> #include <script/interpreter.h> -#include <consensus/validation.h> - -// TODO remove the following dependencies -#include <chain.h> -#include <coins.h> #include <util/moneystr.h> bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h index 777556808a..1209c0faa5 100644 --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 05416d0aca..6027bb9aeb 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/core_io.h b/src/core_io.h index 4d7199ab12..69b9ac3ebd 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/core_read.cpp b/src/core_read.cpp index 484f41f262..3bab5b5d98 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -21,13 +21,15 @@ #include <string> namespace { - -opcodetype ParseOpCode(const std::string& s) +class OpCodeParser { - static std::map<std::string, opcodetype> mapOpNames; +private: + std::map<std::string, opcodetype> mapOpNames; - if (mapOpNames.empty()) { - for (unsigned int op = 0; op <= MAX_OPCODE; op++) { +public: + OpCodeParser() + { + for (unsigned int op = 0; op <= MAX_OPCODE; ++op) { // Allow OP_RESERVED to get into mapOpNames if (op < OP_NOP && op != OP_RESERVED) { continue; @@ -44,10 +46,18 @@ opcodetype ParseOpCode(const std::string& s) } } } + opcodetype Parse(const std::string& s) const + { + auto it = mapOpNames.find(s); + if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode"); + return it->second; + } +}; - auto it = mapOpNames.find(s); - if (it == mapOpNames.end()) throw std::runtime_error("script parse error: unknown opcode"); - return it->second; +opcodetype ParseOpCode(const std::string& s) +{ + static const OpCodeParser ocp; + return ocp.Parse(s); } } // namespace diff --git a/src/core_write.cpp b/src/core_write.cpp index 468694b011..c4b6b8d27e 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -8,6 +8,7 @@ #include <consensus/consensus.h> #include <consensus/validation.h> #include <key_io.h> +#include <script/descriptor.h> #include <script/script.h> #include <script/standard.h> #include <serialize.h> @@ -64,7 +65,7 @@ std::string FormatScript(const CScript& script) ret += strprintf("0x%x ", HexStr(std::vector<uint8_t>(it2, script.end()))); break; } - return ret.substr(0, ret.size() - 1); + return ret.substr(0, ret.empty() ? ret.npos : ret.size() - 1); } const std::map<unsigned char, std::string> mapSigHashTypes = { @@ -152,6 +153,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool include CTxDestination address; out.pushKV("asm", ScriptToAsmStr(scriptPubKey)); + out.pushKV("desc", InferDescriptor(scriptPubKey, DUMMY_SIGNING_PROVIDER)->ToString()); if (include_hex) out.pushKV("hex", HexStr(scriptPubKey)); std::vector<std::vector<unsigned char>> solns; @@ -208,22 +210,17 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, const CTxOut& prev_txout = prev_coin.out; amt_total_in += prev_txout.nValue; - switch (verbosity) { - case TxVerbosity::SHOW_TXID: - case TxVerbosity::SHOW_DETAILS: - break; - case TxVerbosity::SHOW_DETAILS_AND_PREVOUT: - UniValue o_script_pub_key(UniValue::VOBJ); - ScriptPubKeyToUniv(prev_txout.scriptPubKey, o_script_pub_key, /* includeHex */ true); + if (verbosity == TxVerbosity::SHOW_DETAILS_AND_PREVOUT) { + UniValue o_script_pub_key(UniValue::VOBJ); + ScriptPubKeyToUniv(prev_txout.scriptPubKey, o_script_pub_key, /*include_hex=*/ true); - UniValue p(UniValue::VOBJ); - p.pushKV("generated", bool(prev_coin.fCoinBase)); - p.pushKV("height", uint64_t(prev_coin.nHeight)); - p.pushKV("value", ValueFromAmount(prev_txout.nValue)); - p.pushKV("scriptPubKey", o_script_pub_key); - in.pushKV("prevout", p); - break; + UniValue p(UniValue::VOBJ); + p.pushKV("generated", bool(prev_coin.fCoinBase)); + p.pushKV("height", uint64_t(prev_coin.nHeight)); + p.pushKV("value", ValueFromAmount(prev_txout.nValue)); + p.pushKV("scriptPubKey", o_script_pub_key); + in.pushKV("prevout", p); } } in.pushKV("sequence", (int64_t)txin.nSequence); diff --git a/src/crypto/chacha_poly_aead.cpp b/src/crypto/chacha_poly_aead.cpp index b73b22a2b8..4f3e6f7fa3 100644 --- a/src/crypto/chacha_poly_aead.cpp +++ b/src/crypto/chacha_poly_aead.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -73,7 +73,7 @@ bool ChaCha20Poly1305AEAD::Crypt(uint64_t seqnr_payload, uint64_t seqnr_aad, int return false; } memory_cleanse(expected_tag, sizeof(expected_tag)); - // MAC has been successfully verified, make sure we don't covert it in decryption + // MAC has been successfully verified, make sure we don't convert it in decryption src_len -= POLY1305_TAGLEN; } diff --git a/src/crypto/chacha_poly_aead.h b/src/crypto/chacha_poly_aead.h index 6a7998335d..5d57b5a5e2 100644 --- a/src/crypto/chacha_poly_aead.h +++ b/src/crypto/chacha_poly_aead.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/crypto/muhash.cpp b/src/crypto/muhash.cpp index a2b769cd56..57ed357645 100644 --- a/src/crypto/muhash.cpp +++ b/src/crypto/muhash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. diff --git a/src/crypto/muhash.h b/src/crypto/muhash.h index 0c050cd32b..53c5a91a03 100644 --- a/src/crypto/muhash.h +++ b/src/crypto/muhash.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index e35d526d35..cde543e68c 100644 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -10,6 +10,16 @@ #include <compat/cpuid.h> +#if defined(__linux__) && defined(ENABLE_ARM_SHANI) && !defined(BUILD_BITCOIN_INTERNAL) +#include <sys/auxv.h> +#include <asm/hwcap.h> +#endif + +#if defined(MAC_OSX) && defined(ENABLE_ARM_SHANI) && !defined(BUILD_BITCOIN_INTERNAL) +#include <sys/types.h> +#include <sys/sysctl.h> +#endif + #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) #if defined(USE_ASM) namespace sha256_sse4 @@ -29,16 +39,26 @@ namespace sha256d64_avx2 void Transform_8way(unsigned char* out, const unsigned char* in); } -namespace sha256d64_shani +namespace sha256d64_x86_shani { void Transform_2way(unsigned char* out, const unsigned char* in); } -namespace sha256_shani +namespace sha256_x86_shani { void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks); } +namespace sha256_arm_shani +{ +void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks); +} + +namespace sha256d64_arm_shani +{ +void Transform_2way(unsigned char* out, const unsigned char* in); +} + // Internal implementation code. namespace { @@ -567,7 +587,7 @@ std::string SHA256AutoDetect() bool have_xsave = false; bool have_avx = false; bool have_avx2 = false; - bool have_shani = false; + bool have_x86_shani = false; bool enabled_avx = false; (void)AVXEnabled; @@ -575,7 +595,7 @@ std::string SHA256AutoDetect() (void)have_avx; (void)have_xsave; (void)have_avx2; - (void)have_shani; + (void)have_x86_shani; (void)enabled_avx; uint32_t eax, ebx, ecx, edx; @@ -589,15 +609,15 @@ std::string SHA256AutoDetect() if (have_sse4) { GetCPUID(7, 0, eax, ebx, ecx, edx); have_avx2 = (ebx >> 5) & 1; - have_shani = (ebx >> 29) & 1; + have_x86_shani = (ebx >> 29) & 1; } -#if defined(ENABLE_SHANI) && !defined(BUILD_BITCOIN_INTERNAL) - if (have_shani) { - Transform = sha256_shani::Transform; - TransformD64 = TransformD64Wrapper<sha256_shani::Transform>; - TransformD64_2way = sha256d64_shani::Transform_2way; - ret = "shani(1way,2way)"; +#if defined(ENABLE_X86_SHANI) && !defined(BUILD_BITCOIN_INTERNAL) + if (have_x86_shani) { + Transform = sha256_x86_shani::Transform; + TransformD64 = TransformD64Wrapper<sha256_x86_shani::Transform>; + TransformD64_2way = sha256d64_x86_shani::Transform_2way; + ret = "x86_shani(1way,2way)"; have_sse4 = false; // Disable SSE4/AVX2; have_avx2 = false; } @@ -623,6 +643,38 @@ std::string SHA256AutoDetect() #endif #endif +#if defined(ENABLE_ARM_SHANI) && !defined(BUILD_BITCOIN_INTERNAL) + bool have_arm_shani = false; + +#if defined(__linux__) +#if defined(__arm__) // 32-bit + if (getauxval(AT_HWCAP2) & HWCAP2_SHA2) { + have_arm_shani = true; + } +#endif +#if defined(__aarch64__) // 64-bit + if (getauxval(AT_HWCAP) & HWCAP_SHA2) { + have_arm_shani = true; + } +#endif +#endif + +#if defined(MAC_OSX) + int val = 0; + size_t len = sizeof(val); + if (sysctlbyname("hw.optional.arm.FEAT_SHA256", &val, &len, nullptr, 0) == 0) { + have_arm_shani = val != 0; + } +#endif + + if (have_arm_shani) { + Transform = sha256_arm_shani::Transform; + TransformD64 = TransformD64Wrapper<sha256_arm_shani::Transform>; + TransformD64_2way = sha256d64_arm_shani::Transform_2way; + ret = "arm_shani(1way,2way)"; + } +#endif + assert(SelfTest()); return ret; } diff --git a/src/crypto/sha256_arm_shani.cpp b/src/crypto/sha256_arm_shani.cpp new file mode 100644 index 0000000000..2ea1d9c2ac --- /dev/null +++ b/src/crypto/sha256_arm_shani.cpp @@ -0,0 +1,899 @@ +// 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. +// +// Based on https://github.com/noloader/SHA-Intrinsics/blob/master/sha256-arm.c, +// Written and placed in public domain by Jeffrey Walton. +// Based on code from ARM, and by Johannes Schneiders, Skip Hovsmith and +// Barry O'Rourke for the mbedTLS project. +// Variant specialized for 64-byte inputs added by Pieter Wuille. + +#ifdef ENABLE_ARM_SHANI + +#include <array> +#include <cstdint> +#include <cstddef> +#include <arm_acle.h> +#include <arm_neon.h> + +namespace { +alignas(uint32x4_t) static constexpr std::array<uint32_t, 64> K = +{ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, +}; +} + +namespace sha256_arm_shani { +void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks) +{ + uint32x4_t STATE0, STATE1, ABEF_SAVE, CDGH_SAVE; + uint32x4_t MSG0, MSG1, MSG2, MSG3; + uint32x4_t TMP0, TMP2; + + // Load state + STATE0 = vld1q_u32(&s[0]); + STATE1 = vld1q_u32(&s[4]); + + while (blocks--) + { + // Save state + ABEF_SAVE = STATE0; + CDGH_SAVE = STATE1; + + // Load and convert input chunk to Big Endian + MSG0 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 0))); + MSG1 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 16))); + MSG2 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 32))); + MSG3 = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(chunk + 48))); + chunk += 64; + + // Original implementation preloaded message and constant addition which was 1-3% slower. + // Now included as first step in quad round code saving one Q Neon register + // "TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0]));" + + // Rounds 1-4 + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[0])); + TMP2 = STATE0; + MSG0 = vsha256su0q_u32(MSG0, MSG1); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 5-8 + TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[4])); + TMP2 = STATE0; + MSG1 = vsha256su0q_u32(MSG1, MSG2); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 9-12 + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[8])); + TMP2 = STATE0; + MSG2 = vsha256su0q_u32(MSG2, MSG3); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 13-16 + TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[12])); + TMP2 = STATE0; + MSG3 = vsha256su0q_u32(MSG3, MSG0); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 17-20 + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[16])); + TMP2 = STATE0; + MSG0 = vsha256su0q_u32(MSG0, MSG1); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 21-24 + TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[20])); + TMP2 = STATE0; + MSG1 = vsha256su0q_u32(MSG1, MSG2); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 25-28 + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[24])); + TMP2 = STATE0; + MSG2 = vsha256su0q_u32(MSG2, MSG3); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 29-32 + TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[28])); + TMP2 = STATE0; + MSG3 = vsha256su0q_u32(MSG3, MSG0); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 33-36 + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[32])); + TMP2 = STATE0; + MSG0 = vsha256su0q_u32(MSG0, MSG1); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG0 = vsha256su1q_u32(MSG0, MSG2, MSG3); + + // Rounds 37-40 + TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[36])); + TMP2 = STATE0; + MSG1 = vsha256su0q_u32(MSG1, MSG2); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG1 = vsha256su1q_u32(MSG1, MSG3, MSG0); + + // Rounds 41-44 + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[40])); + TMP2 = STATE0; + MSG2 = vsha256su0q_u32(MSG2, MSG3); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG2 = vsha256su1q_u32(MSG2, MSG0, MSG1); + + // Rounds 45-48 + TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[44])); + TMP2 = STATE0; + MSG3 = vsha256su0q_u32(MSG3, MSG0); + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + MSG3 = vsha256su1q_u32(MSG3, MSG1, MSG2); + + // Rounds 49-52 + TMP0 = vaddq_u32(MSG0, vld1q_u32(&K[48])); + TMP2 = STATE0; + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + + // Rounds 53-56 + TMP0 = vaddq_u32(MSG1, vld1q_u32(&K[52])); + TMP2 = STATE0; + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + + // Rounds 57-60 + TMP0 = vaddq_u32(MSG2, vld1q_u32(&K[56])); + TMP2 = STATE0; + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + + // Rounds 61-64 + TMP0 = vaddq_u32(MSG3, vld1q_u32(&K[60])); + TMP2 = STATE0; + STATE0 = vsha256hq_u32(STATE0, STATE1, TMP0); + STATE1 = vsha256h2q_u32(STATE1, TMP2, TMP0); + + // Update state + STATE0 = vaddq_u32(STATE0, ABEF_SAVE); + STATE1 = vaddq_u32(STATE1, CDGH_SAVE); + } + + // Save final state + vst1q_u32(&s[0], STATE0); + vst1q_u32(&s[4], STATE1); +} +} + +namespace sha256d64_arm_shani { +void Transform_2way(unsigned char* output, const unsigned char* input) +{ + /* Initial state. */ + alignas(uint32x4_t) static constexpr std::array<uint32_t, 8> INIT = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + }; + + /* Precomputed message schedule for the 2nd transform. */ + alignas(uint32x4_t) static constexpr std::array<uint32_t, 64> MIDS = { + 0xc28a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf374, + 0x649b69c1, 0xf0fe4786, 0x0fe1edc6, 0x240cf254, + 0x4fe9346f, 0x6cc984be, 0x61b9411e, 0x16f988fa, + 0xf2c65152, 0xa88e5a6d, 0xb019fc65, 0xb9d99ec7, + 0x9a1231c3, 0xe70eeaa0, 0xfdb1232b, 0xc7353eb0, + 0x3069bad5, 0xcb976d5f, 0x5a0f118f, 0xdc1eeefd, + 0x0a35b689, 0xde0b7a04, 0x58f4ca9d, 0xe15d5b16, + 0x007f3e86, 0x37088980, 0xa507ea32, 0x6fab9537, + 0x17406110, 0x0d8cd6f1, 0xcdaa3b6d, 0xc0bbbe37, + 0x83613bda, 0xdb48a363, 0x0b02e931, 0x6fd15ca7, + 0x521afaca, 0x31338431, 0x6ed41a95, 0x6d437890, + 0xc39c91f2, 0x9eccabbd, 0xb5c9a0e6, 0x532fb63c, + 0xd2c741c6, 0x07237ea3, 0xa4954b68, 0x4c191d76 + }; + + /* A few precomputed message schedule values for the 3rd transform. */ + alignas(uint32x4_t) static constexpr std::array<uint32_t, 12> FINS = { + 0x5807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x80000000, 0x00000000, 0x00000000, 0x00000000, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf274 + }; + + /* Padding processed in the 3rd transform (byteswapped). */ + alignas(uint32x4_t) static constexpr std::array<uint32_t, 8> FINAL = {0x80000000, 0, 0, 0, 0, 0, 0, 0x100}; + + uint32x4_t STATE0A, STATE0B, STATE1A, STATE1B, ABEF_SAVEA, ABEF_SAVEB, CDGH_SAVEA, CDGH_SAVEB; + uint32x4_t MSG0A, MSG0B, MSG1A, MSG1B, MSG2A, MSG2B, MSG3A, MSG3B; + uint32x4_t TMP0A, TMP0B, TMP2A, TMP2B, TMP; + + // Transform 1: Load state + STATE0A = vld1q_u32(&INIT[0]); + STATE0B = STATE0A; + STATE1A = vld1q_u32(&INIT[4]); + STATE1B = STATE1A; + + // Transform 1: Load and convert input chunk to Big Endian + MSG0A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 0))); + MSG1A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 16))); + MSG2A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 32))); + MSG3A = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 48))); + MSG0B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 64))); + MSG1B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 80))); + MSG2B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 96))); + MSG3B = vreinterpretq_u32_u8(vrev32q_u8(vld1q_u8(input + 112))); + + // Transform 1: Rounds 1-4 + TMP = vld1q_u32(&K[0]); + TMP0A = vaddq_u32(MSG0A, TMP); + TMP0B = vaddq_u32(MSG0B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG0A = vsha256su0q_u32(MSG0A, MSG1A); + MSG0B = vsha256su0q_u32(MSG0B, MSG1B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A); + MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B); + + // Transform 1: Rounds 5-8 + TMP = vld1q_u32(&K[4]); + TMP0A = vaddq_u32(MSG1A, TMP); + TMP0B = vaddq_u32(MSG1B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG1A = vsha256su0q_u32(MSG1A, MSG2A); + MSG1B = vsha256su0q_u32(MSG1B, MSG2B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A); + MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B); + + // Transform 1: Rounds 9-12 + TMP = vld1q_u32(&K[8]); + TMP0A = vaddq_u32(MSG2A, TMP); + TMP0B = vaddq_u32(MSG2B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG2A = vsha256su0q_u32(MSG2A, MSG3A); + MSG2B = vsha256su0q_u32(MSG2B, MSG3B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A); + MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B); + + // Transform 1: Rounds 13-16 + TMP = vld1q_u32(&K[12]); + TMP0A = vaddq_u32(MSG3A, TMP); + TMP0B = vaddq_u32(MSG3B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG3A = vsha256su0q_u32(MSG3A, MSG0A); + MSG3B = vsha256su0q_u32(MSG3B, MSG0B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A); + MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B); + + // Transform 1: Rounds 17-20 + TMP = vld1q_u32(&K[16]); + TMP0A = vaddq_u32(MSG0A, TMP); + TMP0B = vaddq_u32(MSG0B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG0A = vsha256su0q_u32(MSG0A, MSG1A); + MSG0B = vsha256su0q_u32(MSG0B, MSG1B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A); + MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B); + + // Transform 1: Rounds 21-24 + TMP = vld1q_u32(&K[20]); + TMP0A = vaddq_u32(MSG1A, TMP); + TMP0B = vaddq_u32(MSG1B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG1A = vsha256su0q_u32(MSG1A, MSG2A); + MSG1B = vsha256su0q_u32(MSG1B, MSG2B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A); + MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B); + + // Transform 1: Rounds 25-28 + TMP = vld1q_u32(&K[24]); + TMP0A = vaddq_u32(MSG2A, TMP); + TMP0B = vaddq_u32(MSG2B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG2A = vsha256su0q_u32(MSG2A, MSG3A); + MSG2B = vsha256su0q_u32(MSG2B, MSG3B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A); + MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B); + + // Transform 1: Rounds 29-32 + TMP = vld1q_u32(&K[28]); + TMP0A = vaddq_u32(MSG3A, TMP); + TMP0B = vaddq_u32(MSG3B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG3A = vsha256su0q_u32(MSG3A, MSG0A); + MSG3B = vsha256su0q_u32(MSG3B, MSG0B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A); + MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B); + + // Transform 1: Rounds 33-36 + TMP = vld1q_u32(&K[32]); + TMP0A = vaddq_u32(MSG0A, TMP); + TMP0B = vaddq_u32(MSG0B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG0A = vsha256su0q_u32(MSG0A, MSG1A); + MSG0B = vsha256su0q_u32(MSG0B, MSG1B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A); + MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B); + + // Transform 1: Rounds 37-40 + TMP = vld1q_u32(&K[36]); + TMP0A = vaddq_u32(MSG1A, TMP); + TMP0B = vaddq_u32(MSG1B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG1A = vsha256su0q_u32(MSG1A, MSG2A); + MSG1B = vsha256su0q_u32(MSG1B, MSG2B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A); + MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B); + + // Transform 1: Rounds 41-44 + TMP = vld1q_u32(&K[40]); + TMP0A = vaddq_u32(MSG2A, TMP); + TMP0B = vaddq_u32(MSG2B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG2A = vsha256su0q_u32(MSG2A, MSG3A); + MSG2B = vsha256su0q_u32(MSG2B, MSG3B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A); + MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B); + + // Transform 1: Rounds 45-48 + TMP = vld1q_u32(&K[44]); + TMP0A = vaddq_u32(MSG3A, TMP); + TMP0B = vaddq_u32(MSG3B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG3A = vsha256su0q_u32(MSG3A, MSG0A); + MSG3B = vsha256su0q_u32(MSG3B, MSG0B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A); + MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B); + + // Transform 1: Rounds 49-52 + TMP = vld1q_u32(&K[48]); + TMP0A = vaddq_u32(MSG0A, TMP); + TMP0B = vaddq_u32(MSG0B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + + // Transform 1: Rounds 53-56 + TMP = vld1q_u32(&K[52]); + TMP0A = vaddq_u32(MSG1A, TMP); + TMP0B = vaddq_u32(MSG1B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + + // Transform 1: Rounds 57-60 + TMP = vld1q_u32(&K[56]); + TMP0A = vaddq_u32(MSG2A, TMP); + TMP0B = vaddq_u32(MSG2B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + + // Transform 1: Rounds 61-64 + TMP = vld1q_u32(&K[60]); + TMP0A = vaddq_u32(MSG3A, TMP); + TMP0B = vaddq_u32(MSG3B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + + // Transform 1: Update state + TMP = vld1q_u32(&INIT[0]); + STATE0A = vaddq_u32(STATE0A, TMP); + STATE0B = vaddq_u32(STATE0B, TMP); + TMP = vld1q_u32(&INIT[4]); + STATE1A = vaddq_u32(STATE1A, TMP); + STATE1B = vaddq_u32(STATE1B, TMP); + + // Transform 2: Save state + ABEF_SAVEA = STATE0A; + ABEF_SAVEB = STATE0B; + CDGH_SAVEA = STATE1A; + CDGH_SAVEB = STATE1B; + + // Transform 2: Rounds 1-4 + TMP = vld1q_u32(&MIDS[0]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 5-8 + TMP = vld1q_u32(&MIDS[4]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 9-12 + TMP = vld1q_u32(&MIDS[8]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 13-16 + TMP = vld1q_u32(&MIDS[12]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 17-20 + TMP = vld1q_u32(&MIDS[16]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 21-24 + TMP = vld1q_u32(&MIDS[20]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 25-28 + TMP = vld1q_u32(&MIDS[24]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 29-32 + TMP = vld1q_u32(&MIDS[28]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 33-36 + TMP = vld1q_u32(&MIDS[32]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 37-40 + TMP = vld1q_u32(&MIDS[36]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 41-44 + TMP = vld1q_u32(&MIDS[40]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 45-48 + TMP = vld1q_u32(&MIDS[44]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 49-52 + TMP = vld1q_u32(&MIDS[48]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 53-56 + TMP = vld1q_u32(&MIDS[52]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 57-60 + TMP = vld1q_u32(&MIDS[56]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Rounds 61-64 + TMP = vld1q_u32(&MIDS[60]); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + + // Transform 2: Update state + STATE0A = vaddq_u32(STATE0A, ABEF_SAVEA); + STATE0B = vaddq_u32(STATE0B, ABEF_SAVEB); + STATE1A = vaddq_u32(STATE1A, CDGH_SAVEA); + STATE1B = vaddq_u32(STATE1B, CDGH_SAVEB); + + // Transform 3: Pad previous output + MSG0A = STATE0A; + MSG0B = STATE0B; + MSG1A = STATE1A; + MSG1B = STATE1B; + MSG2A = vld1q_u32(&FINAL[0]); + MSG2B = MSG2A; + MSG3A = vld1q_u32(&FINAL[4]); + MSG3B = MSG3A; + + // Transform 3: Load state + STATE0A = vld1q_u32(&INIT[0]); + STATE0B = STATE0A; + STATE1A = vld1q_u32(&INIT[4]); + STATE1B = STATE1A; + + // Transform 3: Rounds 1-4 + TMP = vld1q_u32(&K[0]); + TMP0A = vaddq_u32(MSG0A, TMP); + TMP0B = vaddq_u32(MSG0B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG0A = vsha256su0q_u32(MSG0A, MSG1A); + MSG0B = vsha256su0q_u32(MSG0B, MSG1B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A); + MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B); + + // Transform 3: Rounds 5-8 + TMP = vld1q_u32(&K[4]); + TMP0A = vaddq_u32(MSG1A, TMP); + TMP0B = vaddq_u32(MSG1B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG1A = vsha256su0q_u32(MSG1A, MSG2A); + MSG1B = vsha256su0q_u32(MSG1B, MSG2B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A); + MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B); + + // Transform 3: Rounds 9-12 + TMP = vld1q_u32(&FINS[0]); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG2A = vld1q_u32(&FINS[4]); + MSG2B = MSG2A; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A); + MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B); + + // Transform 3: Rounds 13-16 + TMP = vld1q_u32(&FINS[8]); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG3A = vsha256su0q_u32(MSG3A, MSG0A); + MSG3B = vsha256su0q_u32(MSG3B, MSG0B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP); + MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A); + MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B); + + // Transform 3: Rounds 17-20 + TMP = vld1q_u32(&K[16]); + TMP0A = vaddq_u32(MSG0A, TMP); + TMP0B = vaddq_u32(MSG0B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG0A = vsha256su0q_u32(MSG0A, MSG1A); + MSG0B = vsha256su0q_u32(MSG0B, MSG1B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A); + MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B); + + // Transform 3: Rounds 21-24 + TMP = vld1q_u32(&K[20]); + TMP0A = vaddq_u32(MSG1A, TMP); + TMP0B = vaddq_u32(MSG1B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG1A = vsha256su0q_u32(MSG1A, MSG2A); + MSG1B = vsha256su0q_u32(MSG1B, MSG2B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A); + MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B); + + // Transform 3: Rounds 25-28 + TMP = vld1q_u32(&K[24]); + TMP0A = vaddq_u32(MSG2A, TMP); + TMP0B = vaddq_u32(MSG2B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG2A = vsha256su0q_u32(MSG2A, MSG3A); + MSG2B = vsha256su0q_u32(MSG2B, MSG3B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A); + MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B); + + // Transform 3: Rounds 29-32 + TMP = vld1q_u32(&K[28]); + TMP0A = vaddq_u32(MSG3A, TMP); + TMP0B = vaddq_u32(MSG3B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG3A = vsha256su0q_u32(MSG3A, MSG0A); + MSG3B = vsha256su0q_u32(MSG3B, MSG0B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A); + MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B); + + // Transform 3: Rounds 33-36 + TMP = vld1q_u32(&K[32]); + TMP0A = vaddq_u32(MSG0A, TMP); + TMP0B = vaddq_u32(MSG0B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG0A = vsha256su0q_u32(MSG0A, MSG1A); + MSG0B = vsha256su0q_u32(MSG0B, MSG1B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG0A = vsha256su1q_u32(MSG0A, MSG2A, MSG3A); + MSG0B = vsha256su1q_u32(MSG0B, MSG2B, MSG3B); + + // Transform 3: Rounds 37-40 + TMP = vld1q_u32(&K[36]); + TMP0A = vaddq_u32(MSG1A, TMP); + TMP0B = vaddq_u32(MSG1B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG1A = vsha256su0q_u32(MSG1A, MSG2A); + MSG1B = vsha256su0q_u32(MSG1B, MSG2B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG1A = vsha256su1q_u32(MSG1A, MSG3A, MSG0A); + MSG1B = vsha256su1q_u32(MSG1B, MSG3B, MSG0B); + + // Transform 3: Rounds 41-44 + TMP = vld1q_u32(&K[40]); + TMP0A = vaddq_u32(MSG2A, TMP); + TMP0B = vaddq_u32(MSG2B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG2A = vsha256su0q_u32(MSG2A, MSG3A); + MSG2B = vsha256su0q_u32(MSG2B, MSG3B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG2A = vsha256su1q_u32(MSG2A, MSG0A, MSG1A); + MSG2B = vsha256su1q_u32(MSG2B, MSG0B, MSG1B); + + // Transform 3: Rounds 45-48 + TMP = vld1q_u32(&K[44]); + TMP0A = vaddq_u32(MSG3A, TMP); + TMP0B = vaddq_u32(MSG3B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + MSG3A = vsha256su0q_u32(MSG3A, MSG0A); + MSG3B = vsha256su0q_u32(MSG3B, MSG0B); + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + MSG3A = vsha256su1q_u32(MSG3A, MSG1A, MSG2A); + MSG3B = vsha256su1q_u32(MSG3B, MSG1B, MSG2B); + + // Transform 3: Rounds 49-52 + TMP = vld1q_u32(&K[48]); + TMP0A = vaddq_u32(MSG0A, TMP); + TMP0B = vaddq_u32(MSG0B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + + // Transform 3: Rounds 53-56 + TMP = vld1q_u32(&K[52]); + TMP0A = vaddq_u32(MSG1A, TMP); + TMP0B = vaddq_u32(MSG1B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + + // Transform 3: Rounds 57-60 + TMP = vld1q_u32(&K[56]); + TMP0A = vaddq_u32(MSG2A, TMP); + TMP0B = vaddq_u32(MSG2B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + + // Transform 3: Rounds 61-64 + TMP = vld1q_u32(&K[60]); + TMP0A = vaddq_u32(MSG3A, TMP); + TMP0B = vaddq_u32(MSG3B, TMP); + TMP2A = STATE0A; + TMP2B = STATE0B; + STATE0A = vsha256hq_u32(STATE0A, STATE1A, TMP0A); + STATE0B = vsha256hq_u32(STATE0B, STATE1B, TMP0B); + STATE1A = vsha256h2q_u32(STATE1A, TMP2A, TMP0A); + STATE1B = vsha256h2q_u32(STATE1B, TMP2B, TMP0B); + + // Transform 3: Update state + TMP = vld1q_u32(&INIT[0]); + STATE0A = vaddq_u32(STATE0A, TMP); + STATE0B = vaddq_u32(STATE0B, TMP); + TMP = vld1q_u32(&INIT[4]); + STATE1A = vaddq_u32(STATE1A, TMP); + STATE1B = vaddq_u32(STATE1B, TMP); + + // Store result + vst1q_u8(output, vrev32q_u8(vreinterpretq_u8_u32(STATE0A))); + vst1q_u8(output + 16, vrev32q_u8(vreinterpretq_u8_u32(STATE1A))); + vst1q_u8(output + 32, vrev32q_u8(vreinterpretq_u8_u32(STATE0B))); + vst1q_u8(output + 48, vrev32q_u8(vreinterpretq_u8_u32(STATE1B))); +} +} + +#endif diff --git a/src/crypto/sha256_sse4.cpp b/src/crypto/sha256_sse4.cpp index 143752c7cf..f1a7fefea3 100644 --- a/src/crypto/sha256_sse4.cpp +++ b/src/crypto/sha256_sse4.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017 The Bitcoin Core developers +// Copyright (c) 2017-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // diff --git a/src/crypto/sha256_shani.cpp b/src/crypto/sha256_x86_shani.cpp index 4f4d5b5837..a82802199f 100644 --- a/src/crypto/sha256_shani.cpp +++ b/src/crypto/sha256_x86_shani.cpp @@ -6,7 +6,7 @@ // Written and placed in public domain by Jeffrey Walton. // Based on code from Intel, and by Sean Gulley for the miTLS project. -#ifdef ENABLE_SHANI +#ifdef ENABLE_X86_SHANI #include <stdint.h> #include <immintrin.h> @@ -74,7 +74,7 @@ void inline __attribute__((always_inline)) Save(unsigned char* out, __m128i s) } } -namespace sha256_shani { +namespace sha256_x86_shani { void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks) { __m128i m0, m1, m2, m3, s0, s1, so0, so1; @@ -139,7 +139,7 @@ void Transform(uint32_t* s, const unsigned char* chunk, size_t blocks) } } -namespace sha256d64_shani { +namespace sha256d64_x86_shani { void Transform_2way(unsigned char* out, const unsigned char* in) { diff --git a/src/cuckoocache.h b/src/cuckoocache.h index 15cb55c3ce..d0dc61c7e6 100644 --- a/src/cuckoocache.h +++ b/src/cuckoocache.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_CUCKOOCACHE_H #define BITCOIN_CUCKOOCACHE_H +#include <util/fastrange.h> + #include <algorithm> // std::find #include <array> #include <atomic> @@ -219,13 +221,8 @@ private: * One option would be to implement the same trick the compiler uses and compute the * constants for exact division based on the size, as described in "{N}-bit Unsigned * Division via {N}-bit Multiply-Add" by Arch D. Robison in 2005. But that code is - * somewhat complicated and the result is still slower than other options: - * - * Instead we treat the 32-bit random number as a Q32 fixed-point number in the range - * [0, 1) and simply multiply it by the size. Then we just shift the result down by - * 32-bits to get our bucket number. The result has non-uniformity the same as a - * mod, but it is much faster to compute. More about this technique can be found at - * https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ . + * somewhat complicated and the result is still slower than an even simpler option: + * see the FastRange32 function in util/fastrange.h. * * The resulting non-uniformity is also more equally distributed which would be * advantageous for something like linear probing, though it shouldn't matter @@ -241,14 +238,14 @@ private: */ inline std::array<uint32_t, 8> compute_hashes(const Element& e) const { - return {{(uint32_t)(((uint64_t)hash_function.template operator()<0>(e) * (uint64_t)size) >> 32), - (uint32_t)(((uint64_t)hash_function.template operator()<1>(e) * (uint64_t)size) >> 32), - (uint32_t)(((uint64_t)hash_function.template operator()<2>(e) * (uint64_t)size) >> 32), - (uint32_t)(((uint64_t)hash_function.template operator()<3>(e) * (uint64_t)size) >> 32), - (uint32_t)(((uint64_t)hash_function.template operator()<4>(e) * (uint64_t)size) >> 32), - (uint32_t)(((uint64_t)hash_function.template operator()<5>(e) * (uint64_t)size) >> 32), - (uint32_t)(((uint64_t)hash_function.template operator()<6>(e) * (uint64_t)size) >> 32), - (uint32_t)(((uint64_t)hash_function.template operator()<7>(e) * (uint64_t)size) >> 32)}}; + return {{FastRange32(hash_function.template operator()<0>(e), size), + FastRange32(hash_function.template operator()<1>(e), size), + FastRange32(hash_function.template operator()<2>(e), size), + FastRange32(hash_function.template operator()<3>(e), size), + FastRange32(hash_function.template operator()<4>(e), size), + FastRange32(hash_function.template operator()<5>(e), size), + FastRange32(hash_function.template operator()<6>(e), size), + FastRange32(hash_function.template operator()<7>(e), size)}}; } /** invalid returns a special index that can never be inserted to diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index dbae2c45f2..b0ea80ea1a 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2019 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/dbwrapper.h b/src/dbwrapper.h index c119036db2..1109cb5888 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -147,7 +147,7 @@ public: template<typename K> bool GetKey(K& key) { leveldb::Slice slKey = piter->key(); try { - CDataStream ssKey(MakeUCharSpan(slKey), SER_DISK, CLIENT_VERSION); + CDataStream ssKey{MakeByteSpan(slKey), SER_DISK, CLIENT_VERSION}; ssKey >> key; } catch (const std::exception&) { return false; @@ -158,7 +158,7 @@ public: template<typename V> bool GetValue(V& value) { leveldb::Slice slValue = piter->value(); try { - CDataStream ssValue(MakeUCharSpan(slValue), SER_DISK, CLIENT_VERSION); + CDataStream ssValue{MakeByteSpan(slValue), SER_DISK, CLIENT_VERSION}; ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); ssValue >> value; } catch (const std::exception&) { @@ -244,7 +244,7 @@ public: dbwrapper_private::HandleError(status); } try { - CDataStream ssValue(MakeUCharSpan(strValue), SER_DISK, CLIENT_VERSION); + CDataStream ssValue{MakeByteSpan(strValue), SER_DISK, CLIENT_VERSION}; ssValue.Xor(obfuscate_key); ssValue >> value; } catch (const std::exception&) { diff --git a/src/deploymentinfo.cpp b/src/deploymentinfo.cpp index 030a7806de..246932e56d 100644 --- a/src/deploymentinfo.cpp +++ b/src/deploymentinfo.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/deploymentinfo.h b/src/deploymentinfo.h index 63d58a7da2..8b909dedb4 100644 --- a/src/deploymentinfo.h +++ b/src/deploymentinfo.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2018 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/deploymentstatus.cpp b/src/deploymentstatus.cpp index bba86639a3..ae19a6e40d 100644 --- a/src/deploymentstatus.cpp +++ b/src/deploymentstatus.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/deploymentstatus.h b/src/deploymentstatus.h index f95c5996f5..ba5103de74 100644 --- a/src/deploymentstatus.h +++ b/src/deploymentstatus.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index 7f6471740f..2b94ed611b 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -6,13 +6,12 @@ #include <walletinitinterface.h> class ArgsManager; -class CWallet; namespace interfaces { class Chain; class Handler; class Wallet; -class WalletClient; +class WalletLoader; } class DummyWalletInit : public WalletInitInterface { @@ -21,7 +20,7 @@ public: bool HasWalletSupport() const override {return false;} void AddWalletOptions(ArgsManager& argsman) const override; bool ParameterInteraction() const override {return true;} - void Construct(NodeContext& node) const override {LogPrintf("No wallet support compiled in!\n");} + void Construct(node::NodeContext& node) const override {LogPrintf("No wallet support compiled in!\n");} }; void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const @@ -59,12 +58,7 @@ const WalletInitInterface& g_wallet_init_interface = DummyWalletInit(); namespace interfaces { -std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) -{ - throw std::logic_error("Wallet function called in non-wallet build."); -} - -std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args) +std::unique_ptr<WalletLoader> MakeWalletLoader(Chain& chain, ArgsManager& args) { throw std::logic_error("Wallet function called in non-wallet build."); } diff --git a/src/flatfile.cpp b/src/flatfile.cpp index 929808c7fa..d6cada0c46 100644 --- a/src/flatfile.cpp +++ b/src/flatfile.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/fs.cpp b/src/fs.cpp index 7a99444eef..219fdee959 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -7,7 +7,6 @@ #ifndef WIN32 #include <cstring> #include <fcntl.h> -#include <string> #include <sys/file.h> #include <sys/utsname.h> #include <unistd.h> @@ -20,6 +19,9 @@ #include <windows.h> #endif +#include <cassert> +#include <string> + namespace fsbridge { FILE *fopen(const fs::path& p, const char *mode) @@ -35,7 +37,7 @@ FILE *fopen(const fs::path& p, const char *mode) fs::path AbsPathJoin(const fs::path& base, const fs::path& path) { assert(base.is_absolute()); - return fs::absolute(path, base); + return path.empty() ? base : fs::path(base / path); } #ifndef WIN32 @@ -151,118 +153,4 @@ std::string get_filesystem_error_message(const fs::filesystem_error& e) #endif } -#ifdef WIN32 -#ifdef __GLIBCXX__ - -// reference: https://github.com/gcc-mirror/gcc/blob/gcc-7_3_0-release/libstdc%2B%2B-v3/include/std/fstream#L270 -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wswitch" -#endif -static std::string openmodeToStr(std::ios_base::openmode mode) -{ - switch (mode & ~std::ios_base::ate) { - case std::ios_base::out: - case std::ios_base::out | std::ios_base::trunc: - return "w"; - case std::ios_base::out | std::ios_base::app: - case std::ios_base::app: - return "a"; - case std::ios_base::in: - return "r"; - case std::ios_base::in | std::ios_base::out: - return "r+"; - case std::ios_base::in | std::ios_base::out | std::ios_base::trunc: - return "w+"; - case std::ios_base::in | std::ios_base::out | std::ios_base::app: - case std::ios_base::in | std::ios_base::app: - return "a+"; - case std::ios_base::out | std::ios_base::binary: - case std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: - return "wb"; - case std::ios_base::out | std::ios_base::app | std::ios_base::binary: - case std::ios_base::app | std::ios_base::binary: - return "ab"; - case std::ios_base::in | std::ios_base::binary: - return "rb"; - case std::ios_base::in | std::ios_base::out | std::ios_base::binary: - return "r+b"; - case std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary: - return "w+b"; - case std::ios_base::in | std::ios_base::out | std::ios_base::app | std::ios_base::binary: - case std::ios_base::in | std::ios_base::app | std::ios_base::binary: - return "a+b"; - default: - return std::string(); - } -} -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - -void ifstream::open(const fs::path& p, std::ios_base::openmode mode) -{ - close(); - mode |= std::ios_base::in; - m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str()); - if (m_file == nullptr) { - return; - } - m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode); - rdbuf(&m_filebuf); - if (mode & std::ios_base::ate) { - seekg(0, std::ios_base::end); - } -} - -void ifstream::close() -{ - if (m_file != nullptr) { - m_filebuf.close(); - fclose(m_file); - } - m_file = nullptr; -} - -void ofstream::open(const fs::path& p, std::ios_base::openmode mode) -{ - close(); - mode |= std::ios_base::out; - m_file = fsbridge::fopen(p, openmodeToStr(mode).c_str()); - if (m_file == nullptr) { - return; - } - m_filebuf = __gnu_cxx::stdio_filebuf<char>(m_file, mode); - rdbuf(&m_filebuf); - if (mode & std::ios_base::ate) { - seekp(0, std::ios_base::end); - } -} - -void ofstream::close() -{ - if (m_file != nullptr) { - m_filebuf.close(); - fclose(m_file); - } - m_file = nullptr; -} -#else // __GLIBCXX__ - -#if BOOST_VERSION >= 107700 -static_assert(sizeof(*BOOST_FILESYSTEM_C_STR(boost::filesystem::path())) == sizeof(wchar_t), -#else -static_assert(sizeof(*boost::filesystem::path().BOOST_FILESYSTEM_C_STR) == sizeof(wchar_t), -#endif // BOOST_VERSION >= 107700 - "Warning: This build is using boost::filesystem ofstream and ifstream " - "implementations which will fail to open paths containing multibyte " - "characters. You should delete this static_assert to ignore this warning, " - "or switch to a different C++ standard library like the Microsoft C++ " - "Standard Library (where boost uses non-standard extensions to construct " - "stream objects with wide filenames), or the GNU libstdc++ library (where " - "a more complicated workaround has been implemented above)."); - -#endif // __GLIBCXX__ -#endif // WIN32 - } // fsbridge @@ -1,50 +1,46 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-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. #ifndef BITCOIN_FS_H #define BITCOIN_FS_H -#include <stdio.h> -#include <string> -#if defined WIN32 && defined __GLIBCXX__ -#include <ext/stdio_filebuf.h> -#endif - -#include <boost/filesystem.hpp> -#include <boost/filesystem/fstream.hpp> #include <tinyformat.h> +#include <cstdio> +#include <filesystem> +#include <iomanip> +#include <ios> +#include <ostream> +#include <string> +#include <utility> + /** Filesystem operations and types */ namespace fs { -using namespace boost::filesystem; +using namespace std::filesystem; /** - * Path class wrapper to prepare application code for transition from - * boost::filesystem library to std::filesystem implementation. The main - * purpose of the class is to define fs::path::u8string() and fs::u8path() - * functions not present in boost. It also blocks calls to the - * fs::path(std::string) implicit constructor and the fs::path::string() - * method, which worked well in the boost::filesystem implementation, but have - * unsafe and unpredictable behavior on Windows in the std::filesystem - * implementation (see implementation note in \ref PathToString for details). + * Path class wrapper to block calls to the fs::path(std::string) implicit + * constructor and the fs::path::string() method, which have unsafe and + * unpredictable behavior on Windows (see implementation note in + * \ref PathToString for details) */ -class path : public boost::filesystem::path +class path : public std::filesystem::path { public: - using boost::filesystem::path::path; + using std::filesystem::path::path; // Allow path objects arguments for compatibility. - path(boost::filesystem::path path) : boost::filesystem::path::path(std::move(path)) {} - path& operator=(boost::filesystem::path path) { boost::filesystem::path::operator=(std::move(path)); return *this; } - path& operator/=(boost::filesystem::path path) { boost::filesystem::path::operator/=(std::move(path)); return *this; } + path(std::filesystem::path path) : std::filesystem::path::path(std::move(path)) {} + path& operator=(std::filesystem::path path) { std::filesystem::path::operator=(std::move(path)); return *this; } + path& operator/=(std::filesystem::path path) { std::filesystem::path::operator/=(std::move(path)); return *this; } // Allow literal string arguments, which are safe as long as the literals are ASCII. - path(const char* c) : boost::filesystem::path(c) {} - path& operator=(const char* c) { boost::filesystem::path::operator=(c); return *this; } - path& operator/=(const char* c) { boost::filesystem::path::operator/=(c); return *this; } - path& append(const char* c) { boost::filesystem::path::append(c); return *this; } + path(const char* c) : std::filesystem::path(c) {} + path& operator=(const char* c) { std::filesystem::path::operator=(c); return *this; } + path& operator/=(const char* c) { std::filesystem::path::operator/=(c); return *this; } + path& append(const char* c) { std::filesystem::path::append(c); return *this; } // Disallow std::string arguments to avoid locale-dependent decoding on windows. path(std::string) = delete; @@ -55,34 +51,30 @@ public: // Disallow std::string conversion method to avoid locale-dependent encoding on windows. std::string string() const = delete; - // Define UTF-8 string conversion method not present in boost::filesystem but present in std::filesystem. - std::string u8string() const { return boost::filesystem::path::string(); } + // Required for path overloads in <fstream>. + // See https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=96e0367ead5d8dcac3bec2865582e76e2fbab190 + path& make_preferred() { std::filesystem::path::make_preferred(); return *this; } + path filename() const { return std::filesystem::path::filename(); } }; -// Define UTF-8 string conversion function not present in boost::filesystem but present in std::filesystem. -static inline path u8path(const std::string& string) -{ - return boost::filesystem::path(string); -} - -// Disallow implicit std::string conversion for system_complete to avoid +// Disallow implicit std::string conversion for absolute to avoid // locale-dependent encoding on windows. -static inline path system_complete(const path& p) +static inline path absolute(const path& p) { - return boost::filesystem::system_complete(p); + return std::filesystem::absolute(p); } // Disallow implicit std::string conversion for exists to avoid // locale-dependent encoding on windows. static inline bool exists(const path& p) { - return boost::filesystem::exists(p); + return std::filesystem::exists(p); } // Allow explicit quoted stream I/O. static inline auto quoted(const std::string& s) { - return boost::io::quoted(s, '&'); + return std::quoted(s, '"', '&'); } // Allow safe path append operations. @@ -92,8 +84,15 @@ static inline path operator+(path p1, path p2) return p1; } +// Disallow implicit std::string conversion for copy_file +// to avoid locale-dependent encoding on Windows. +static inline bool copy_file(const path& from, const path& to, copy_options options) +{ + return std::filesystem::copy_file(from, to, options); +} + /** - * Convert path object to byte string. On POSIX, paths natively are byte + * Convert path object to a byte string. On POSIX, paths natively are byte * strings, so this is trivial. On Windows, paths natively are Unicode, so an * encoding step is necessary. The inverse of \ref PathToString is \ref * PathFromString. The strings returned and parsed by these functions can be @@ -105,7 +104,7 @@ static inline path operator+(path p1, path p2) * appropriate to use in applications requiring UTF-8, where * fs::path::u8string() and fs::u8path() methods should be used instead. Other * applications could require still different encodings. For example, JSON, XML, - * or URI applications might prefer to use higher level escapes (\uXXXX or + * or URI applications might prefer to use higher-level escapes (\uXXXX or * &XXXX; or %XX) instead of multibyte encoding. Rust, Python, Java applications * may require encoding paths with their respective UTF-8 derivatives WTF-8, * PEP-383, and CESU-8 (see https://en.wikipedia.org/wiki/UTF-8#Derivatives). @@ -126,7 +125,7 @@ static inline std::string PathToString(const path& path) return path.u8string(); #else static_assert(std::is_same<path::string_type, std::string>::value, "PathToString not implemented on this platform"); - return path.boost::filesystem::path::string(); + return path.std::filesystem::path::string(); #endif } @@ -138,7 +137,7 @@ static inline path PathFromString(const std::string& string) #ifdef WIN32 return u8path(string); #else - return boost::filesystem::path(string); + return std::filesystem::path(string); #endif } } // namespace fs @@ -179,60 +178,12 @@ namespace fsbridge { }; std::string get_filesystem_error_message(const fs::filesystem_error& e); - - // GNU libstdc++ specific workaround for opening UTF-8 paths on Windows. - // - // On Windows, it is only possible to reliably access multibyte file paths through - // `wchar_t` APIs, not `char` APIs. But because the C++ standard doesn't - // require ifstream/ofstream `wchar_t` constructors, and the GNU library doesn't - // provide them (in contrast to the Microsoft C++ library, see - // https://stackoverflow.com/questions/821873/how-to-open-an-stdfstream-ofstream-or-ifstream-with-a-unicode-filename/822032#822032), - // Boost is forced to fall back to `char` constructors which may not work properly. - // - // Work around this issue by creating stream objects with `_wfopen` in - // combination with `__gnu_cxx::stdio_filebuf`. This workaround can be removed - // with an upgrade to C++17, where streams can be constructed directly from - // `std::filesystem::path` objects. - -#if defined WIN32 && defined __GLIBCXX__ - class ifstream : public std::istream - { - public: - ifstream() = default; - explicit ifstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in) { open(p, mode); } - ~ifstream() { close(); } - void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::in); - bool is_open() { return m_filebuf.is_open(); } - void close(); - - private: - __gnu_cxx::stdio_filebuf<char> m_filebuf; - FILE* m_file = nullptr; - }; - class ofstream : public std::ostream - { - public: - ofstream() = default; - explicit ofstream(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out) { open(p, mode); } - ~ofstream() { close(); } - void open(const fs::path& p, std::ios_base::openmode mode = std::ios_base::out); - bool is_open() { return m_filebuf.is_open(); } - void close(); - - private: - __gnu_cxx::stdio_filebuf<char> m_filebuf; - FILE* m_file = nullptr; - }; -#else // !(WIN32 && __GLIBCXX__) - typedef fs::ifstream ifstream; - typedef fs::ofstream ofstream; -#endif // WIN32 && __GLIBCXX__ }; // Disallow path operator<< formatting in tinyformat to avoid locale-dependent // encoding on windows. namespace tinyformat { -template<> inline void formatValue(std::ostream&, const char*, const char*, int, const boost::filesystem::path&) = delete; +template<> inline void formatValue(std::ostream&, const char*, const char*, int, const std::filesystem::path&) = delete; template<> inline void formatValue(std::ostream&, const char*, const char*, int, const fs::path&) = delete; } // namespace tinyformat diff --git a/src/hash.cpp b/src/hash.cpp index 0e5bd975e4..f58b29e3ba 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2020 The Bitcoin Core developers +// Copyright (c) 2013-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. diff --git a/src/hash.h b/src/hash.h index 1456a899d8..9f582842c1 100644 --- a/src/hash.h +++ b/src/hash.h @@ -111,8 +111,9 @@ public: int GetType() const { return nType; } int GetVersion() const { return nVersion; } - void write(const char *pch, size_t size) { - ctx.Write((const unsigned char*)pch, size); + void write(Span<const std::byte> src) + { + ctx.Write(UCharCast(src.data()), src.size()); } /** Compute the double-SHA256 hash of all data written to this object. @@ -162,18 +163,18 @@ private: public: explicit CHashVerifier(Source* source_) : CHashWriter(source_->GetType(), source_->GetVersion()), source(source_) {} - void read(char* pch, size_t nSize) + void read(Span<std::byte> dst) { - source->read(pch, nSize); - this->write(pch, nSize); + source->read(dst); + this->write(dst); } void ignore(size_t nSize) { - char data[1024]; + std::byte data[1024]; while (nSize > 0) { size_t now = std::min<size_t>(nSize, 1024); - read(data, now); + read({data, now}); nSize -= now; } } diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 9ae592be79..5d0b59f7cb 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. diff --git a/src/httprpc.h b/src/httprpc.h index 6daf7d28f5..404d13083f 100644 --- a/src/httprpc.h +++ b/src/httprpc.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 6e75e28596..e00c68585e 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -1,7 +1,11 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + #include <httpserver.h> #include <chainparamsbase.h> @@ -597,7 +601,13 @@ CService HTTPRequest::GetPeer() const // evhttp retains ownership over returned address string const char* address = ""; uint16_t port = 0; + +#ifdef HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR + evhttp_connection_get_peer(con, &address, &port); +#else evhttp_connection_get_peer(con, (char**)&address, &port); +#endif // HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR + peer = LookupNumeric(address, port); } return peer; diff --git a/src/i2p.cpp b/src/i2p.cpp index 35ac8731f2..ccba14d63d 100644 --- a/src/i2p.cpp +++ b/src/i2p.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/index/base.cpp b/src/index/base.cpp index 9d5c68d69e..8fe30f8960 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -14,6 +14,8 @@ #include <validation.h> // For g_chainman #include <warnings.h> +using node::ReadBlockFromDisk; + constexpr uint8_t DB_BEST_BLOCK{'B'}; constexpr int64_t SYNC_LOG_INTERVAL = 30; // seconds @@ -209,6 +211,11 @@ bool BaseIndex::Commit() 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; + } GetDB().WriteBestBlock(batch, m_chainstate->m_chain.GetLocator(m_best_block_index)); return true; } diff --git a/src/index/base.h b/src/index/base.h index 1390e3e570..66149686f0 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp index b485776732..4f99eddfd7 100644 --- a/src/index/blockfilterindex.cpp +++ b/src/index/blockfilterindex.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -9,6 +9,8 @@ #include <node/blockstorage.h> #include <util/system.h> +using node::UndoReadFromDisk; + /* The index database stores three items for each block: the disk location of the encoded filter, * its dSHA256 hash, and the header. Those belonging to blocks on the active chain are indexed by * height, and those belonging to blocks that have been reorganized out of the active chain are diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h index 221ac02c9e..a049019c02 100644 --- a/src/index/blockfilterindex.h +++ b/src/index/blockfilterindex.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp index 9ab9209ca4..7d4860b20b 100644 --- a/src/index/coinstatsindex.cpp +++ b/src/index/coinstatsindex.cpp @@ -12,6 +12,12 @@ #include <undo.h> #include <validation.h> +using node::CCoinsStats; +using node::GetBogoSize; +using node::ReadBlockFromDisk; +using node::TxOutSer; +using node::UndoReadFromDisk; + static constexpr uint8_t DB_BLOCK_HASH{'s'}; static constexpr uint8_t DB_BLOCK_HEIGHT{'t'}; static constexpr uint8_t DB_MUHASH{'M'}; @@ -321,7 +327,7 @@ bool CoinStatsIndex::LookUpStats(const CBlockIndex* block_index, CCoinsStats& co coins_stats.hashSerialized = entry.muhash; coins_stats.nTransactionOutputs = entry.transaction_output_count; coins_stats.nBogoSize = entry.bogo_size; - coins_stats.nTotalAmount = entry.total_amount; + coins_stats.total_amount = entry.total_amount; coins_stats.total_subsidy = entry.total_subsidy; coins_stats.total_unspendable_amount = entry.total_unspendable_amount; coins_stats.total_prevout_spent_amount = entry.total_prevout_spent_amount; @@ -354,9 +360,9 @@ bool CoinStatsIndex::Init() if (pindex) { DBVal entry; if (!LookUpOne(*m_db, pindex, entry)) { - return false; + return error("%s: Cannot read current %s state; index may be corrupted", + __func__, GetName()); } - m_transaction_output_count = entry.transaction_output_count; m_bogo_size = entry.bogo_size; m_total_amount = entry.total_amount; diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h index a575b37c7c..d2a6c9c964 100644 --- a/src/index/coinstatsindex.h +++ b/src/index/coinstatsindex.h @@ -52,7 +52,7 @@ public: explicit CoinStatsIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false); // Look up stats for a specific block using CBlockIndex - bool LookUpStats(const CBlockIndex* block_index, CCoinsStats& coins_stats) const; + bool LookUpStats(const CBlockIndex* block_index, node::CCoinsStats& coins_stats) const; }; /// The global UTXO set hash object. diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index 209785d487..e1d807f39a 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -9,6 +9,8 @@ #include <util/system.h> #include <validation.h> +using node::OpenBlockFile; + constexpr uint8_t DB_TXINDEX{'t'}; std::unique_ptr<TxIndex> g_txindex; @@ -57,7 +59,9 @@ bool TxIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex) // Exclude genesis block transaction because outputs are not spendable. if (pindex->nHeight == 0) return true; - CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); + CDiskTxPos pos{ + WITH_LOCK(::cs_main, return pindex->GetBlockPos()), + GetSizeOfCompactSize(block.vtx.size())}; std::vector<std::pair<uint256, CDiskTxPos>> vPos; vPos.reserve(block.vtx.size()); for (const auto& tx : block.vtx) { diff --git a/src/index/txindex.h b/src/index/txindex.h index 59375bc204..2bbc602631 100644 --- a/src/index/txindex.h +++ b/src/index/txindex.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2018 The Bitcoin Core developers +// Copyright (c) 2017-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. diff --git a/src/init.cpp b/src/init.cpp index 1f4537a975..6aef1f8149 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -72,10 +72,13 @@ #include <validationinterface.h> #include <walletinitinterface.h> +#include <condition_variable> +#include <cstdint> +#include <cstdio> +#include <fstream> #include <functional> #include <set> -#include <stdint.h> -#include <stdio.h> +#include <string> #include <thread> #include <vector> @@ -95,6 +98,22 @@ #include <zmq/zmqrpc.h> #endif +using node::CacheSizes; +using node::CalculateCacheSizes; +using node::ChainstateLoadVerifyError; +using node::ChainstateLoadingError; +using node::CleanupBlockRevFiles; +using node::DEFAULT_PRINTPRIORITY; +using node::DEFAULT_STOPAFTERBLOCKIMPORT; +using node::LoadChainstate; +using node::NodeContext; +using node::ThreadImport; +using node::VerifyLoadedChainstate; +using node::fHavePruned; +using node::fPruneMode; +using node::fReindex; +using node::nPruneTarget; + static const bool DEFAULT_PROXYRANDOMIZE = true; static const bool DEFAULT_REST_ENABLE = false; @@ -121,7 +140,7 @@ static fs::path GetPidFile(const ArgsManager& args) [[nodiscard]] static bool CreatePidFile(const ArgsManager& args) { - fsbridge::ofstream file{GetPidFile(args)}; + std::ofstream file{GetPidFile(args)}; if (file) { #ifdef WIN32 tfm::format(file, "%d\n", GetCurrentProcessId()); @@ -1115,7 +1134,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) auto opt_max_upload = ParseByteUnits(args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET), ByteUnit::M); if (!opt_max_upload) { - return InitError(strprintf(_("Unable to parse -maxuploadtarget: '%s' (possible integer overflow?)"), args.GetArg("-maxuploadtarget", ""))); + return InitError(strprintf(_("Unable to parse -maxuploadtarget: '%s'"), args.GetArg("-maxuploadtarget", ""))); } // ********************************************************* Step 4a: application initialization @@ -1131,7 +1150,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD); // Warn about relative -datadir path. - if (args.IsArgSet("-datadir") && !fs::PathFromString(args.GetArg("-datadir", "")).is_absolute()) { + if (args.IsArgSet("-datadir") && !args.GetPathArg("-datadir").is_absolute()) { LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */ "current working directory '%s'. This is fragile, because if bitcoin is started in the future " "from a different location, it will be unable to locate the current data files. There could " @@ -1404,31 +1423,31 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) uiInterface.InitMessage(_("Loading block index…").translated); const int64_t load_block_index_start_time = GetTimeMillis(); - std::optional<ChainstateLoadingError> rv; + std::optional<ChainstateLoadingError> maybe_load_error; try { - rv = LoadChainstate(fReset, - chainman, - Assert(node.mempool.get()), - fPruneMode, - chainparams.GetConsensus(), - fReindexChainState, - cache_sizes.block_tree_db, - cache_sizes.coins_db, - cache_sizes.coins, - false, - false, - ShutdownRequested, - []() { - uiInterface.ThreadSafeMessageBox( - _("Error reading from database, shutting down."), - "", CClientUIInterface::MSG_ERROR); - }); + maybe_load_error = LoadChainstate(fReset, + chainman, + Assert(node.mempool.get()), + fPruneMode, + chainparams.GetConsensus(), + 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()); - rv = ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED; + maybe_load_error = ChainstateLoadingError::ERROR_GENERIC_BLOCKDB_OPEN_FAILED; } - if (rv.has_value()) { - switch (rv.value()) { + if (maybe_load_error.has_value()) { + switch (maybe_load_error.value()) { case ChainstateLoadingError::ERROR_LOADING_BLOCK_DB: strLoadError = _("Error loading block database"); break; @@ -1462,7 +1481,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) break; } } else { - std::optional<ChainstateLoadVerifyError> rv2; + std::optional<ChainstateLoadVerifyError> maybe_verify_error; try { uiInterface.InitMessage(_("Verifying blocks…").translated); auto check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS); @@ -1470,19 +1489,19 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n", MIN_BLOCKS_TO_KEEP); } - rv2 = VerifyLoadedChainstate(chainman, - fReset, - fReindexChainState, - chainparams.GetConsensus(), - check_blocks, - args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL), - static_cast<int64_t(*)()>(GetTime)); + maybe_verify_error = VerifyLoadedChainstate(chainman, + fReset, + fReindexChainState, + chainparams.GetConsensus(), + check_blocks, + args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL), + /*get_unix_time_seconds=*/static_cast<int64_t(*)()>(GetTime)); } catch (const std::exception& e) { LogPrintf("%s\n", e.what()); - rv2 = ChainstateLoadVerifyError::ERROR_GENERIC_FAILURE; + maybe_verify_error = ChainstateLoadVerifyError::ERROR_GENERIC_FAILURE; } - if (rv2.has_value()) { - switch (rv2.value()) { + 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. " diff --git a/src/init.h b/src/init.h index 5af6930a16..1292cc1a3a 100644 --- a/src/init.h +++ b/src/init.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -16,14 +16,16 @@ static constexpr bool DEFAULT_DAEMON = false; static constexpr bool DEFAULT_DAEMONWAIT = false; class ArgsManager; -struct NodeContext; namespace interfaces { struct BlockAndHeaderTipInfo; } +namespace node { +struct NodeContext; +} // namespace node /** Interrupt threads */ -void Interrupt(NodeContext& node); -void Shutdown(NodeContext& node); +void Interrupt(node::NodeContext& node); +void Shutdown(node::NodeContext& node); //!Initialize the logging infrastructure void InitLogging(const ArgsManager& args); //!Parameter interaction: change current parameters depending on various rules @@ -55,13 +57,13 @@ bool AppInitLockDataDirectory(); /** * Initialize node and wallet interface pointers. Has no prerequisites or side effects besides allocating memory. */ -bool AppInitInterfaces(NodeContext& node); +bool AppInitInterfaces(node::NodeContext& node); /** * Bitcoin core main initialization. * @note This should only be done after daemonization. Call Shutdown() if this function fails. * @pre Parameters should be parsed and config file should be read, AppInitLockDataDirectory should have been called. */ -bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info = nullptr); +bool AppInitMain(node::NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info = nullptr); /** * Register all arguments with the ArgsManager diff --git a/src/init/bitcoin-gui.cpp b/src/init/bitcoin-gui.cpp index c549ed3cc0..e297b48718 100644 --- a/src/init/bitcoin-gui.cpp +++ b/src/init/bitcoin-gui.cpp @@ -27,13 +27,13 @@ public: } std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); } std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); } - std::unique_ptr<interfaces::WalletClient> makeWalletClient(interfaces::Chain& chain) override + std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override { - return MakeWalletClient(chain, *Assert(m_node.args)); + return MakeWalletLoader(chain, *Assert(m_node.args)); } std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); } interfaces::Ipc* ipc() override { return m_ipc.get(); } - NodeContext m_node; + node::NodeContext m_node; std::unique_ptr<interfaces::Ipc> m_ipc; }; } // namespace diff --git a/src/init/bitcoin-node.cpp b/src/init/bitcoin-node.cpp index fa56153745..511a872bc0 100644 --- a/src/init/bitcoin-node.cpp +++ b/src/init/bitcoin-node.cpp @@ -20,7 +20,7 @@ const char* EXE_NAME = "bitcoin-node"; class BitcoinNodeInit : public interfaces::Init { public: - BitcoinNodeInit(NodeContext& node, const char* arg0) + BitcoinNodeInit(node::NodeContext& node, const char* arg0) : m_node(node), m_ipc(interfaces::MakeIpc(EXE_NAME, arg0, *this)) { @@ -29,20 +29,20 @@ public: } std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); } std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); } - std::unique_ptr<interfaces::WalletClient> makeWalletClient(interfaces::Chain& chain) override + std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override { - return MakeWalletClient(chain, *Assert(m_node.args)); + return MakeWalletLoader(chain, *Assert(m_node.args)); } std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); } interfaces::Ipc* ipc() override { return m_ipc.get(); } - NodeContext& m_node; + node::NodeContext& m_node; std::unique_ptr<interfaces::Ipc> m_ipc; }; } // namespace } // namespace init namespace interfaces { -std::unique_ptr<Init> MakeNodeInit(NodeContext& node, int argc, char* argv[], int& exit_status) +std::unique_ptr<Init> MakeNodeInit(node::NodeContext& node, int argc, char* argv[], int& exit_status) { auto init = std::make_unique<init::BitcoinNodeInit>(node, argc > 0 ? argv[0] : ""); // Check if bitcoin-node is being invoked as an IPC server. If so, then diff --git a/src/init/bitcoin-qt.cpp b/src/init/bitcoin-qt.cpp index d71177e885..37d4e426c5 100644 --- a/src/init/bitcoin-qt.cpp +++ b/src/init/bitcoin-qt.cpp @@ -24,12 +24,12 @@ public: } std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); } std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); } - std::unique_ptr<interfaces::WalletClient> makeWalletClient(interfaces::Chain& chain) override + std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override { - return MakeWalletClient(chain, *Assert(m_node.args)); + return MakeWalletLoader(chain, *Assert(m_node.args)); } std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); } - NodeContext m_node; + node::NodeContext m_node; }; } // namespace } // namespace init diff --git a/src/init/bitcoind.cpp b/src/init/bitcoind.cpp index 9c8d5bd9bb..2addff07c1 100644 --- a/src/init/bitcoind.cpp +++ b/src/init/bitcoind.cpp @@ -12,6 +12,8 @@ #include <memory> +using node::NodeContext; + namespace init { namespace { class BitcoindInit : public interfaces::Init @@ -24,9 +26,9 @@ public: } std::unique_ptr<interfaces::Node> makeNode() override { return interfaces::MakeNode(m_node); } std::unique_ptr<interfaces::Chain> makeChain() override { return interfaces::MakeChain(m_node); } - std::unique_ptr<interfaces::WalletClient> makeWalletClient(interfaces::Chain& chain) override + std::unique_ptr<interfaces::WalletLoader> makeWalletLoader(interfaces::Chain& chain) override { - return MakeWalletClient(chain, *Assert(m_node.args)); + return MakeWalletLoader(chain, *Assert(m_node.args)); } std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); } NodeContext& m_node; diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 601c677a20..ddfb4bda95 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -28,7 +28,9 @@ enum class RBFTransactionState; struct bilingual_str; struct CBlockLocator; struct FeeCalculation; +namespace node { struct NodeContext; +} // namespace node namespace interfaces { @@ -114,9 +116,6 @@ public: //! or one of its ancestors. virtual std::optional<int> findLocatorFork(const CBlockLocator& locator) = 0; - //! Check if transaction will be final given chain height current time. - virtual bool checkFinalTx(const CTransaction& tx) = 0; - //! Return whether node has the block and optionally return block metadata //! or contents. virtual bool findBlock(const uint256& hash, const FoundBlock& block={}) = 0; @@ -316,7 +315,7 @@ public: }; //! Return implementation of Chain interface. -std::unique_ptr<Chain> MakeChain(NodeContext& node); +std::unique_ptr<Chain> MakeChain(node::NodeContext& node); } // namespace interfaces diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp index c6bbbed445..adb7031cbc 100644 --- a/src/interfaces/handler.cpp +++ b/src/interfaces/handler.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. diff --git a/src/interfaces/init.cpp b/src/interfaces/init.cpp index a3c949e616..f0f8aa5fed 100644 --- a/src/interfaces/init.cpp +++ b/src/interfaces/init.cpp @@ -11,7 +11,7 @@ namespace interfaces { std::unique_ptr<Node> Init::makeNode() { return {}; } std::unique_ptr<Chain> Init::makeChain() { return {}; } -std::unique_ptr<WalletClient> Init::makeWalletClient(Chain& chain) { return {}; } +std::unique_ptr<WalletLoader> Init::makeWalletLoader(Chain& chain) { return {}; } std::unique_ptr<Echo> Init::makeEcho() { return {}; } Ipc* Init::ipc() { return nullptr; } } // namespace interfaces diff --git a/src/interfaces/init.h b/src/interfaces/init.h index 2a38054a17..2153076366 100644 --- a/src/interfaces/init.h +++ b/src/interfaces/init.h @@ -7,14 +7,16 @@ #include <memory> +namespace node { struct NodeContext; +} // namespace node namespace interfaces { class Chain; class Echo; class Ipc; class Node; -class WalletClient; +class WalletLoader; //! Initial interface created when a process is first started, and used to give //! and get access to other interfaces (Node, Chain, Wallet, etc). @@ -29,7 +31,7 @@ public: virtual ~Init() = default; virtual std::unique_ptr<Node> makeNode(); virtual std::unique_ptr<Chain> makeChain(); - virtual std::unique_ptr<WalletClient> makeWalletClient(Chain& chain); + virtual std::unique_ptr<WalletLoader> makeWalletLoader(Chain& chain); virtual std::unique_ptr<Echo> makeEcho(); virtual Ipc* ipc(); }; @@ -40,7 +42,7 @@ public: //! status code to exit with. If this returns non-null, the caller can start up //! normally and use the Init object to spawn and connect to other processes //! while it is running. -std::unique_ptr<Init> MakeNodeInit(NodeContext& node, int argc, char* argv[], int& exit_status); +std::unique_ptr<Init> MakeNodeInit(node::NodeContext& node, int argc, char* argv[], int& exit_status); //! Return implementation of Init interface for the wallet process. std::unique_ptr<Init> MakeWalletInit(int argc, char* argv[], int& exit_status); diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 974156e6e1..9c1b196d61 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -22,7 +22,6 @@ #include <vector> class BanMan; -class CCoinControl; class CFeeRate; class CNodeStats; class Coin; @@ -32,12 +31,17 @@ class proxyType; enum class SynchronizationState; enum class TransactionError; struct CNodeStateStats; -struct NodeContext; struct bilingual_str; +namespace node { +struct NodeContext; +} // namespace node +namespace wallet { +class CCoinControl; +} // namespace wallet namespace interfaces { class Handler; -class WalletClient; +class WalletLoader; struct BlockTip; //! Block and header tip information @@ -187,8 +191,8 @@ public: //! Broadcast transaction. virtual TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) = 0; - //! Get wallet client. - virtual WalletClient& walletClient() = 0; + //! Get wallet loader. + virtual WalletLoader& walletLoader() = 0; //! Register handler for init messages. using InitMessageFn = std::function<void(const std::string& message)>; @@ -210,7 +214,7 @@ public: using ShowProgressFn = std::function<void(const std::string& title, int progress, bool resume_possible)>; virtual std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) = 0; - //! Register handler for wallet client constructed messages. + //! Register handler for wallet loader constructed messages. using InitWalletFn = std::function<void()>; virtual std::unique_ptr<Handler> handleInitWallet(InitWalletFn fn) = 0; @@ -242,12 +246,12 @@ public: //! Get and set internal node context. Useful for testing, but not //! accessible across processes. - virtual NodeContext* context() { return nullptr; } - virtual void setContext(NodeContext* context) { } + virtual node::NodeContext* context() { return nullptr; } + virtual void setContext(node::NodeContext* context) { } }; //! Return implementation of Node interface. -std::unique_ptr<Node> MakeNode(NodeContext& context); +std::unique_ptr<Node> MakeNode(node::NodeContext& context); //! Block tip (could be a header or not, depends on the subscribed signal). struct BlockTip { diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 4213a22749..f26ac866dc 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -6,6 +6,7 @@ #define BITCOIN_INTERFACES_WALLET_H #include <consensus/amount.h> +#include <fs.h> #include <interfaces/chain.h> // For ChainClient #include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation) #include <script/standard.h> // For CTxDestination @@ -23,19 +24,21 @@ #include <utility> #include <vector> -class CCoinControl; class CFeeRate; class CKey; -class CWallet; enum class FeeReason; enum class OutputType; enum class TransactionError; +struct PartiallySignedTransaction; +struct bilingual_str; +namespace wallet { +class CCoinControl; +class CWallet; enum isminetype : unsigned int; struct CRecipient; -struct PartiallySignedTransaction; struct WalletContext; -struct bilingual_str; using isminefilter = std::underlying_type<isminetype>::type; +} // namespace wallet namespace interfaces { @@ -107,7 +110,7 @@ public: //! Look up address in wallet, return whether exists. virtual bool getAddress(const CTxDestination& dest, std::string* name, - isminetype* is_mine, + wallet::isminetype* is_mine, std::string* purpose) = 0; //! Get wallet address list. @@ -135,8 +138,8 @@ public: virtual void listLockedCoins(std::vector<COutPoint>& outputs) = 0; //! Create transaction. - virtual CTransactionRef createTransaction(const std::vector<CRecipient>& recipients, - const CCoinControl& coin_control, + virtual CTransactionRef createTransaction(const std::vector<wallet::CRecipient>& recipients, + const wallet::CCoinControl& coin_control, bool sign, int& change_pos, CAmount& fee, @@ -158,7 +161,7 @@ public: //! Create bump transaction. virtual bool createBumpTransaction(const uint256& txid, - const CCoinControl& coin_control, + const wallet::CCoinControl& coin_control, std::vector<bilingual_str>& errors, CAmount& old_fee, CAmount& new_fee, @@ -213,19 +216,19 @@ public: virtual CAmount getBalance() = 0; //! Get available balance. - virtual CAmount getAvailableBalance(const CCoinControl& coin_control) = 0; + virtual CAmount getAvailableBalance(const wallet::CCoinControl& coin_control) = 0; //! Return whether transaction input belongs to wallet. - virtual isminetype txinIsMine(const CTxIn& txin) = 0; + virtual wallet::isminetype txinIsMine(const CTxIn& txin) = 0; //! Return whether transaction output belongs to wallet. - virtual isminetype txoutIsMine(const CTxOut& txout) = 0; + virtual wallet::isminetype txoutIsMine(const CTxOut& txout) = 0; //! Return debit amount if transaction input belongs to wallet. - virtual CAmount getDebit(const CTxIn& txin, isminefilter filter) = 0; + virtual CAmount getDebit(const CTxIn& txin, wallet::isminefilter filter) = 0; //! Return credit amount if transaction input belongs to wallet. - virtual CAmount getCredit(const CTxOut& txout, isminefilter filter) = 0; + virtual CAmount getCredit(const CTxOut& txout, wallet::isminefilter filter) = 0; //! Return AvailableCoins + LockedCoins grouped by wallet address. //! (put change in one group with wallet address) @@ -240,7 +243,7 @@ public: //! Get minimum fee. virtual CAmount getMinimumFee(unsigned int tx_bytes, - const CCoinControl& coin_control, + const wallet::CCoinControl& coin_control, int* returned_target, FeeReason* reason) = 0; @@ -256,6 +259,9 @@ public: // Return whether private keys enabled. virtual bool privateKeysDisabled() = 0; + // Return whether the wallet contains a Taproot scriptPubKeyMan + virtual bool taprootEnabled() = 0; + // Return whether wallet uses an external signer. virtual bool hasExternalSigner() = 0; @@ -304,13 +310,13 @@ public: virtual std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) = 0; //! Return pointer to internal wallet class, useful for testing. - virtual CWallet* wallet() { return nullptr; } + virtual wallet::CWallet* wallet() { return nullptr; } }; //! Wallet chain client that in addition to having chain client methods for //! starting up, shutting down, and registering RPCs, also has additional //! methods (called by the GUI) to load and create wallets. -class WalletClient : public ChainClient +class WalletLoader : public ChainClient { public: //! Create new wallet. @@ -323,7 +329,7 @@ public: virtual std::string getWalletDir() = 0; //! Restore backup wallet - virtual std::unique_ptr<Wallet> restoreWallet(const std::string& backup_file, const std::string& wallet_name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0; + virtual std::unique_ptr<Wallet> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0; //! Return available wallets in wallet directory. virtual std::vector<std::string> listWalletDir() = 0; @@ -338,18 +344,18 @@ public: virtual std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) = 0; //! Return pointer to internal context, useful for testing. - virtual WalletContext* context() { return nullptr; } + virtual wallet::WalletContext* context() { return nullptr; } }; //! Information about one wallet address. struct WalletAddress { CTxDestination dest; - isminetype is_mine; + wallet::isminetype is_mine; std::string name; std::string purpose; - WalletAddress(CTxDestination dest, isminetype is_mine, std::string name, std::string purpose) + WalletAddress(CTxDestination dest, wallet::isminetype is_mine, std::string name, std::string purpose) : dest(std::move(dest)), is_mine(is_mine), name(std::move(name)), purpose(std::move(purpose)) { } @@ -379,10 +385,10 @@ struct WalletBalances struct WalletTx { CTransactionRef tx; - std::vector<isminetype> txin_is_mine; - std::vector<isminetype> txout_is_mine; + std::vector<wallet::isminetype> txin_is_mine; + std::vector<wallet::isminetype> txout_is_mine; std::vector<CTxDestination> txout_address; - std::vector<isminetype> txout_address_is_mine; + std::vector<wallet::isminetype> txout_address_is_mine; CAmount credit; CAmount debit; CAmount change; @@ -399,7 +405,6 @@ struct WalletTxStatus int depth_in_main_chain; unsigned int time_received; uint32_t lock_time; - bool is_final; bool is_trusted; bool is_abandoned; bool is_coinbase; @@ -417,11 +422,11 @@ struct WalletTxOut //! Return implementation of Wallet interface. This function is defined in //! dummywallet.cpp and throws if the wallet component is not compiled. -std::unique_ptr<Wallet> MakeWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet); +std::unique_ptr<Wallet> MakeWallet(wallet::WalletContext& context, const std::shared_ptr<wallet::CWallet>& wallet); -//! Return implementation of ChainClient interface for a wallet client. This +//! Return implementation of ChainClient interface for a wallet loader. This //! function will be undefined in builds where ENABLE_WALLET is false. -std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args); +std::unique_ptr<WalletLoader> MakeWalletLoader(Chain& chain, ArgsManager& args); } // namespace interfaces diff --git a/src/key.cpp b/src/key.cpp index bf4dd49bb9..354bd097ce 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2021 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-2021 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/key_io.cpp b/src/key_io.cpp index 3559f3a03d..6dd6f82112 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-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. diff --git a/src/key_io.h b/src/key_io.h index 2062bb4c44..07b80c4b85 100644 --- a/src/key_io.h +++ b/src/key_io.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/logging.cpp b/src/logging.cpp index 1efce21bdb..764941c8ea 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -1,8 +1,9 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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 <fs.h> #include <logging.h> #include <util/threadnames.h> #include <util/string.h> diff --git a/src/logging.h b/src/logging.h index f46104364c..710e6c4c32 100644 --- a/src/logging.h +++ b/src/logging.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -13,6 +13,7 @@ #include <atomic> #include <cstdint> +#include <functional> #include <list> #include <mutex> #include <string> diff --git a/src/logging/timer.h b/src/logging/timer.h index b77a0e17c7..fc5307bc62 100644 --- a/src/logging/timer.h +++ b/src/logging/timer.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/mapport.cpp b/src/mapport.cpp index a2d06c68b4..42ca366089 100644 --- a/src/mapport.cpp +++ b/src/mapport.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/merkleblock.h b/src/merkleblock.h index 70749b6378..b546b17f52 100644 --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/minisketch/src/minisketch.cpp b/src/minisketch/src/minisketch.cpp index e9a322f139..d003fdf755 100644 --- a/src/minisketch/src/minisketch.cpp +++ b/src/minisketch/src/minisketch.cpp @@ -63,9 +63,9 @@ enum class FieldImpl { #endif }; +#ifdef HAVE_CLMUL static inline bool EnableClmul() { -#ifdef HAVE_CLMUL #ifdef _MSC_VER int regs[4]; __cpuid(regs, 1); @@ -74,10 +74,8 @@ static inline bool EnableClmul() uint32_t eax, ebx, ecx, edx; return (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & 0x2)); #endif -#else - return false; -#endif } +#endif Sketch* Construct(int bits, int impl) { diff --git a/src/net.cpp b/src/net.cpp index 0f49b8ad5a..bee8710062 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -16,6 +16,7 @@ #include <compat.h> #include <consensus/consensus.h> #include <crypto/sha256.h> +#include <fs.h> #include <i2p.h> #include <net_permissions.h> #include <netaddress.h> @@ -112,9 +113,9 @@ static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256 // bool fDiscover = true; bool fListen = true; -RecursiveMutex cs_mapLocalHost; -std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost); -static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {}; +Mutex g_maplocalhost_mutex; +std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex); +static bool vfLimited[NET_MAX] GUARDED_BY(g_maplocalhost_mutex) = {}; std::string strSubVersion; void CConnman::AddAddrFetch(const std::string& strDest) @@ -137,7 +138,7 @@ bool GetLocal(CService& addr, const CNetAddr *paddrPeer) int nBestScore = -1; int nBestReachability = -1; { - LOCK(cs_mapLocalHost); + LOCK(g_maplocalhost_mutex); for (const auto& entry : mapLocalHost) { int nScore = entry.second.nScore; @@ -193,7 +194,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer, ServiceFlags nLocalServices) static int GetnScore(const CService& addr) { - LOCK(cs_mapLocalHost); + LOCK(g_maplocalhost_mutex); const auto it = mapLocalHost.find(addr); return (it != mapLocalHost.end()) ? it->second.nScore : 0; } @@ -264,7 +265,7 @@ bool AddLocal(const CService& addr_, int nScore) LogPrintf("AddLocal(%s,%i)\n", addr.ToString(), nScore); { - LOCK(cs_mapLocalHost); + LOCK(g_maplocalhost_mutex); const auto [it, is_newly_added] = mapLocalHost.emplace(addr, LocalServiceInfo()); LocalServiceInfo &info = it->second; if (is_newly_added || nScore >= info.nScore) { @@ -283,7 +284,7 @@ bool AddLocal(const CNetAddr &addr, int nScore) void RemoveLocal(const CService& addr) { - LOCK(cs_mapLocalHost); + LOCK(g_maplocalhost_mutex); LogPrintf("RemoveLocal(%s)\n", addr.ToString()); mapLocalHost.erase(addr); } @@ -292,13 +293,13 @@ void SetReachable(enum Network net, bool reachable) { if (net == NET_UNROUTABLE || net == NET_INTERNAL) return; - LOCK(cs_mapLocalHost); + LOCK(g_maplocalhost_mutex); vfLimited[net] = !reachable; } bool IsReachable(enum Network net) { - LOCK(cs_mapLocalHost); + LOCK(g_maplocalhost_mutex); return !vfLimited[net]; } @@ -310,7 +311,7 @@ bool IsReachable(const CNetAddr &addr) /** vote for a local address */ bool SeenLocal(const CService& addr) { - LOCK(cs_mapLocalHost); + LOCK(g_maplocalhost_mutex); const auto it = mapLocalHost.find(addr); if (it == mapLocalHost.end()) return false; ++it->second.nScore; @@ -321,7 +322,7 @@ bool SeenLocal(const CService& addr) /** check whether a given address is potentially local */ bool IsLocal(const CService& addr) { - LOCK(cs_mapLocalHost); + LOCK(g_maplocalhost_mutex); return mapLocalHost.count(addr) > 0; } @@ -505,7 +506,16 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo if (!addr_bind.IsValid()) { addr_bind = GetBindAddress(sock->Get()); } - CNode* pnode = new CNode(id, nLocalServices, sock->Release(), addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", conn_type, /* inbound_onion */ false); + CNode* pnode = new CNode(id, + nLocalServices, + std::move(sock), + addrConnect, + CalculateKeyedNetGroup(addrConnect), + nonce, + addr_bind, + pszDest ? pszDest : "", + conn_type, + /*inbound_onion=*/false); pnode->AddRef(); // We're making a new connection, harvest entropy from the time (and our peer count) @@ -517,11 +527,10 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo void CNode::CloseSocketDisconnect() { fDisconnect = true; - LOCK(cs_hSocket); - if (hSocket != INVALID_SOCKET) - { + LOCK(m_sock_mutex); + if (m_sock) { LogPrint(BCLog::NET, "disconnecting peer=%d\n", id); - CloseSocket(hSocket); + m_sock.reset(); } } @@ -553,12 +562,14 @@ std::string ConnectionTypeAsString(ConnectionType conn_type) CService CNode::GetAddrLocal() const { - LOCK(cs_addrLocal); + AssertLockNotHeld(m_addr_local_mutex); + LOCK(m_addr_local_mutex); return addrLocal; } void CNode::SetAddrLocal(const CService& addrLocalIn) { - LOCK(cs_addrLocal); + AssertLockNotHeld(m_addr_local_mutex); + LOCK(m_addr_local_mutex); if (addrLocal.IsValid()) { error("Addr local already set for node: %i. Refusing to change from %s to %s", id, addrLocal.ToString(), addrLocalIn.ToString()); } else { @@ -595,7 +606,7 @@ void CNode::CopyStats(CNodeStats& stats) X(m_addr_name); X(nVersion); { - LOCK(cs_SubVer); + LOCK(m_subver_mutex); X(cleanSubVer); } stats.fInbound = IsInboundConn(); @@ -657,7 +668,7 @@ bool CNode::ReceiveMsgBytes(Span<const uint8_t> msg_bytes, bool& complete) // Store received bytes per message command // to prevent a memory DOS, only allow valid commands - auto i = mapRecvBytesPerMsgCmd.find(msg.m_command); + auto i = mapRecvBytesPerMsgCmd.find(msg.m_type); if (i == mapRecvBytesPerMsgCmd.end()) { i = mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER); } @@ -747,7 +758,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds CNetMessage msg(std::move(vRecv)); // store command string, time, and sizes - msg.m_command = hdr.GetCommand(); + msg.m_type = hdr.GetCommand(); msg.m_time = time; msg.m_message_size = hdr.nMessageSize; msg.m_raw_message_size = hdr.nMessageSize + CMessageHeader::HEADER_SIZE; @@ -760,7 +771,7 @@ CNetMessage V1TransportDeserializer::GetMessage(const std::chrono::microseconds // Check checksum and header command string if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) { LogPrint(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n", - SanitizeString(msg.m_command), msg.m_message_size, + SanitizeString(msg.m_type), msg.m_message_size, HexStr(Span{hash}.first(CMessageHeader::CHECKSUM_SIZE)), HexStr(hdr.pchChecksum), m_node_id); @@ -799,10 +810,11 @@ size_t CConnman::SocketSendData(CNode& node) const assert(data.size() > node.nSendOffset); int nBytes = 0; { - LOCK(node.cs_hSocket); - if (node.hSocket == INVALID_SOCKET) + LOCK(node.m_sock_mutex); + if (!node.m_sock) { break; - nBytes = send(node.hSocket, reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); + } + nBytes = node.m_sock->Send(reinterpret_cast<const char*>(data.data()) + node.nSendOffset, data.size() - node.nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT); } if (nBytes > 0) { node.m_last_send = GetTime<std::chrono::seconds>(); @@ -1099,10 +1111,10 @@ bool CConnman::AttemptToEvictConnection() void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { struct sockaddr_storage sockaddr; socklen_t len = sizeof(sockaddr); - SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len); + auto sock = hListenSocket.sock->Accept((struct sockaddr*)&sockaddr, &len); CAddress addr; - if (hSocket == INVALID_SOCKET) { + if (!sock) { const int nErr = WSAGetLastError(); if (nErr != WSAEWOULDBLOCK) { LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr)); @@ -1116,15 +1128,15 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { addr = CAddress{MaybeFlipIPv6toCJDNS(addr), NODE_NONE}; } - const CAddress addr_bind{MaybeFlipIPv6toCJDNS(GetBindAddress(hSocket)), NODE_NONE}; + const CAddress addr_bind{MaybeFlipIPv6toCJDNS(GetBindAddress(sock->Get())), NODE_NONE}; NetPermissionFlags permissionFlags = NetPermissionFlags::None; hListenSocket.AddSocketPermissionFlags(permissionFlags); - CreateNodeFromAcceptedSocket(hSocket, permissionFlags, addr_bind, addr); + CreateNodeFromAcceptedSocket(std::move(sock), permissionFlags, addr_bind, addr); } -void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket, +void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, NetPermissionFlags permissionFlags, const CAddress& addr_bind, const CAddress& addr) @@ -1150,27 +1162,24 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket, if (!fNetworkActive) { LogPrint(BCLog::NET, "connection from %s dropped: not accepting new connections\n", addr.ToString()); - CloseSocket(hSocket); return; } - if (!IsSelectableSocket(hSocket)) + if (!IsSelectableSocket(sock->Get())) { LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString()); - CloseSocket(hSocket); return; } // According to the internet TCP_NODELAY is not carried into accepted sockets // on all platforms. Set it again here just to be sure. - SetSocketNoDelay(hSocket); + SetSocketNoDelay(sock->Get()); // Don't accept connections from banned peers. bool banned = m_banman && m_banman->IsBanned(addr); if (!NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::NoBan) && banned) { LogPrint(BCLog::NET, "connection from %s dropped (banned)\n", addr.ToString()); - CloseSocket(hSocket); return; } @@ -1179,7 +1188,6 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket, if (!NetPermissions::HasFlag(permissionFlags, NetPermissionFlags::NoBan) && nInbound + 1 >= nMaxInbound && discouraged) { LogPrint(BCLog::NET, "connection from %s dropped (discouraged)\n", addr.ToString()); - CloseSocket(hSocket); return; } @@ -1188,7 +1196,6 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket, if (!AttemptToEvictConnection()) { // No connection to evict, disconnect the new connection LogPrint(BCLog::NET, "failed to find an eviction candidate - connection dropped (full)\n"); - CloseSocket(hSocket); return; } } @@ -1202,7 +1209,16 @@ void CConnman::CreateNodeFromAcceptedSocket(SOCKET hSocket, } 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, hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", ConnectionType::INBOUND, inbound_onion); + CNode* pnode = new CNode(id, + nodeServices, + std::move(sock), + addr, + CalculateKeyedNetGroup(addr), + nonce, + addr_bind, + /*addrNameIn=*/"", + ConnectionType::INBOUND, + inbound_onion); pnode->AddRef(); pnode->m_permissionFlags = permissionFlags; pnode->m_prefer_evict = discouraged; @@ -1364,7 +1380,7 @@ bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes, std::set<SOCKET>& error_set) { for (const ListenSocket& hListenSocket : vhListenSocket) { - recv_set.insert(hListenSocket.socket); + recv_set.insert(hListenSocket.sock->Get()); } for (CNode* pnode : nodes) { @@ -1386,17 +1402,18 @@ bool CConnman::GenerateSelectSet(const std::vector<CNode*>& nodes, select_send = !pnode->vSendMsg.empty(); } - LOCK(pnode->cs_hSocket); - if (pnode->hSocket == INVALID_SOCKET) + LOCK(pnode->m_sock_mutex); + if (!pnode->m_sock) { continue; + } - error_set.insert(pnode->hSocket); + error_set.insert(pnode->m_sock->Get()); if (select_send) { - send_set.insert(pnode->hSocket); + send_set.insert(pnode->m_sock->Get()); continue; } if (select_recv) { - recv_set.insert(pnode->hSocket); + recv_set.insert(pnode->m_sock->Get()); } } @@ -1566,12 +1583,13 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes, bool sendSet = false; bool errorSet = false; { - LOCK(pnode->cs_hSocket); - if (pnode->hSocket == INVALID_SOCKET) + LOCK(pnode->m_sock_mutex); + if (!pnode->m_sock) { continue; - recvSet = recv_set.count(pnode->hSocket) > 0; - sendSet = send_set.count(pnode->hSocket) > 0; - errorSet = error_set.count(pnode->hSocket) > 0; + } + recvSet = recv_set.count(pnode->m_sock->Get()) > 0; + sendSet = send_set.count(pnode->m_sock->Get()) > 0; + errorSet = error_set.count(pnode->m_sock->Get()) > 0; } if (recvSet || errorSet) { @@ -1579,10 +1597,11 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes, uint8_t pchBuf[0x10000]; int nBytes = 0; { - LOCK(pnode->cs_hSocket); - if (pnode->hSocket == INVALID_SOCKET) + LOCK(pnode->m_sock_mutex); + if (!pnode->m_sock) { continue; - nBytes = recv(pnode->hSocket, (char*)pchBuf, sizeof(pchBuf), MSG_DONTWAIT); + } + nBytes = pnode->m_sock->Recv(pchBuf, sizeof(pchBuf), MSG_DONTWAIT); } if (nBytes > 0) { @@ -1646,7 +1665,7 @@ void CConnman::SocketHandlerListening(const std::set<SOCKET>& recv_set) if (interruptNet) { return; } - if (recv_set.count(listen_socket.socket) > 0) { + if (recv_set.count(listen_socket.sock->Get()) > 0) { AcceptConnection(listen_socket); } } @@ -1883,8 +1902,8 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) auto start = GetTime<std::chrono::microseconds>(); // Minimum time before next feeler connection (in microseconds). - auto next_feeler = PoissonNextSend(start, FEELER_INTERVAL); - auto next_extra_block_relay = PoissonNextSend(start, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); + auto next_feeler = GetExponentialRand(start, FEELER_INTERVAL); + auto next_extra_block_relay = GetExponentialRand(start, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED); bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS); @@ -2004,7 +2023,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) // // This is similar to the logic for trying extra outbound (full-relay) // peers, except: - // - we do this all the time on a poisson timer, rather than just when + // - we do this all the time on an exponential timer, rather than just when // our tip is stale // - we potentially disconnect our next-youngest block-relay-only peer, if our // newest block-relay-only peer delivers a block more recently. @@ -2013,10 +2032,10 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) // Because we can promote these connections to block-relay-only // connections, they do not get their own ConnectionType enum // (similar to how we deal with extra outbound peers). - next_extra_block_relay = PoissonNextSend(now, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); + next_extra_block_relay = GetExponentialRand(now, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL); conn_type = ConnectionType::BLOCK_RELAY; } else if (now > next_feeler) { - next_feeler = PoissonNextSend(now, FEELER_INTERVAL); + next_feeler = GetExponentialRand(now, FEELER_INTERVAL); conn_type = ConnectionType::FEELER; fFeeler = true; } else { @@ -2335,7 +2354,7 @@ void CConnman::ThreadI2PAcceptIncoming() continue; } - CreateNodeFromAcceptedSocket(conn.sock->Release(), NetPermissionFlags::None, + CreateNodeFromAcceptedSocket(std::move(conn.sock), NetPermissionFlags::None, CAddress{conn.me, NODE_NONE}, CAddress{conn.peer, NODE_NONE}); } } @@ -2397,7 +2416,7 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError, return false; } - vhListenSocket.push_back(ListenSocket(sock->Release(), permissions)); + vhListenSocket.emplace_back(std::move(sock), permissions); return true; } @@ -2706,15 +2725,6 @@ void CConnman::StopNodes() DeleteNode(pnode); } - // Close listening sockets. - for (ListenSocket& hListenSocket : vhListenSocket) { - if (hListenSocket.socket != INVALID_SOCKET) { - if (!CloseSocket(hListenSocket.socket)) { - LogPrintf("CloseSocket(hListenSocket) failed with error %s\n", NetworkErrorString(WSAGetLastError())); - } - } - } - for (CNode* pnode : m_nodes_disconnected) { DeleteNode(pnode); } @@ -2976,8 +2986,9 @@ ServiceFlags CConnman::GetLocalServices() const unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } -CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion) - : m_connected{GetTime<std::chrono::seconds>()}, +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) + : m_sock{sock}, + m_connected{GetTime<std::chrono::seconds>()}, addr(addrIn), addrBind(addrBindIn), m_addr_name{addrNameIn.empty() ? addr.ToStringIPPort() : addrNameIn}, @@ -2989,7 +3000,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const nLocalServices(nLocalServicesIn) { if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND); - hSocket = hSocketIn; if (conn_type_in != ConnectionType::BLOCK_RELAY) { m_tx_relay = std::make_unique<TxRelay>(); } @@ -3008,11 +3018,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, const m_serializer = std::make_unique<V1TransportSerializer>(V1TransportSerializer()); } -CNode::~CNode() -{ - CloseSocket(hSocket); -} - bool CConnman::NodeFullyConnected(const CNode* pnode) { return pnode && pnode->fSuccessfullyConnected && !pnode->fDisconnect; @@ -3072,23 +3077,6 @@ bool CConnman::ForNode(NodeId id, std::function<bool(CNode* pnode)> func) return found != nullptr && NodeFullyConnected(found) && func(found); } -std::chrono::microseconds CConnman::PoissonNextSendInbound(std::chrono::microseconds now, std::chrono::seconds average_interval) -{ - if (m_next_send_inv_to_incoming.load() < now) { - // If this function were called from multiple threads simultaneously - // it would possible that both update the next send variable, and return a different result to their caller. - // This is not possible in practice as only the net processing thread invokes this function. - m_next_send_inv_to_incoming = PoissonNextSend(now, average_interval); - } - return m_next_send_inv_to_incoming; -} - -std::chrono::microseconds PoissonNextSend(std::chrono::microseconds now, std::chrono::seconds average_interval) -{ - double unscaled = -log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */); - return now + std::chrono::duration_cast<std::chrono::microseconds>(unscaled * average_interval + 0.5us); -} - CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) const { return CSipHasher(nSeed0, nSeed1).Write(id); @@ -3120,11 +3108,11 @@ void CaptureMessage(const CAddress& addr, const std::string& msg_type, const Spa CAutoFile f(fsbridge::fopen(path, "ab"), SER_DISK, CLIENT_VERSION); ser_writedata64(f, now.count()); - f.write(msg_type.data(), msg_type.length()); + f.write(MakeByteSpan(msg_type)); for (auto i = msg_type.length(); i < CMessageHeader::COMMAND_SIZE; ++i) { f << uint8_t{'\0'}; } uint32_t size = data.size(); ser_writedata32(f, size); - f.write((const char*)data.data(), data.size()); + f.write(AsBytes(data)); } @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -25,6 +25,7 @@ #include <threadinterrupt.h> #include <uint256.h> #include <util/check.h> +#include <util/sock.h> #include <atomic> #include <condition_variable> @@ -229,8 +230,8 @@ struct LocalServiceInfo { uint16_t nPort; }; -extern RecursiveMutex cs_mapLocalHost; -extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost); +extern Mutex g_maplocalhost_mutex; +extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex); extern const std::string NET_MESSAGE_COMMAND_OTHER; typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes @@ -277,7 +278,7 @@ public: /** Transport protocol agnostic message container. * Ideally it should only contain receive time, payload, - * command and size. + * type and size. */ class CNetMessage { public: @@ -285,7 +286,7 @@ public: std::chrono::microseconds m_time{0}; //!< time of message receipt uint32_t m_message_size{0}; //!< size of the payload uint32_t m_raw_message_size{0}; //!< used wire size of the message (including header/checksum) - std::string m_command; + std::string m_type; CNetMessage(CDataStream&& recv_in) : m_recv(std::move(recv_in)) {} @@ -401,7 +402,17 @@ public: NetPermissionFlags m_permissionFlags{NetPermissionFlags::None}; std::atomic<ServiceFlags> nServices{NODE_NONE}; - SOCKET hSocket GUARDED_BY(cs_hSocket); + + /** + * Socket used for communication with the node. + * May not own a Sock object (after `CloseSocketDisconnect()` or during tests). + * `shared_ptr` (instead of `unique_ptr`) is used to avoid premature close of + * the underlying file descriptor by one thread while another thread is + * poll(2)-ing it for activity. + * @see https://github.com/bitcoin/bitcoin/issues/21744 for details. + */ + std::shared_ptr<Sock> m_sock GUARDED_BY(m_sock_mutex); + /** Total size of all vSendMsg entries */ size_t nSendSize GUARDED_BY(cs_vSend){0}; /** Offset inside the first vSendMsg already sent */ @@ -409,7 +420,7 @@ public: uint64_t nSendBytes GUARDED_BY(cs_vSend){0}; std::deque<std::vector<unsigned char>> vSendMsg GUARDED_BY(cs_vSend); Mutex cs_vSend; - Mutex cs_hSocket; + Mutex m_sock_mutex; Mutex cs_vRecv; RecursiveMutex cs_vProcessMsg; @@ -433,12 +444,12 @@ public: //! Whether this peer is an inbound onion, i.e. connected via our Tor onion service. const bool m_inbound_onion; std::atomic<int> nVersion{0}; - RecursiveMutex cs_SubVer; + Mutex m_subver_mutex; /** * cleanSubVer is a sanitized string of the user agent byte array we read * from the wire. This cleaned string can safely be logged or displayed. */ - std::string cleanSubVer GUARDED_BY(cs_SubVer){}; + std::string cleanSubVer GUARDED_BY(m_subver_mutex){}; bool m_prefer_evict{false}; // This peer is preferred for eviction. bool HasPermission(NetPermissionFlags permission) const { return NetPermissions::HasFlag(m_permissionFlags, permission); @@ -577,8 +588,7 @@ public: * criterium in CConnman::AttemptToEvictConnection. */ std::atomic<std::chrono::microseconds> m_min_ping_time{std::chrono::microseconds::max()}; - CNode(NodeId id, ServiceFlags nLocalServicesIn, SOCKET hSocketIn, 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 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(const CNode&) = delete; CNode& operator=(const CNode&) = delete; @@ -617,9 +627,9 @@ public: return m_greatest_common_version; } - CService GetAddrLocal() const; + CService GetAddrLocal() const LOCKS_EXCLUDED(m_addr_local_mutex); //! May not be called more than once - void SetAddrLocal(const CService& addrLocalIn); + void SetAddrLocal(const CService& addrLocalIn) LOCKS_EXCLUDED(m_addr_local_mutex); CNode* AddRef() { @@ -692,8 +702,8 @@ private: std::list<CNetMessage> vRecvMsg; // Used only by SocketHandler thread // Our address, as reported by the peer - CService addrLocal GUARDED_BY(cs_addrLocal); - mutable RecursiveMutex cs_addrLocal; + CService addrLocal GUARDED_BY(m_addr_local_mutex); + mutable Mutex m_addr_local_mutex; mapMsgCmdSize mapSendBytesPerMsgCmd GUARDED_BY(cs_vSend); mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv); @@ -935,21 +945,19 @@ public: void WakeMessageHandler(); - /** Attempts to obfuscate tx time through exponentially distributed emitting. - Works assuming that a single interval is used. - Variable intervals will result in privacy decrease. - */ - std::chrono::microseconds PoissonNextSendInbound(std::chrono::microseconds now, std::chrono::seconds average_interval); - /** Return true if we should disconnect the peer for failing an inactivity check. */ bool ShouldRunInactivityChecks(const CNode& node, std::chrono::seconds now) const; private: struct ListenSocket { public: - SOCKET socket; + std::shared_ptr<Sock> sock; inline void AddSocketPermissionFlags(NetPermissionFlags& flags) const { NetPermissions::AddFlag(flags, m_permissions); } - ListenSocket(SOCKET socket_, NetPermissionFlags permissions_) : socket(socket_), m_permissions(permissions_) {} + ListenSocket(std::shared_ptr<Sock> sock_, NetPermissionFlags permissions_) + : sock{sock_}, m_permissions{permissions_} + { + } + private: NetPermissionFlags m_permissions; }; @@ -969,12 +977,12 @@ private: /** * Create a `CNode` object from a socket that has just been accepted and add the node to * the `m_nodes` member. - * @param[in] hSocket Connected socket to communicate with the peer. + * @param[in] sock Connected socket to communicate with the peer. * @param[in] permissionFlags The peer's permissions. * @param[in] addr_bind The address and port at our side of the connection. * @param[in] addr The address and port at the peer's side of the connection. */ - void CreateNodeFromAcceptedSocket(SOCKET hSocket, + void CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock, NetPermissionFlags permissionFlags, const CAddress& addr_bind, const CAddress& addr); @@ -1216,8 +1224,6 @@ private: */ std::atomic_bool m_start_extra_block_relay_peers{false}; - std::atomic<std::chrono::microseconds> m_next_send_inv_to_incoming{0us}; - /** * A vector of -bind=<address>:<port>=onion arguments each of which is * an address and port that are designated for incoming Tor connections. @@ -1265,9 +1271,6 @@ private: friend struct ConnmanTestMsg; }; -/** Return a timestamp in the future (in microseconds) for exponentially distributed events. */ -std::chrono::microseconds PoissonNextSend(std::chrono::microseconds now, std::chrono::seconds average_interval); - /** Dump binary message to file, with timestamp */ void CaptureMessage(const CAddress& addr, const std::string& msg_type, const Span<const unsigned char>& data, bool is_incoming); diff --git a/src/net_permissions.cpp b/src/net_permissions.cpp index d0a45f90fa..f829e56aa2 100644 --- a/src/net_permissions.cpp +++ b/src/net_permissions.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/net_permissions.h b/src/net_permissions.h index bc979e3792..662464083c 100644 --- a/src/net_permissions.h +++ b/src/net_permissions.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/net_processing.cpp b/src/net_processing.cpp index d67ced99ea..3cebca1a77 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -39,10 +39,18 @@ #include <validation.h> #include <algorithm> +#include <atomic> +#include <chrono> #include <memory> #include <optional> #include <typeinfo> +using node::ReadBlockFromDisk; +using node::ReadRawBlockFromDisk; +using node::fImporting; +using node::fPruneMode; +using node::fReindex; + /** How long to cache transactions in mapRelay for normal relay */ static constexpr auto RELAY_TX_CACHE_TIME = 15min; /** How long a transaction has to be in the mempool before it can unconditionally be relayed (even when not in mapRelay). */ @@ -55,14 +63,14 @@ static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1ms; * behind headers chain. */ static constexpr int32_t MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT = 4; -/** Timeout for (unprotected) outbound peers to sync to our chainwork, in seconds */ -static constexpr int64_t CHAIN_SYNC_TIMEOUT = 20 * 60; // 20 minutes -/** How frequently to check for stale tips, in seconds */ -static constexpr int64_t STALE_CHECK_INTERVAL = 10 * 60; // 10 minutes -/** How frequently to check for extra outbound peers and disconnect, in seconds */ -static constexpr int64_t EXTRA_PEER_CHECK_INTERVAL = 45; +/** Timeout for (unprotected) outbound peers to sync to our chainwork */ +static constexpr auto CHAIN_SYNC_TIMEOUT{20min}; +/** How frequently to check for stale tips */ +static constexpr auto STALE_CHECK_INTERVAL{10min}; +/** How frequently to check for extra outbound peers and disconnect */ +static constexpr auto EXTRA_PEER_CHECK_INTERVAL{45s}; /** Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict */ -static constexpr std::chrono::seconds MINIMUM_CONNECT_TIME{30}; +static constexpr auto MINIMUM_CONNECT_TIME{30s}; /** SHA256("main address relay")[0:8] */ static constexpr uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; /// Age after which a stale block will no longer be served if requested as @@ -72,7 +80,7 @@ static constexpr int STALE_RELAY_AGE_LIMIT = 30 * 24 * 60 * 60; /// limiting block relay. Set to one week, denominated in seconds. static constexpr int HISTORICAL_BLOCK_AGE = 7 * 24 * 60 * 60; /** Time between pings automatically sent out for latency probing and keepalive */ -static constexpr std::chrono::minutes PING_INTERVAL{2}; +static constexpr auto PING_INTERVAL{2min}; /** The maximum number of entries in a locator */ static const unsigned int MAX_LOCATOR_SZ = 101; /** The maximum number of entries in an 'inv' protocol message */ @@ -86,19 +94,19 @@ static constexpr int32_t MAX_PEER_TX_REQUEST_IN_FLIGHT = 100; * the actual transaction (from any peer) in response to requests for them. */ static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 5000; /** How long to delay requesting transactions via txids, if we have wtxid-relaying peers */ -static constexpr auto TXID_RELAY_DELAY = std::chrono::seconds{2}; +static constexpr auto TXID_RELAY_DELAY{2s}; /** How long to delay requesting transactions from non-preferred peers */ -static constexpr auto NONPREF_PEER_TX_DELAY = std::chrono::seconds{2}; +static constexpr auto NONPREF_PEER_TX_DELAY{2s}; /** How long to delay requesting transactions from overloaded peers (see MAX_PEER_TX_REQUEST_IN_FLIGHT). */ -static constexpr auto OVERLOADED_PEER_TX_DELAY = std::chrono::seconds{2}; -/** How long to wait (in microseconds) before downloading a transaction from an additional peer */ -static constexpr std::chrono::microseconds GETDATA_TX_INTERVAL{std::chrono::seconds{60}}; +static constexpr auto OVERLOADED_PEER_TX_DELAY{2s}; +/** How long to wait before downloading a transaction from an additional peer */ +static constexpr auto GETDATA_TX_INTERVAL{60s}; /** Limit to avoid sending big packets. Not used in processing incoming GETDATA for compatibility */ static const unsigned int MAX_GETDATA_SZ = 1000; /** Number of blocks that can be requested at any given time from a single peer. */ static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16; /** Time during which a peer must stall block download progress before being disconnected. */ -static constexpr auto BLOCK_STALLING_TIMEOUT = 2s; +static constexpr auto BLOCK_STALLING_TIMEOUT{2s}; /** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends * less than this number, we reached its tip. Changing this value is a protocol upgrade. */ static const unsigned int MAX_HEADERS_RESULTS = 2000; @@ -123,16 +131,16 @@ static const int MAX_UNCONNECTING_HEADERS = 10; /** Minimum blocks required to signal NODE_NETWORK_LIMITED */ static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288; /** Average delay between local address broadcasts */ -static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24h; +static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL{24h}; /** Average delay between peer address broadcasts */ -static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL = 30s; +static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL{30s}; /** Average delay between trickled inventory transmissions for inbound peers. * Blocks and peers with NetPermissionFlags::NoBan permission bypass this. */ -static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL = 5s; +static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL{5s}; /** Average delay between trickled inventory transmissions for outbound peers. * Use a smaller delay as there is less privacy concern for them. * Blocks and peers with NetPermissionFlags::NoBan permission bypass this. */ -static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL = 2s; +static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL{2s}; /** Maximum rate of inventory items to send per second. * Limits the impact of low-fee transaction floods. */ static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND = 7; @@ -146,9 +154,9 @@ static constexpr unsigned int INVENTORY_MAX_RECENT_RELAY = 3500; * peers, and random variations in the broadcast mechanism. */ static_assert(INVENTORY_MAX_RECENT_RELAY >= INVENTORY_BROADCAST_PER_SECOND * UNCONDITIONAL_RELAY_DELAY / std::chrono::seconds{1}, "INVENTORY_RELAY_MAX too low"); /** Average delay between feefilter broadcasts in seconds. */ -static constexpr auto AVG_FEEFILTER_BROADCAST_INTERVAL = 10min; +static constexpr auto AVG_FEEFILTER_BROADCAST_INTERVAL{10min}; /** Maximum feefilter broadcast delay after significant change. */ -static constexpr auto MAX_FEEFILTER_CHANGE_DELAY = 5min; +static constexpr auto MAX_FEEFILTER_CHANGE_DELAY{5min}; /** Maximum number of compact filters that may be requested with one getcfilters. See BIP 157. */ static constexpr uint32_t MAX_GETCFILTERS_SIZE = 1000; /** Maximum number of cf hashes that may be requested with one getcfheaders. See BIP 157. */ @@ -312,7 +320,7 @@ public: /** Implement PeerManager */ void StartScheduledTasks(CScheduler& scheduler) override; void CheckForStaleTipAndEvictPeers() override; - bool FetchBlock(NodeId id, const uint256& hash, const CBlockIndex& index) override; + std::optional<std::string> FetchBlock(NodeId peer_id, const CBlockIndex& block_index) override; bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override; bool IgnoresIncomingTxs() override { return m_ignore_incoming_txs; } void SendPings() override; @@ -327,7 +335,7 @@ private: EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** Consider evicting an outbound peer based on the amount of time they've been behind our tip */ - void ConsiderEviction(CNode& pto, int64_t time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + void ConsiderEviction(CNode& pto, std::chrono::seconds time_in_seconds) EXCLUSIVE_LOCKS_REQUIRED(cs_main); /** If we have extra outbound peers, try to disconnect the one with the oldest block announcement */ void EvictExtraOutboundPeers(std::chrono::seconds now) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -422,7 +430,7 @@ private: std::atomic<int> m_best_height{-1}; /** Next time to check for stale tip */ - int64_t m_stale_tip_check_time{0}; + std::chrono::seconds m_stale_tip_check_time{0s}; /** Whether this node is running in blocks only mode */ const bool m_ignore_incoming_txs; @@ -442,6 +450,8 @@ private: */ std::map<NodeId, PeerRef> m_peer_map GUARDED_BY(m_peer_mutex); + std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us}; + /** Number of nodes with fSyncStarted. */ int nSyncStarted GUARDED_BY(cs_main) = 0; @@ -516,6 +526,15 @@ private: Mutex m_recent_confirmed_transactions_mutex; CRollingBloomFilter m_recent_confirmed_transactions GUARDED_BY(m_recent_confirmed_transactions_mutex){48'000, 0.000'001}; + /** + * For sending `inv`s to inbound peers, we use a single (exponentially + * distributed) timer for all peers. If we used a separate timer for each + * peer, a spy node could make multiple inbound connections to us to + * accurately determine when we received the transaction (and potentially + * determine the transaction's origin). */ + std::chrono::microseconds NextInvToInbounds(std::chrono::microseconds now, + std::chrono::seconds average_interval); + /** Have we requested this block from a peer */ bool IsBlockRequested(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -541,7 +560,7 @@ private: std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> > mapBlocksInFlight GUARDED_BY(cs_main); /** When our tip was last updated. */ - std::atomic<int64_t> m_last_tip_update{0}; + std::atomic<std::chrono::seconds> m_last_tip_update{0s}; /** Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */ CTransactionRef FindTxForGetData(const CNode& peer, const GenTxid& gtxid, const std::chrono::seconds mempool_req, const std::chrono::seconds now) LOCKS_EXCLUDED(cs_main); @@ -725,7 +744,7 @@ struct CNodeState { * - its chain tip has at least as much work as ours * * CHAIN_SYNC_TIMEOUT: if a peer's best known block has less work than our tip, - * set a timeout CHAIN_SYNC_TIMEOUT seconds in the future: + * set a timeout CHAIN_SYNC_TIMEOUT in the future: * - If at timeout their best known block now has more work than our tip * when the timeout was set, then either reset the timeout or clear it * (after comparing against our current tip's work) @@ -740,7 +759,7 @@ struct CNodeState { */ struct ChainSyncTimeoutState { //! A timeout used for checking whether our peer has sufficiently synced - int64_t m_timeout{0}; + std::chrono::seconds m_timeout{0s}; //! A header with the work we require on our peer's chain const CBlockIndex* m_work_header{nullptr}; //! After timeout is reached, set to true after sending getheaders @@ -817,6 +836,18 @@ static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUS nPreferredDownload += state->fPreferredDownload; } +std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now, + std::chrono::seconds average_interval) +{ + if (m_next_inv_to_inbounds.load() < now) { + // If this function were called from multiple threads simultaneously + // it would possible that both update the next send variable, and return a different result to their caller. + // This is not possible in practice as only the net processing thread invokes this function. + m_next_inv_to_inbounds = GetExponentialRand(now, average_interval); + } + return m_next_inv_to_inbounds; +} + bool PeerManagerImpl::IsBlockRequested(const uint256& hash) { return mapBlocksInFlight.find(hash) != mapBlocksInFlight.end(); @@ -947,10 +978,10 @@ bool PeerManagerImpl::TipMayBeStale() { AssertLockHeld(cs_main); const Consensus::Params& consensusParams = m_chainparams.GetConsensus(); - if (m_last_tip_update == 0) { - m_last_tip_update = GetTime(); + if (m_last_tip_update.load() == 0s) { + m_last_tip_update = GetTime<std::chrono::seconds>(); } - return m_last_tip_update < GetTime() - consensusParams.nPowTargetSpacing * 3 && mapBlocksInFlight.empty(); + return m_last_tip_update.load() < GetTime<std::chrono::seconds>() - std::chrono::seconds{consensusParams.nPowTargetSpacing * 3} && mapBlocksInFlight.empty(); } bool PeerManagerImpl::CanDirectFetch() @@ -1135,7 +1166,7 @@ void PeerManagerImpl::AddTxAnnouncement(const CNode& node, const GenTxid& gtxid, // - TXID_RELAY_DELAY for txid announcements while wtxid peers are available // - OVERLOADED_PEER_TX_DELAY for announcements from peers which have at least // MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have NetPermissionFlags::Relay). - auto delay = std::chrono::microseconds{0}; + auto delay{0us}; const bool preferred = state->fPreferredDownload; if (!preferred) delay += NONPREF_PEER_TX_DELAY; if (!gtxid.IsWtxid() && m_wtxid_relay_peers > 0) delay += TXID_RELAY_DELAY; @@ -1189,7 +1220,7 @@ void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler) // Schedule next run for 10-15 minutes in the future. // We add randomness on every cycle to avoid the possibility of P2P fingerprinting. - const std::chrono::milliseconds delta = std::chrono::minutes{10} + GetRandMillis(std::chrono::minutes{5}); + const std::chrono::milliseconds delta = 10min + GetRandMillis(5min); scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } @@ -1294,7 +1325,7 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c // since pingtime does not update until the ping is complete, which might take a while. // So, if a ping is taking an unusually long time in flight, // the caller can immediately detect that this is happening. - std::chrono::microseconds ping_wait{0}; + auto ping_wait{0us}; if ((0 != peer->m_ping_nonce_sent) && (0 != peer->m_ping_start.load().count())) { ping_wait = GetTime<std::chrono::microseconds>() - peer->m_ping_start.load(); } @@ -1429,39 +1460,39 @@ bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex) (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT); } -bool PeerManagerImpl::FetchBlock(NodeId id, const uint256& hash, const CBlockIndex& index) +std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBlockIndex& block_index) { - if (fImporting || fReindex) return false; + if (fImporting) return "Importing..."; + if (fReindex) return "Reindexing..."; LOCK(cs_main); // Ensure this peer exists and hasn't been disconnected - CNodeState* state = State(id); - if (state == nullptr) return false; + CNodeState* state = State(peer_id); + if (state == nullptr) return "Peer does not exist"; // Ignore pre-segwit peers - if (!state->fHaveWitness) return false; + if (!state->fHaveWitness) return "Pre-SegWit peer"; - // Mark block as in-flight unless it already is - if (!BlockRequested(id, index)) return false; + // 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 + // response will be dropped. + if (!BlockRequested(peer_id, block_index)) return "Already requested from this peer"; // Construct message to request the block + const uint256& hash{block_index.GetBlockHash()}; std::vector<CInv> invs{CInv(MSG_BLOCK | MSG_WITNESS_FLAG, hash)}; // Send block request message to the peer - bool success = m_connman.ForNode(id, [this, &invs](CNode* node) { + bool success = m_connman.ForNode(peer_id, [this, &invs](CNode* node) { const CNetMsgMaker msgMaker(node->GetCommonVersion()); this->m_connman.PushMessage(node, msgMaker.Make(NetMsgType::GETDATA, invs)); return true; }); - if (success) { - LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", - hash.ToString(), id); - } else { - RemoveBlockRequest(hash); - LogPrint(BCLog::NET, "Failed to request block %s from peer=%d\n", - hash.ToString(), id); - } - return success; + if (!success) return "Peer not fully connected"; + + LogPrint(BCLog::NET, "Requesting block %s from peer=%d\n", + hash.ToString(), peer_id); + return std::nullopt; } std::unique_ptr<PeerManager> PeerManager::make(const CChainParams& chainparams, CConnman& connman, AddrMan& addrman, @@ -1494,7 +1525,7 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler) scheduler.scheduleEvery([this] { this->CheckForStaleTipAndEvictPeers(); }, std::chrono::seconds{EXTRA_PEER_CHECK_INTERVAL}); // schedule next run for 10-15 minutes in the future - const std::chrono::milliseconds delta = std::chrono::minutes{10} + GetRandMillis(std::chrono::minutes{5}); + const std::chrono::milliseconds delta = 10min + GetRandMillis(5min); scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } @@ -1506,7 +1537,7 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler) void PeerManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex) { m_orphanage.EraseForBlock(*pblock); - m_last_tip_update = GetTime(); + m_last_tip_update = GetTime<std::chrono::seconds>(); { LOCK(m_recent_confirmed_transactions_mutex); @@ -1744,8 +1775,8 @@ void PeerManagerImpl::RelayAddress(NodeId originator, // Relay to a limited number of other nodes // Use deterministic randomness to send to the same nodes for 24 hours // at a time so the m_addr_knowns of the chosen nodes prevent repeats - uint64_t hashAddr = addr.GetHash(); - const CSipHasher hasher = m_connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24 * 60 * 60)); + const uint64_t hashAddr{addr.GetHash()}; + const CSipHasher hasher{m_connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr).Write((GetTime() + hashAddr) / (24 * 60 * 60))}; FastRandomContext insecure_rand; // Relay reachable addresses to 2 peers. Unreachable addresses are relayed randomly to 1 or 2 peers. @@ -1849,7 +1880,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& // Fast-path: in this case it is possible to serve the block directly from disk, // as the network format matches the format on disk std::vector<uint8_t> block_data; - if (!ReadRawBlockFromDisk(block_data, pindex, m_chainparams.MessageStart())) { + if (!ReadRawBlockFromDisk(block_data, pindex->GetBlockPos(), m_chainparams.MessageStart())) { assert(!"cannot load block from disk"); } m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, Span{block_data})); @@ -1961,10 +1992,9 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic std::vector<CInv> vNotFound; const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); - const std::chrono::seconds now = GetTime<std::chrono::seconds>(); + const auto now{GetTime<std::chrono::seconds>()}; // Get last mempool request time - const std::chrono::seconds mempool_req = pfrom.m_tx_relay != nullptr ? pfrom.m_tx_relay->m_last_mempool_req.load() - : std::chrono::seconds::min(); + const auto mempool_req = pfrom.m_tx_relay != nullptr ? pfrom.m_tx_relay->m_last_mempool_req.load() : std::chrono::seconds::min(); // Process as many TX items from the front of the getdata queue as // possible, since they're common and it's efficient to batch process @@ -2629,7 +2659,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, pfrom.nServices = nServices; pfrom.SetAddrLocal(addrMe); { - LOCK(pfrom.cs_SubVer); + LOCK(pfrom.m_subver_mutex); pfrom.cleanSubVer = cleanSubVer; } peer->m_starting_height = starting_height; @@ -2888,7 +2918,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, int64_t nSince = nNow - 10 * 60; // Update/increment addr rate limiting bucket. - const auto current_time = GetTime<std::chrono::microseconds>(); + const auto current_time{GetTime<std::chrono::microseconds>()}; if (peer->m_addr_token_bucket < MAX_ADDR_PROCESSING_TOKEN_BUCKET) { // Don't increment bucket if it's already full const auto time_diff = std::max(current_time - peer->m_addr_token_timestamp, 0us); @@ -2974,7 +3004,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, LOCK(cs_main); - const auto current_time = GetTime<std::chrono::microseconds>(); + const auto current_time{GetTime<std::chrono::microseconds>()}; uint256* best_block{nullptr}; for (CInv& inv : vInv) { @@ -3352,7 +3382,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, } } if (!fRejectedParents) { - const auto current_time = GetTime<std::chrono::microseconds>(); + const auto current_time{GetTime<std::chrono::microseconds>()}; for (const uint256& parent_txid : unique_parents) { // Here, we only have the txid (and not wtxid) of the @@ -4147,38 +4177,34 @@ bool PeerManagerImpl::ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt pfrom->GetId(), pfrom->m_addr_name.c_str(), pfrom->ConnectionTypeAsString().c_str(), - msg.m_command.c_str(), + msg.m_type.c_str(), msg.m_recv.size(), msg.m_recv.data() ); if (gArgs.GetBoolArg("-capturemessages", false)) { - CaptureMessage(pfrom->addr, msg.m_command, MakeUCharSpan(msg.m_recv), /*is_incoming=*/true); + CaptureMessage(pfrom->addr, msg.m_type, MakeUCharSpan(msg.m_recv), /*is_incoming=*/true); } msg.SetVersion(pfrom->GetCommonVersion()); - const std::string& msg_type = msg.m_command; - - // Message size - unsigned int nMessageSize = msg.m_message_size; try { - ProcessMessage(*pfrom, msg_type, msg.m_recv, msg.m_time, interruptMsgProc); + ProcessMessage(*pfrom, msg.m_type, msg.m_recv, msg.m_time, interruptMsgProc); if (interruptMsgProc) return false; { LOCK(peer->m_getdata_requests_mutex); if (!peer->m_getdata_requests.empty()) fMoreWork = true; } } catch (const std::exception& e) { - LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' (%s) caught\n", __func__, SanitizeString(msg_type), nMessageSize, e.what(), typeid(e).name()); + LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' (%s) caught\n", __func__, SanitizeString(msg.m_type), msg.m_message_size, e.what(), typeid(e).name()); } catch (...) { - LogPrint(BCLog::NET, "%s(%s, %u bytes): Unknown exception caught\n", __func__, SanitizeString(msg_type), nMessageSize); + LogPrint(BCLog::NET, "%s(%s, %u bytes): Unknown exception caught\n", __func__, SanitizeString(msg.m_type), msg.m_message_size); } return fMoreWork; } -void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds) +void PeerManagerImpl::ConsiderEviction(CNode& pto, std::chrono::seconds time_in_seconds) { AssertLockHeld(cs_main); @@ -4193,12 +4219,12 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds) // unless it's invalid, in which case we should find that out and // disconnect from them elsewhere). if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= m_chainman.ActiveChain().Tip()->nChainWork) { - if (state.m_chain_sync.m_timeout != 0) { - state.m_chain_sync.m_timeout = 0; + if (state.m_chain_sync.m_timeout != 0s) { + state.m_chain_sync.m_timeout = 0s; state.m_chain_sync.m_work_header = nullptr; state.m_chain_sync.m_sent_getheaders = false; } - } else if (state.m_chain_sync.m_timeout == 0 || (state.m_chain_sync.m_work_header != nullptr && state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= state.m_chain_sync.m_work_header->nChainWork)) { + } else if (state.m_chain_sync.m_timeout == 0s || (state.m_chain_sync.m_work_header != nullptr && state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= state.m_chain_sync.m_work_header->nChainWork)) { // Our best block known by this peer is behind our tip, and we're either noticing // that for the first time, OR this peer was able to catch up to some earlier point // where we checked against our tip. @@ -4206,7 +4232,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds) state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT; state.m_chain_sync.m_work_header = m_chainman.ActiveChain().Tip(); state.m_chain_sync.m_sent_getheaders = false; - } else if (state.m_chain_sync.m_timeout > 0 && time_in_seconds > state.m_chain_sync.m_timeout) { + } else if (state.m_chain_sync.m_timeout > 0s && time_in_seconds > state.m_chain_sync.m_timeout) { // No evidence yet that our peer has synced to a chain with work equal to that // of our tip, when we first detected it was behind. Send a single getheaders // message to give the peer a chance to update us. @@ -4219,7 +4245,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds) LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString()); m_connman.PushMessage(&pto, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256())); state.m_chain_sync.m_sent_getheaders = true; - constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes + constexpr auto HEADERS_RESPONSE_TIME{2min}; // Bump the timeout to allow a response, which could clear the timeout // (if the response shows the peer has synced), reset the timeout (if // the peer syncs to the required work but not to our tip), or result @@ -4338,20 +4364,21 @@ void PeerManagerImpl::CheckForStaleTipAndEvictPeers() { LOCK(cs_main); - int64_t time_in_seconds = GetTime(); + auto now{GetTime<std::chrono::seconds>()}; - EvictExtraOutboundPeers(std::chrono::seconds{time_in_seconds}); + EvictExtraOutboundPeers(now); - if (time_in_seconds > m_stale_tip_check_time) { + if (now > m_stale_tip_check_time) { // Check whether our tip is stale, and if so, allow using an extra // outbound peer if (!fImporting && !fReindex && m_connman.GetNetworkActive() && m_connman.GetUseAddrmanOutgoing() && TipMayBeStale()) { - LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n", time_in_seconds - m_last_tip_update); + LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n", + count_seconds(now - m_last_tip_update.load())); m_connman.SetTryNewOutboundPeer(true); } else if (m_connman.GetTryNewOutboundPeer()) { m_connman.SetTryNewOutboundPeer(false); } - m_stale_tip_check_time = time_in_seconds + STALE_CHECK_INTERVAL; + m_stale_tip_check_time = now + STALE_CHECK_INTERVAL; } if (!m_initial_sync_finished && CanDirectFetch()) { @@ -4426,13 +4453,13 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros FastRandomContext insecure_rand; PushAddress(peer, *local_addr, insecure_rand); } - peer.m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); + peer.m_next_local_addr_send = GetExponentialRand(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); } // We sent an `addr` message to this peer recently. Nothing more to do. if (current_time <= peer.m_next_addr_send) return; - peer.m_next_addr_send = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL); + peer.m_next_addr_send = GetExponentialRand(current_time, AVG_ADDRESS_BROADCAST_INTERVAL); if (!Assume(peer.m_addrs_to_send.size() <= MAX_ADDR_TO_SEND)) { // Should be impossible since we always check size before adding to @@ -4504,7 +4531,7 @@ void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, std::chrono::microseconds c m_connman.PushMessage(&pto, CNetMsgMaker(pto.GetCommonVersion()).Make(NetMsgType::FEEFILTER, filterToSend)); pto.m_tx_relay->lastSentFeeFilter = filterToSend; } - pto.m_tx_relay->m_next_send_feefilter = PoissonNextSend(current_time, AVG_FEEFILTER_BROADCAST_INTERVAL); + pto.m_tx_relay->m_next_send_feefilter = GetExponentialRand(current_time, AVG_FEEFILTER_BROADCAST_INTERVAL); } // If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. @@ -4568,7 +4595,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // If we get here, the outgoing message serialization version is set and can't change. const CNetMsgMaker msgMaker(pto->GetCommonVersion()); - const auto current_time = GetTime<std::chrono::microseconds>(); + const auto current_time{GetTime<std::chrono::microseconds>()}; if (pto->IsAddrFetchConn() && current_time - pto->m_connected > 10 * AVG_ADDRESS_BROADCAST_INTERVAL) { LogPrint(BCLog::NET, "addrfetch connection timeout; disconnecting peer=%d\n", pto->GetId()); @@ -4784,9 +4811,9 @@ bool PeerManagerImpl::SendMessages(CNode* pto) if (pto->m_tx_relay->nNextInvSend < current_time) { fSendTrickle = true; if (pto->IsInboundConn()) { - pto->m_tx_relay->nNextInvSend = m_connman.PoissonNextSendInbound(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL); + pto->m_tx_relay->nNextInvSend = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL); } else { - pto->m_tx_relay->nNextInvSend = PoissonNextSend(current_time, OUTBOUND_INVENTORY_BROADCAST_INTERVAL); + pto->m_tx_relay->nNextInvSend = GetExponentialRand(current_time, OUTBOUND_INVENTORY_BROADCAST_INTERVAL); } } @@ -4967,7 +4994,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // Check that outbound peers have reasonable chains // GetTime() is used by this anti-DoS logic so we can test this using mocktime - ConsiderEviction(*pto, GetTime()); + ConsiderEviction(*pto, GetTime<std::chrono::seconds>()); // // Message: getdata (blocks) diff --git a/src/net_processing.h b/src/net_processing.h index 6c18e8ddfa..e30f9f516c 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -45,12 +45,11 @@ public: /** * Attempt to manually fetch block from a given peer. We must already have the header. * - * @param[in] id The peer id - * @param[in] hash The block hash - * @param[in] pindex The blockindex - * @returns Whether a request was successfully made + * @param[in] peer_id The peer id + * @param[in] block_index The blockindex + * @returns std::nullopt if a request was successfully made, otherwise an error message */ - virtual bool FetchBlock(NodeId id, const uint256& hash, const CBlockIndex& pindex) = 0; + virtual std::optional<std::string> FetchBlock(NodeId peer_id, const CBlockIndex& block_index) = 0; /** Begin running background tasks, should only be called once */ virtual void StartScheduledTasks(CScheduler& scheduler) = 0; diff --git a/src/net_types.h b/src/net_types.h index ffdc24c772..b9e019d8fd 100644 --- a/src/net_types.h +++ b/src/net_types.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/netaddress.cpp b/src/netaddress.cpp index f6bc7fbb94..4874b82eca 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/netaddress.h b/src/netaddress.h index c8af4a9605..b06b6c65b6 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/netbase.cpp b/src/netbase.cpp index 0b68c0d041..87014a0644 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/netbase.h b/src/netbase.h index f3d8f15788..980aa47d66 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 53bc2b5069..8a99130fd0 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -12,6 +12,7 @@ #include <fs.h> #include <hash.h> #include <pow.h> +#include <reverse_iterator.h> #include <shutdown.h> #include <signet.h> #include <streams.h> @@ -20,42 +21,422 @@ #include <util/system.h> #include <validation.h> +namespace node { std::atomic_bool fImporting(false); std::atomic_bool fReindex(false); bool fHavePruned = false; bool fPruneMode = false; uint64_t nPruneTarget = 0; -// TODO make namespace { -RecursiveMutex cs_LastBlockFile; -std::vector<CBlockFileInfo> vinfoBlockFile; -int nLastBlockFile = 0; -/** Global flag to indicate we should check to see if there are -* block/undo files that should be deleted. Set on startup -* or if we allocate more file space when we're in prune mode -*/ -bool fCheckForPruning = false; - -/** Dirty block index entries. */ -std::set<CBlockIndex*> setDirtyBlockIndex; - -/** Dirty block file entries. */ -std::set<int> setDirtyFileInfo; -// } // namespace - static FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false); static FlatFileSeq BlockFileSeq(); static FlatFileSeq UndoFileSeq(); +CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const +{ + AssertLockHeld(cs_main); + BlockMap::const_iterator it = m_block_index.find(hash); + return it == m_block_index.end() ? nullptr : it->second; +} + +CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block) +{ + AssertLockHeld(cs_main); + + // Check for duplicate + uint256 hash = block.GetHash(); + BlockMap::iterator it = m_block_index.find(hash); + if (it != m_block_index.end()) { + return it->second; + } + + // Construct new block index object + CBlockIndex* pindexNew = new CBlockIndex(block); + // We assign the sequence id to blocks only when the full data is available, + // to avoid miners withholding blocks but broadcasting headers, to get a + // competitive advantage. + pindexNew->nSequenceId = 0; + BlockMap::iterator mi = m_block_index.insert(std::make_pair(hash, pindexNew)).first; + pindexNew->phashBlock = &((*mi).first); + BlockMap::iterator miPrev = m_block_index.find(block.hashPrevBlock); + if (miPrev != m_block_index.end()) { + pindexNew->pprev = (*miPrev).second; + pindexNew->nHeight = pindexNew->pprev->nHeight + 1; + pindexNew->BuildSkip(); + } + pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime); + pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); + pindexNew->RaiseValidity(BLOCK_VALID_TREE); + if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork) + pindexBestHeader = pindexNew; + + m_dirty_blockindex.insert(pindexNew); + + return pindexNew; +} + +void BlockManager::PruneOneBlockFile(const int fileNumber) +{ + AssertLockHeld(cs_main); + LOCK(cs_LastBlockFile); + + for (const auto& entry : m_block_index) { + CBlockIndex* pindex = entry.second; + if (pindex->nFile == fileNumber) { + pindex->nStatus &= ~BLOCK_HAVE_DATA; + pindex->nStatus &= ~BLOCK_HAVE_UNDO; + pindex->nFile = 0; + pindex->nDataPos = 0; + pindex->nUndoPos = 0; + m_dirty_blockindex.insert(pindex); + + // Prune from m_blocks_unlinked -- any block we prune would have + // to be downloaded again in order to consider its chain, at which + // point it would be considered as a candidate for + // m_blocks_unlinked or setBlockIndexCandidates. + auto range = m_blocks_unlinked.equal_range(pindex->pprev); + while (range.first != range.second) { + std::multimap<CBlockIndex*, CBlockIndex*>::iterator _it = range.first; + range.first++; + if (_it->second == pindex) { + m_blocks_unlinked.erase(_it); + } + } + } + } + + m_blockfile_info[fileNumber].SetNull(); + m_dirty_fileinfo.insert(fileNumber); +} + +void BlockManager::FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height) +{ + assert(fPruneMode && nManualPruneHeight > 0); + + LOCK2(cs_main, cs_LastBlockFile); + if (chain_tip_height < 0) { + return; + } + + // last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip) + unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chain_tip_height - MIN_BLOCKS_TO_KEEP); + int count = 0; + for (int fileNumber = 0; fileNumber < m_last_blockfile; fileNumber++) { + if (m_blockfile_info[fileNumber].nSize == 0 || m_blockfile_info[fileNumber].nHeightLast > nLastBlockWeCanPrune) { + continue; + } + PruneOneBlockFile(fileNumber); + setFilesToPrune.insert(fileNumber); + count++; + } + LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", nLastBlockWeCanPrune, count); +} + +void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd) +{ + LOCK2(cs_main, cs_LastBlockFile); + if (chain_tip_height < 0 || nPruneTarget == 0) { + return; + } + if ((uint64_t)chain_tip_height <= nPruneAfterHeight) { + return; + } + + unsigned int nLastBlockWeCanPrune{(unsigned)std::min(prune_height, chain_tip_height - static_cast<int>(MIN_BLOCKS_TO_KEEP))}; + uint64_t nCurrentUsage = CalculateCurrentUsage(); + // We don't check to prune until after we've allocated new space for files + // So we should leave a buffer under our target to account for another allocation + // before the next pruning. + uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE; + uint64_t nBytesToPrune; + int count = 0; + + if (nCurrentUsage + nBuffer >= nPruneTarget) { + // On a prune event, the chainstate DB is flushed. + // To avoid excessive prune events negating the benefit of high dbcache + // values, we should not prune too rapidly. + // So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon. + if (is_ibd) { + // Since this is only relevant during IBD, we use a fixed 10% + nBuffer += nPruneTarget / 10; + } + + for (int fileNumber = 0; fileNumber < m_last_blockfile; fileNumber++) { + nBytesToPrune = m_blockfile_info[fileNumber].nSize + m_blockfile_info[fileNumber].nUndoSize; + + if (m_blockfile_info[fileNumber].nSize == 0) { + continue; + } + + if (nCurrentUsage + nBuffer < nPruneTarget) { // are we below our target? + break; + } + + // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning + if (m_blockfile_info[fileNumber].nHeightLast > nLastBlockWeCanPrune) { + continue; + } + + PruneOneBlockFile(fileNumber); + // Queue up the files for removal + setFilesToPrune.insert(fileNumber); + nCurrentUsage -= nBytesToPrune; + count++; + } + } + + LogPrint(BCLog::PRUNE, "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n", + nPruneTarget/1024/1024, nCurrentUsage/1024/1024, + ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024, + nLastBlockWeCanPrune, count); +} + +CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash) +{ + AssertLockHeld(cs_main); + + if (hash.IsNull()) { + return nullptr; + } + + // Return existing + BlockMap::iterator mi = m_block_index.find(hash); + if (mi != m_block_index.end()) { + return (*mi).second; + } + + // Create new + CBlockIndex* pindexNew = new CBlockIndex(); + mi = m_block_index.insert(std::make_pair(hash, pindexNew)).first; + pindexNew->phashBlock = &((*mi).first); + + return pindexNew; +} + +bool BlockManager::LoadBlockIndex( + const Consensus::Params& consensus_params, + ChainstateManager& chainman) +{ + if (!m_block_tree_db->LoadBlockIndexGuts(consensus_params, [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); })) { + return false; + } + + // Calculate nChainWork + std::vector<std::pair<int, CBlockIndex*>> vSortedByHeight; + vSortedByHeight.reserve(m_block_index.size()); + for (const std::pair<const uint256, CBlockIndex*>& item : m_block_index) { + CBlockIndex* pindex = item.second; + vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex)); + } + sort(vSortedByHeight.begin(), vSortedByHeight.end()); + + // Find start of assumed-valid region. + int first_assumed_valid_height = std::numeric_limits<int>::max(); + + for (const auto& [height, block] : vSortedByHeight) { + if (block->IsAssumedValid()) { + auto chainstates = chainman.GetAll(); + + // If we encounter an assumed-valid block index entry, ensure that we have + // one chainstate that tolerates assumed-valid entries and another that does + // not (i.e. the background validation chainstate), since assumed-valid + // entries should always be pending validation by a fully-validated chainstate. + auto any_chain = [&](auto fnc) { return std::any_of(chainstates.cbegin(), chainstates.cend(), fnc); }; + assert(any_chain([](auto chainstate) { return chainstate->reliesOnAssumedValid(); })); + assert(any_chain([](auto chainstate) { return !chainstate->reliesOnAssumedValid(); })); + + first_assumed_valid_height = height; + break; + } + } + + for (const std::pair<int, CBlockIndex*>& item : vSortedByHeight) { + if (ShutdownRequested()) return false; + CBlockIndex* pindex = item.second; + pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); + pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime); + + // We can link the chain of blocks for which we've received transactions at some point, or + // blocks that are assumed-valid on the basis of snapshot load (see + // PopulateAndValidateSnapshot()). + // Pruned nodes may have deleted the block. + if (pindex->nTx > 0) { + if (pindex->pprev) { + if (pindex->pprev->nChainTx > 0) { + pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx; + } else { + pindex->nChainTx = 0; + m_blocks_unlinked.insert(std::make_pair(pindex->pprev, pindex)); + } + } else { + pindex->nChainTx = pindex->nTx; + } + } + if (!(pindex->nStatus & BLOCK_FAILED_MASK) && pindex->pprev && (pindex->pprev->nStatus & BLOCK_FAILED_MASK)) { + pindex->nStatus |= BLOCK_FAILED_CHILD; + m_dirty_blockindex.insert(pindex); + } + if (pindex->IsAssumedValid() || + (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && + (pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))) { + + // Fill each chainstate's block candidate set. Only add assumed-valid + // blocks to the tip candidate set if the chainstate is allowed to rely on + // assumed-valid blocks. + // + // If all setBlockIndexCandidates contained the assumed-valid blocks, the + // background chainstate's ActivateBestChain() call would add assumed-valid + // blocks to the chain (based on how FindMostWorkChain() works). Obviously + // we don't want this since the purpose of the background validation chain + // is to validate assued-valid blocks. + // + // Note: This is considering all blocks whose height is greater or equal to + // the first assumed-valid block to be assumed-valid blocks, and excluding + // them from the background chainstate's setBlockIndexCandidates set. This + // does mean that some blocks which are not technically assumed-valid + // (later blocks on a fork beginning before the first assumed-valid block) + // might not get added to the background chainstate, but this is ok, + // because they will still be attached to the active chainstate if they + // actually contain more work. + // + // Instead of this height-based approach, an earlier attempt was made at + // detecting "holistically" whether the block index under consideration + // relied on an assumed-valid ancestor, but this proved to be too slow to + // be practical. + for (CChainState* chainstate : chainman.GetAll()) { + if (chainstate->reliesOnAssumedValid() || + pindex->nHeight < first_assumed_valid_height) { + chainstate->setBlockIndexCandidates.insert(pindex); + } + } + } + if (pindex->nStatus & BLOCK_FAILED_MASK && (!chainman.m_best_invalid || pindex->nChainWork > chainman.m_best_invalid->nChainWork)) { + chainman.m_best_invalid = pindex; + } + if (pindex->pprev) { + pindex->BuildSkip(); + } + if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == nullptr || CBlockIndexWorkComparator()(pindexBestHeader, pindex))) + pindexBestHeader = pindex; + } + + return true; +} + +void BlockManager::Unload() +{ + m_blocks_unlinked.clear(); + + for (const BlockMap::value_type& entry : m_block_index) { + delete entry.second; + } + + m_block_index.clear(); + + m_blockfile_info.clear(); + m_last_blockfile = 0; + m_dirty_blockindex.clear(); + m_dirty_fileinfo.clear(); +} + +bool BlockManager::WriteBlockIndexDB() +{ + AssertLockHeld(::cs_main); + std::vector<std::pair<int, const CBlockFileInfo*>> vFiles; + vFiles.reserve(m_dirty_fileinfo.size()); + for (std::set<int>::iterator it = m_dirty_fileinfo.begin(); it != m_dirty_fileinfo.end();) { + vFiles.push_back(std::make_pair(*it, &m_blockfile_info[*it])); + m_dirty_fileinfo.erase(it++); + } + std::vector<const CBlockIndex*> vBlocks; + vBlocks.reserve(m_dirty_blockindex.size()); + for (std::set<CBlockIndex*>::iterator it = m_dirty_blockindex.begin(); it != m_dirty_blockindex.end();) { + vBlocks.push_back(*it); + m_dirty_blockindex.erase(it++); + } + if (!m_block_tree_db->WriteBatchSync(vFiles, m_last_blockfile, vBlocks)) { + return false; + } + return true; +} + +bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman) +{ + if (!LoadBlockIndex(::Params().GetConsensus(), chainman)) { + return false; + } + + // Load block file info + m_block_tree_db->ReadLastBlockFile(m_last_blockfile); + m_blockfile_info.resize(m_last_blockfile + 1); + LogPrintf("%s: last block file = %i\n", __func__, m_last_blockfile); + for (int nFile = 0; nFile <= m_last_blockfile; nFile++) { + m_block_tree_db->ReadBlockFileInfo(nFile, m_blockfile_info[nFile]); + } + LogPrintf("%s: last block file info: %s\n", __func__, m_blockfile_info[m_last_blockfile].ToString()); + for (int nFile = m_last_blockfile + 1; true; nFile++) { + CBlockFileInfo info; + if (m_block_tree_db->ReadBlockFileInfo(nFile, info)) { + m_blockfile_info.push_back(info); + } else { + break; + } + } + + // Check presence of blk files + LogPrintf("Checking all blk files are present...\n"); + std::set<int> setBlkDataFiles; + for (const std::pair<const uint256, CBlockIndex*>& item : m_block_index) { + CBlockIndex* pindex = item.second; + if (pindex->nStatus & BLOCK_HAVE_DATA) { + setBlkDataFiles.insert(pindex->nFile); + } + } + for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) { + FlatFilePos pos(*it, 0); + if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) { + return false; + } + } + + // Check whether we have ever pruned block & undo files + m_block_tree_db->ReadFlag("prunedblockfiles", fHavePruned); + if (fHavePruned) { + LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n"); + } + + // Check whether we need to continue reindexing + bool fReindexing = false; + m_block_tree_db->ReadReindexing(fReindexing); + if (fReindexing) fReindex = true; + + return true; +} + +CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data) +{ + const MapCheckpoints& checkpoints = data.mapCheckpoints; + + for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints)) { + const uint256& hash = i.second; + CBlockIndex* pindex = LookupBlockIndex(hash); + if (pindex) { + return pindex; + } + } + return nullptr; +} + bool IsBlockPruned(const CBlockIndex* pblockindex) { + AssertLockHeld(::cs_main); return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0); } // If we're using -prune with -reindex, then delete block files that will be ignored by the // reindex. Since reindexing works by starting at block file 0 and looping until a blockfile // is missing, do the same here to delete any later block files after a gap. Also delete all -// rev files since they'll be rewritten by the reindex anyway. This ensures that vinfoBlockFile +// rev files since they'll be rewritten by the reindex anyway. This ensures that m_blockfile_info // is in sync with what's actually on disk by the time we start downloading, so that pruning // works correctly. void CleanupBlockRevFiles() @@ -95,16 +476,11 @@ void CleanupBlockRevFiles() } } -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)); -} - -CBlockFileInfo* GetBlockFileInfo(size_t n) +CBlockFileInfo* BlockManager::GetBlockFileInfo(size_t n) { LOCK(cs_LastBlockFile); - return &vinfoBlockFile.at(n); + return &m_blockfile_info.at(n); } static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) @@ -138,7 +514,8 @@ static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex) { - FlatFilePos pos = pindex->GetUndoPos(); + const FlatFilePos pos{WITH_LOCK(::cs_main, return pindex->GetUndoPos())}; + if (pos.IsNull()) { return error("%s: no undo data available", __func__); } @@ -168,32 +545,32 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex) return true; } -static void FlushUndoFile(int block_file, bool finalize = false) +void BlockManager::FlushUndoFile(int block_file, bool finalize) { - FlatFilePos undo_pos_old(block_file, vinfoBlockFile[block_file].nUndoSize); + FlatFilePos undo_pos_old(block_file, m_blockfile_info[block_file].nUndoSize); if (!UndoFileSeq().Flush(undo_pos_old, finalize)) { AbortNode("Flushing undo file to disk failed. This is likely the result of an I/O error."); } } -void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false) +void BlockManager::FlushBlockFile(bool fFinalize, bool finalize_undo) { LOCK(cs_LastBlockFile); - FlatFilePos block_pos_old(nLastBlockFile, vinfoBlockFile[nLastBlockFile].nSize); + FlatFilePos block_pos_old(m_last_blockfile, m_blockfile_info[m_last_blockfile].nSize); if (!BlockFileSeq().Flush(block_pos_old, fFinalize)) { AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error."); } // we do not always flush the undo file, as the chain tip may be lagging behind the incoming blocks, // e.g. during IBD or a sync after a node going offline - if (!fFinalize || finalize_undo) FlushUndoFile(nLastBlockFile, finalize_undo); + if (!fFinalize || finalize_undo) FlushUndoFile(m_last_blockfile, finalize_undo); } -uint64_t CalculateCurrentUsage() +uint64_t BlockManager::CalculateCurrentUsage() { LOCK(cs_LastBlockFile); uint64_t retval = 0; - for (const CBlockFileInfo& file : vinfoBlockFile) { + for (const CBlockFileInfo& file : m_blockfile_info) { retval += file.nSize + file.nUndoSize; } return retval; @@ -235,44 +612,44 @@ fs::path GetBlockPosFilename(const FlatFilePos& pos) return BlockFileSeq().FileName(pos); } -bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown = false) +bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown) { LOCK(cs_LastBlockFile); - unsigned int nFile = fKnown ? pos.nFile : nLastBlockFile; - if (vinfoBlockFile.size() <= nFile) { - vinfoBlockFile.resize(nFile + 1); + unsigned int nFile = fKnown ? pos.nFile : m_last_blockfile; + if (m_blockfile_info.size() <= nFile) { + m_blockfile_info.resize(nFile + 1); } bool finalize_undo = false; if (!fKnown) { - while (vinfoBlockFile[nFile].nSize + nAddSize >= (gArgs.GetBoolArg("-fastprune", false) ? 0x10000 /* 64kb */ : MAX_BLOCKFILE_SIZE)) { + while (m_blockfile_info[nFile].nSize + nAddSize >= (gArgs.GetBoolArg("-fastprune", false) ? 0x10000 /* 64kb */ : MAX_BLOCKFILE_SIZE)) { // when the undo file is keeping up with the block file, we want to flush it explicitly // when it is lagging behind (more blocks arrive than are being connected), we let the // undo block write case handle it - finalize_undo = (vinfoBlockFile[nFile].nHeightLast == (unsigned int)active_chain.Tip()->nHeight); + finalize_undo = (m_blockfile_info[nFile].nHeightLast == (unsigned int)active_chain.Tip()->nHeight); nFile++; - if (vinfoBlockFile.size() <= nFile) { - vinfoBlockFile.resize(nFile + 1); + if (m_blockfile_info.size() <= nFile) { + m_blockfile_info.resize(nFile + 1); } } pos.nFile = nFile; - pos.nPos = vinfoBlockFile[nFile].nSize; + pos.nPos = m_blockfile_info[nFile].nSize; } - if ((int)nFile != nLastBlockFile) { + if ((int)nFile != m_last_blockfile) { if (!fKnown) { - LogPrint(BCLog::BLOCKSTORE, "Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString()); + LogPrint(BCLog::BLOCKSTORE, "Leaving block file %i: %s\n", m_last_blockfile, m_blockfile_info[m_last_blockfile].ToString()); } FlushBlockFile(!fKnown, finalize_undo); - nLastBlockFile = nFile; + m_last_blockfile = nFile; } - vinfoBlockFile[nFile].AddBlock(nHeight, nTime); + m_blockfile_info[nFile].AddBlock(nHeight, nTime); if (fKnown) { - vinfoBlockFile[nFile].nSize = std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize); + m_blockfile_info[nFile].nSize = std::max(pos.nPos + nAddSize, m_blockfile_info[nFile].nSize); } else { - vinfoBlockFile[nFile].nSize += nAddSize; + m_blockfile_info[nFile].nSize += nAddSize; } if (!fKnown) { @@ -282,23 +659,23 @@ bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, return AbortNode("Disk space is too low!", _("Disk space is too low!")); } if (bytes_allocated != 0 && fPruneMode) { - fCheckForPruning = true; + m_check_for_pruning = true; } } - setDirtyFileInfo.insert(nFile); + m_dirty_fileinfo.insert(nFile); return true; } -static bool FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize) +bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize) { pos.nFile = nFile; LOCK(cs_LastBlockFile); - pos.nPos = vinfoBlockFile[nFile].nUndoSize; - vinfoBlockFile[nFile].nUndoSize += nAddSize; - setDirtyFileInfo.insert(nFile); + pos.nPos = m_blockfile_info[nFile].nUndoSize; + m_blockfile_info[nFile].nUndoSize += nAddSize; + m_dirty_fileinfo.insert(nFile); bool out_of_space; size_t bytes_allocated = UndoFileSeq().Allocate(pos, nAddSize, out_of_space); @@ -306,7 +683,7 @@ static bool FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos return AbortNode(state, "Disk space is too low!", _("Disk space is too low!")); } if (bytes_allocated != 0 && fPruneMode) { - fCheckForPruning = true; + m_check_for_pruning = true; } return true; @@ -335,8 +712,9 @@ static bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessa return true; } -bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams) +bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams) { + AssertLockHeld(::cs_main); // Write undo information to disk if (pindex->GetUndoPos().IsNull()) { FlatFilePos _pos; @@ -351,14 +729,14 @@ bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& st // in the block file info as below; note that this does not catch the case where the undo writes are keeping up // with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in // the FindBlockPos function - if (_pos.nFile < nLastBlockFile && static_cast<uint32_t>(pindex->nHeight) == vinfoBlockFile[_pos.nFile].nHeightLast) { + if (_pos.nFile < m_last_blockfile && static_cast<uint32_t>(pindex->nHeight) == m_blockfile_info[_pos.nFile].nHeightLast) { FlushUndoFile(_pos.nFile, true); } // update nUndoPos in block index pindex->nUndoPos = _pos.nPos; pindex->nStatus |= BLOCK_HAVE_UNDO; - setDirtyBlockIndex.insert(pindex); + m_dirty_blockindex.insert(pindex); } return true; @@ -435,7 +813,7 @@ bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, c } block.resize(blk_size); // Zeroing of memory is intentional here - filein.read((char*)block.data(), blk_size); + filein.read(MakeWritableByteSpan(block)); } catch (const std::exception& e) { return error("%s: Read from block file failed: %s for %s", __func__, e.what(), pos.ToString()); } @@ -443,19 +821,8 @@ bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, c return true; } -bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, const CMessageHeader::MessageStartChars& message_start) -{ - FlatFilePos block_pos; - { - LOCK(cs_main); - block_pos = pindex->GetBlockPos(); - } - - return ReadRawBlockFromDisk(block, block_pos, message_start); -} - /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ -FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp) +FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp) { unsigned int nBlockSize = ::GetSerializeSize(block, CLIENT_VERSION); FlatFilePos blockPos; @@ -561,3 +928,4 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile } // End scope of CImportingNow chainman.ActiveChainstate().LoadMempool(args); } +} // namespace node diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index 7c7bf68178..42e46797d2 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -7,11 +7,15 @@ #include <fs.h> #include <protocol.h> // For CMessageHeader::MessageStartChars +#include <sync.h> +#include <txdb.h> #include <atomic> #include <cstdint> #include <vector> +extern RecursiveMutex cs_main; + class ArgsManager; class BlockValidationState; class CBlock; @@ -20,12 +24,15 @@ class CBlockIndex; class CBlockUndo; class CChain; class CChainParams; +class CChainState; class ChainstateManager; +struct CCheckpointData; struct FlatFilePos; namespace Consensus { struct Params; } +namespace node { static constexpr bool DEFAULT_STOPAFTERBLOCKIMPORT{false}; /** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ @@ -45,8 +52,122 @@ extern bool fPruneMode; /** Number of MiB of block files that we're trying to stay below. */ extern uint64_t nPruneTarget; +typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap; + +struct CBlockIndexWorkComparator { + bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const; +}; + +/** + * Maintains a tree of blocks (stored in `m_block_index`) which is consulted + * to determine where the most-work tip is. + * + * This data is used mostly in `CChainState` - information about, e.g., + * candidate tips is not maintained here. + */ +class BlockManager +{ + friend CChainState; + friend ChainstateManager; + +private: + void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false); + void FlushUndoFile(int block_file, bool finalize = false); + bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown); + bool FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize); + + /* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */ + void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height); + + /** + * Prune block and undo files (blk???.dat and rev???.dat) so that the disk space used is less than a user-defined target. + * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new + * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex + * (which in this case means the blockchain must be re-downloaded.) + * + * Pruning functions are called from FlushStateToDisk when the m_check_for_pruning flag has been set. + * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.) + * Pruning cannot take place until the longest chain is at least a certain length (CChainParams::nPruneAfterHeight). + * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip. + * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files. + * A db flag records the fact that at least some block files have been pruned. + * + * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned + */ + void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd); + + RecursiveMutex cs_LastBlockFile; + std::vector<CBlockFileInfo> m_blockfile_info; + int m_last_blockfile = 0; + /** Global flag to indicate we should check to see if there are + * block/undo files that should be deleted. Set on startup + * or if we allocate more file space when we're in prune mode + */ + bool m_check_for_pruning = false; + + /** Dirty block index entries. */ + std::set<CBlockIndex*> m_dirty_blockindex; + + /** Dirty block file entries. */ + std::set<int> m_dirty_fileinfo; + +public: + BlockMap m_block_index GUARDED_BY(cs_main); + + /** + * All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions. + * Pruned nodes may have entries where B is missing data. + */ + std::multimap<CBlockIndex*, CBlockIndex*> m_blocks_unlinked; + + std::unique_ptr<CBlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main); + + bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + bool LoadBlockIndexDB(ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + + /** + * Load the blocktree off disk and into memory. Populate certain metadata + * per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral + * collections like m_dirty_blockindex. + */ + bool LoadBlockIndex( + const Consensus::Params& consensus_params, + ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + /** Clear all data members. */ + void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + /** Create a new block index entry for a given block hash */ + CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + //! Mark one block file as pruned (modify associated database entries) + void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + CBlockIndex* LookupBlockIndex(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + /** Get block file info entry for one block file */ + CBlockFileInfo* GetBlockFileInfo(size_t n); + + bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams) + EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + + FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp); + + /** Calculate the amount of disk space the block & undo files currently use */ + uint64_t CalculateCurrentUsage(); + + //! Returns last CBlockIndex* that is a checkpoint + CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + ~BlockManager() + { + Unload(); + } +}; + //! Check whether the block associated with this index entry is pruned or not. -bool IsBlockPruned(const CBlockIndex* pblockindex); +bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); void CleanupBlockRevFiles(); @@ -55,12 +176,6 @@ FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false); /** Translation to a filesystem path */ fs::path GetBlockPosFilename(const FlatFilePos& pos); -/** Get block file info entry for one block file */ -CBlockFileInfo* GetBlockFileInfo(size_t n); - -/** Calculate the amount of disk space the block & undo files currently use */ -uint64_t CalculateCurrentUsage(); - /** * Actually unlink the specified files */ @@ -70,13 +185,10 @@ void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune); bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams); bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams); bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start); -bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, const CMessageHeader::MessageStartChars& message_start); bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex); -bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams); - -FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp); void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args); +} // namespace node #endif // BITCOIN_NODE_BLOCKSTORAGE_H diff --git a/src/node/caches.cpp b/src/node/caches.cpp index 36254dc714..f168332ee6 100644 --- a/src/node/caches.cpp +++ b/src/node/caches.cpp @@ -8,6 +8,7 @@ #include <util/system.h> #include <validation.h> +namespace node { CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes) { int64_t nTotalCache = (args.GetIntArg("-dbcache", nDefaultDbCache) << 20); @@ -30,3 +31,4 @@ CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes) sizes.coins = nTotalCache; // the rest goes to in-memory cache return sizes; } +} // namespace node diff --git a/src/node/caches.h b/src/node/caches.h index 200f0b85b8..67388b91fd 100644 --- a/src/node/caches.h +++ b/src/node/caches.h @@ -10,6 +10,7 @@ class ArgsManager; +namespace node { struct CacheSizes { int64_t block_tree_db; int64_t coins_db; @@ -18,5 +19,6 @@ struct CacheSizes { int64_t filter_index; }; CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes = 0); +} // namespace node #endif // BITCOIN_NODE_CACHES_H diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index abeebad1a6..e21116dd7e 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -8,6 +8,7 @@ #include <node/blockstorage.h> #include <validation.h> +namespace node { std::optional<ChainstateLoadingError> LoadChainstate(bool fReset, ChainstateManager& chainman, CTxMemPool* mempool, @@ -141,7 +142,7 @@ std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManage for (CChainState* chainstate : chainman.GetAll()) { if (!is_coinsview_empty(chainstate)) { const CBlockIndex* tip = chainstate->m_chain.Tip(); - if (tip && tip->nTime > get_unix_time_seconds() + 2 * 60 * 60) { + if (tip && tip->nTime > get_unix_time_seconds() + MAX_FUTURE_BLOCK_TIME) { return ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE; } @@ -156,3 +157,4 @@ std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManage return std::nullopt; } +} // namespace node diff --git a/src/node/chainstate.h b/src/node/chainstate.h index 11278a0991..279f187642 100644 --- a/src/node/chainstate.h +++ b/src/node/chainstate.h @@ -10,11 +10,12 @@ #include <optional> class ChainstateManager; -namespace Consensus { - struct Params; -} class CTxMemPool; +namespace Consensus { +struct Params; +} // namespace Consensus +namespace node { enum class ChainstateLoadingError { ERROR_LOADING_BLOCK_DB, ERROR_BAD_GENESIS_BLOCK, @@ -50,7 +51,7 @@ enum class ChainstateLoadingError { * 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_requested() hasn't been called indirectly. + * shutdown hasn't been called indirectly. * - else * - Success! */ @@ -81,5 +82,6 @@ std::optional<ChainstateLoadVerifyError> VerifyLoadedChainstate(ChainstateManage unsigned int check_blocks, unsigned int check_level, std::function<int64_t()> get_unix_time_seconds); +} // namespace node #endif // BITCOIN_NODE_CHAINSTATE_H diff --git a/src/node/coin.cpp b/src/node/coin.cpp index 50fddf3ab0..221854c5f6 100644 --- a/src/node/coin.cpp +++ b/src/node/coin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -8,6 +8,7 @@ #include <txmempool.h> #include <validation.h> +namespace node { void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins) { assert(node.mempool); @@ -22,3 +23,4 @@ void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins) } } } +} // namespace node diff --git a/src/node/coin.h b/src/node/coin.h index 908850e2a5..3d534463e8 100644 --- a/src/node/coin.h +++ b/src/node/coin.h @@ -9,6 +9,8 @@ class COutPoint; class Coin; + +namespace node { struct NodeContext; /** @@ -19,6 +21,7 @@ struct NodeContext; * @param[in] node The node context to use for lookup * @param[in,out] coins map to fill */ -void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins); +void FindCoins(const node::NodeContext& node, std::map<COutPoint, Coin>& coins); +} // namespace node #endif // BITCOIN_NODE_COIN_H diff --git a/src/node/coinstats.cpp b/src/node/coinstats.cpp index 67e497c218..eed43a1bc7 100644 --- a/src/node/coinstats.cpp +++ b/src/node/coinstats.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -11,11 +11,13 @@ #include <index/coinstatsindex.h> #include <serialize.h> #include <uint256.h> +#include <util/overflow.h> #include <util/system.h> #include <validation.h> #include <map> +namespace node { // Database-independent metric indicating the UTXO set size uint64_t GetBogoSize(const CScript& script_pub_key) { @@ -82,7 +84,9 @@ static void ApplyStats(CCoinsStats& stats, const uint256& hash, const std::map<u stats.nTransactions++; for (auto it = outputs.begin(); it != outputs.end(); ++it) { stats.nTransactionOutputs++; - stats.nTotalAmount += it->second.out.nValue; + if (stats.total_amount.has_value()) { + stats.total_amount = CheckedAdd(*stats.total_amount, it->second.out.nValue); + } stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey); } } @@ -95,10 +99,8 @@ static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& assert(pcursor); if (!pindex) { - { - LOCK(cs_main); - pindex = blockman.LookupBlockIndex(view->GetBestBlock()); - } + LOCK(cs_main); + pindex = blockman.LookupBlockIndex(view->GetBestBlock()); } stats.nHeight = Assert(pindex)->nHeight; stats.hashBlock = pindex->GetBlockHash(); @@ -180,3 +182,4 @@ static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats) stats.hashSerialized = out; } static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {} +} // namespace node diff --git a/src/node/coinstats.h b/src/node/coinstats.h index 9e9503ff5d..aa771b18b0 100644 --- a/src/node/coinstats.h +++ b/src/node/coinstats.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -15,18 +15,22 @@ #include <cstdint> #include <functional> -class BlockManager; class CCoinsView; +namespace node { +class BlockManager; +} // namespace node +namespace node { enum class CoinStatsHashType { HASH_SERIALIZED, MUHASH, NONE, }; -struct CCoinsStats -{ - CoinStatsHashType m_hash_type; +struct CCoinsStats { + //! Which hash type to use + const CoinStatsHashType m_hash_type; + int nHeight{0}; uint256 hashBlock{}; uint64_t nTransactions{0}; @@ -34,7 +38,8 @@ struct CCoinsStats uint64_t nBogoSize{0}; uint256 hashSerialized{}; uint64_t nDiskSize{0}; - CAmount nTotalAmount{0}; + //! The total amount, or nullopt if an overflow occurred calculating it + std::optional<CAmount> total_amount{0}; //! The number of coins contained. uint64_t coins_count{0}; @@ -69,10 +74,11 @@ struct CCoinsStats }; //! Calculate statistics about the unspent transaction output set -bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, const std::function<void()>& interruption_point = {}, const CBlockIndex* pindex = nullptr); +bool GetUTXOStats(CCoinsView* view, node::BlockManager& blockman, CCoinsStats& stats, const std::function<void()>& interruption_point = {}, const CBlockIndex* pindex = nullptr); uint64_t GetBogoSize(const CScript& script_pub_key); CDataStream TxOutSer(const COutPoint& outpoint, const Coin& coin); +} // namespace node #endif // BITCOIN_NODE_COINSTATS_H diff --git a/src/node/context.cpp b/src/node/context.cpp index 9afadd09a9..893c32f1bc 100644 --- a/src/node/context.cpp +++ b/src/node/context.cpp @@ -14,5 +14,7 @@ #include <txmempool.h> #include <validation.h> +namespace node { NodeContext::NodeContext() {} NodeContext::~NodeContext() {} +} // namespace node diff --git a/src/node/context.h b/src/node/context.h index 26873345b4..644c997531 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -23,9 +23,10 @@ namespace interfaces { class Chain; class ChainClient; class Init; -class WalletClient; +class WalletLoader; } // namespace interfaces +namespace node { //! NodeContext struct containing references to chain state and connection //! state. //! @@ -52,7 +53,7 @@ struct NodeContext { std::vector<std::unique_ptr<interfaces::ChainClient>> chain_clients; //! Reference to chain client that should used to load or create wallets //! opened by the gui. - interfaces::WalletClient* wallet_client{nullptr}; + interfaces::WalletLoader* wallet_loader{nullptr}; std::unique_ptr<CScheduler> scheduler; std::function<void()> rpc_interruption_point = [] {}; @@ -62,5 +63,6 @@ struct NodeContext { NodeContext(); ~NodeContext(); }; +} // namespace node #endif // BITCOIN_NODE_CONTEXT_H diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 8109dce2c0..ffad289fa9 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -63,7 +63,7 @@ using interfaces::FoundBlock; using interfaces::Handler; using interfaces::MakeHandler; using interfaces::Node; -using interfaces::WalletClient; +using interfaces::WalletLoader; namespace node { namespace { @@ -249,8 +249,8 @@ public: bool isInitialBlockDownload() override { return chainman().ActiveChainstate().IsInitialBlockDownload(); } - bool getReindex() override { return ::fReindex; } - bool getImporting() override { return ::fImporting; } + bool getReindex() override { return node::fReindex; } + bool getImporting() override { return node::fImporting; } void setNetworkActive(bool active) override { if (m_context->connman) { @@ -280,9 +280,9 @@ public: { return BroadcastTransaction(*m_context, std::move(tx), err_string, max_tx_fee, /*relay=*/ true, /*wait_callback=*/ false); } - WalletClient& walletClient() override + WalletLoader& walletLoader() override { - return *Assert(m_context->wallet_client); + return *Assert(m_context->wallet_loader); } std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override { @@ -486,11 +486,6 @@ public: const CChain& active = Assert(m_node.chainman)->ActiveChain(); return active.GetLocator(); } - bool checkFinalTx(const CTransaction& tx) override - { - LOCK(cs_main); - return CheckFinalTx(chainman().ActiveChain().Tip(), tx); - } std::optional<int> findLocatorFork(const CBlockLocator& locator) override { LOCK(cs_main); @@ -649,9 +644,9 @@ public: bool havePruned() override { LOCK(cs_main); - return ::fHavePruned; + return node::fHavePruned; } - bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); } + bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); } bool isInitialBlockDownload() override { return chainman().ActiveChainstate().IsInitialBlockDownload(); } @@ -729,6 +724,6 @@ public: } // namespace node namespace interfaces { -std::unique_ptr<Node> MakeNode(NodeContext& context) { return std::make_unique<node::NodeImpl>(context); } -std::unique_ptr<Chain> MakeChain(NodeContext& context) { return std::make_unique<node::ChainImpl>(context); } +std::unique_ptr<Node> MakeNode(node::NodeContext& context) { return std::make_unique<node::NodeImpl>(context); } +std::unique_ptr<Chain> MakeChain(node::NodeContext& context) { return std::make_unique<node::ChainImpl>(context); } } // namespace interfaces diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 6e9bde84d8..7fe10ecabc 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -26,6 +26,7 @@ #include <algorithm> #include <utility> +namespace node { int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { int64_t nOldTime = pblock->nTime; @@ -464,3 +465,4 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase)); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); } +} // namespace node diff --git a/src/node/miner.h b/src/node/miner.h index e50db731b7..c96da874a7 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -23,6 +23,7 @@ class CScript; namespace Consensus { struct Params; }; +namespace node { static const bool DEFAULT_PRINTPRIORITY = false; struct CBlockTemplate @@ -206,5 +207,6 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam /** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman); +} // namespace node #endif // BITCOIN_NODE_MINER_H diff --git a/src/node/minisketchwrapper.cpp b/src/node/minisketchwrapper.cpp index 572df63463..67e823cb68 100644 --- a/src/node/minisketchwrapper.cpp +++ b/src/node/minisketchwrapper.cpp @@ -16,6 +16,7 @@ #include <utility> #include <vector> +namespace node { namespace { static constexpr uint32_t BITS = 32; @@ -75,3 +76,4 @@ Minisketch MakeMinisketch32FP(size_t max_elements, uint32_t fpbits) { return Minisketch::CreateFP(BITS, Minisketch32Implementation(), max_elements, fpbits); } +} // namespace node diff --git a/src/node/minisketchwrapper.h b/src/node/minisketchwrapper.h index a8aef68d01..a92912d9ed 100644 --- a/src/node/minisketchwrapper.h +++ b/src/node/minisketchwrapper.h @@ -10,9 +10,11 @@ #include <cstddef> #include <cstdint> +namespace node { /** Wrapper around Minisketch::Minisketch(32, implementation, capacity). */ Minisketch MakeMinisketch32(size_t capacity); /** Wrapper around Minisketch::CreateFP. */ Minisketch MakeMinisketch32FP(size_t max_elements, uint32_t fpbits); +} // namespace node #endif // BITCOIN_NODE_MINISKETCHWRAPPER_H diff --git a/src/node/psbt.cpp b/src/node/psbt.cpp index 0be2bdb3ef..5a932f435d 100644 --- a/src/node/psbt.cpp +++ b/src/node/psbt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -12,6 +12,7 @@ #include <numeric> +namespace node { PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx) { // Go through each input and build status @@ -147,3 +148,4 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx) return result; } +} // namespace node diff --git a/src/node/psbt.h b/src/node/psbt.h index def4385c09..cbb3bd8201 100644 --- a/src/node/psbt.h +++ b/src/node/psbt.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -9,6 +9,7 @@ #include <optional> +namespace node { /** * Holds an analysis of one input from a PSBT */ @@ -52,5 +53,6 @@ struct PSBTAnalysis { * @return A PSBTAnalysis with information about the provided PSBT. */ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx); +} // namespace node #endif // BITCOIN_NODE_PSBT_H diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index 33b8e9351c..c7c8493f0c 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -16,6 +16,7 @@ #include <future> +namespace node { static TransactionError HandleATMPError(const TxValidationState& state, std::string& err_string_out) { err_string_out = state.ToString(); @@ -153,3 +154,4 @@ CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMe } return nullptr; } +} // namespace node diff --git a/src/node/transaction.h b/src/node/transaction.h index aed519cf7f..b7cf225636 100644 --- a/src/node/transaction.h +++ b/src/node/transaction.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -12,11 +12,13 @@ class CBlockIndex; class CTxMemPool; -struct NodeContext; namespace Consensus { struct Params; } +namespace node { +struct NodeContext; + /** Maximum fee rate for sendrawtransaction and testmempoolaccept RPC calls. * Also used by the GUI when broadcasting a completed PSBT. * By default, a transaction with a fee rate higher than this will be rejected @@ -57,5 +59,6 @@ static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10}; * @returns The tx if found, otherwise nullptr */ CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock); +} // namespace node #endif // BITCOIN_NODE_TRANSACTION_H diff --git a/src/node/ui_interface.cpp b/src/node/ui_interface.cpp index 29fa16d8be..a3a6ede39a 100644 --- a/src/node/ui_interface.cpp +++ b/src/node/ui_interface.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020 The Bitcoin Core developers +// Copyright (c) 2010-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. diff --git a/src/node/ui_interface.h b/src/node/ui_interface.h index f969bcde21..d02238b549 100644 --- a/src/node/ui_interface.h +++ b/src/node/ui_interface.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -25,8 +25,7 @@ class CClientUIInterface { public: /** Flags for CClientUIInterface::ThreadSafeMessageBox */ - enum MessageBoxFlags - { + enum MessageBoxFlags : uint32_t { ICON_INFORMATION = 0, ICON_WARNING = (1U << 0), ICON_ERROR = (1U << 1), @@ -82,7 +81,7 @@ public: /** Progress message during initialization. */ ADD_SIGNALS_DECL_WRAPPER(InitMessage, void, const std::string& message); - /** Wallet client created. */ + /** Wallet loader created. */ ADD_SIGNALS_DECL_WRAPPER(InitWallet, void, ); /** Number of network connections changed. */ diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h index 61292cdcc5..401d4baaeb 100644 --- a/src/node/utxo_snapshot.h +++ b/src/node/utxo_snapshot.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -9,6 +9,7 @@ #include <uint256.h> #include <serialize.h> +namespace node { //! Metadata describing a serialized version of a UTXO set from which an //! assumeutxo CChainState can be constructed. class SnapshotMetadata @@ -32,5 +33,6 @@ public: SERIALIZE_METHODS(SnapshotMetadata, obj) { READWRITE(obj.m_base_blockhash, obj.m_coins_count); } }; +} // namespace node #endif // BITCOIN_NODE_UTXO_SNAPSHOT_H diff --git a/src/outputtype.cpp b/src/outputtype.cpp index b5f1df9792..19366295e6 100644 --- a/src/outputtype.cpp +++ b/src/outputtype.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/outputtype.h b/src/outputtype.h index 0de7689125..66fe489bb0 100644 --- a/src/outputtype.h +++ b/src/outputtype.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp index ce149067b7..0ea56d8db7 100644 --- a/src/policy/feerate.cpp +++ b/src/policy/feerate.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/policy/feerate.h b/src/policy/feerate.h index 13c7ec2002..188a44b73d 100644 --- a/src/policy/feerate.h +++ b/src/policy/feerate.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp index 36cf786bd5..6499dbd97f 100644 --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/policy/fees.h b/src/policy/fees.h index 37a7051045..6e25bb42b8 100644 --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. #ifndef BITCOIN_POLICY_FEES_H diff --git a/src/policy/packages.h b/src/policy/packages.h index d2744f1265..9f274f6b7d 100644 --- a/src/policy/packages.h +++ b/src/policy/packages.h @@ -25,6 +25,7 @@ enum class PackageValidationResult { PCKG_RESULT_UNSET = 0, //!< Initial value. The package has not yet been rejected. PCKG_POLICY, //!< The package itself is invalid (e.g. too many transactions). PCKG_TX, //!< At least one tx is invalid. + PCKG_MEMPOOL_ERROR, //!< Mempool logic error. }; /** A package is an ordered list of transactions. The transactions cannot conflict with (spend the diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 5d0bb68ec6..6aba6a4a5b 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/policy/policy.h b/src/policy/policy.h index f6ac6500f6..89f6e72618 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/policy/rbf.cpp b/src/policy/rbf.cpp index 7e6b0cf245..8fe4dc35b8 100644 --- a/src/policy/rbf.cpp +++ b/src/policy/rbf.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/policy/rbf.h b/src/policy/rbf.h index be8c2e5b8b..fcec7052ed 100644 --- a/src/policy/rbf.h +++ b/src/policy/rbf.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index a871912225..f7f6ae4480 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 947c1c60bb..1fcbc45c72 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -70,25 +70,45 @@ public: uint32_t nSequence; CScriptWitness scriptWitness; //!< Only serialized through CTransaction - /* Setting nSequence to this value for every input in a transaction - * disables nLockTime. */ + /** + * Setting nSequence to this value for every input in a transaction + * disables nLockTime/IsFinalTx(). + * It fails OP_CHECKLOCKTIMEVERIFY/CheckLockTime() for any input that has + * it set (BIP 65). + * It has SEQUENCE_LOCKTIME_DISABLE_FLAG set (BIP 68/112). + */ static const uint32_t SEQUENCE_FINAL = 0xffffffff; + /** + * This is the maximum sequence number that enables both nLockTime and + * OP_CHECKLOCKTIMEVERIFY (BIP 65). + * It has SEQUENCE_LOCKTIME_DISABLE_FLAG set (BIP 68/112). + */ + static const uint32_t MAX_SEQUENCE_NONFINAL{SEQUENCE_FINAL - 1}; - /* Below flags apply in the context of BIP 68*/ - /* If this flag set, CTxIn::nSequence is NOT interpreted as a - * relative lock-time. */ + // Below flags apply in the context of BIP 68. BIP 68 requires the tx + // version to be set to 2, or higher. + /** + * If this flag is set, CTxIn::nSequence is NOT interpreted as a + * relative lock-time. + * It skips SequenceLocks() for any input that has it set (BIP 68). + * It fails OP_CHECKSEQUENCEVERIFY/CheckSequence() for any input that has + * it set (BIP 112). + */ static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1U << 31); - /* If CTxIn::nSequence encodes a relative lock-time and this flag + /** + * If CTxIn::nSequence encodes a relative lock-time and this flag * is set, the relative lock-time has units of 512 seconds, * otherwise it specifies blocks with a granularity of 1. */ static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22); - /* If CTxIn::nSequence encodes a relative lock-time, this mask is + /** + * If CTxIn::nSequence encodes a relative lock-time, this mask is * applied to extract that lock-time from the sequence field. */ static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff; - /* In order to use the same number of bits to encode roughly the + /** + * In order to use the same number of bits to encode roughly the * same wall-clock duration, and because blocks are naturally * limited to occur every 600s on average, the minimum granularity * for time-based relative lock-time is fixed at 512 seconds. diff --git a/src/protocol.cpp b/src/protocol.cpp index 7506c81815..139405170b 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/protocol.h b/src/protocol.h index 2149e45993..fdeaa9a9c5 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/psbt.cpp b/src/psbt.cpp index 203e0a0bd3..c8c73e130b 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -399,7 +399,7 @@ bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base6 bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data, std::string& error) { - CDataStream ss_data(MakeUCharSpan(tx_data), SER_NETWORK, PROTOCOL_VERSION); + CDataStream ss_data(MakeByteSpan(tx_data), SER_NETWORK, PROTOCOL_VERSION); try { ss_data >> psbt; if (!ss_data.empty()) { diff --git a/src/psbt.h b/src/psbt.h index 43b1b249c5..f0ceb02481 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/pubkey.cpp b/src/pubkey.cpp index b7dfb6d83f..324f681a0a 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2021 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/pubkey.h b/src/pubkey.h index 204e96f49e..dfe06f834c 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-2021 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -142,14 +142,14 @@ public: { unsigned int len = size(); ::WriteCompactSize(s, len); - s.write((char*)vch, len); + s.write(AsBytes(Span{vch, len})); } template <typename Stream> void Unserialize(Stream& s) { const unsigned int len(::ReadCompactSize(s)); if (len <= SIZE) { - s.read((char*)vch, len); + s.read(AsWritableBytes(Span{vch, len})); if (len != size()) { Invalidate(); } diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index a617bb4451..d59a4345f3 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -189,7 +189,7 @@ void AddressBookPage::onEditAction() dlg->setModel(model); QModelIndex origIndex = proxyModel->mapToSource(indexes.at(0)); dlg->loadRow(origIndex.row()); - GUIUtil::ShowModalDialogAndDeleteOnClose(dlg); + GUIUtil::ShowModalDialogAsynchronously(dlg); } void AddressBookPage::on_newAddress_clicked() diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 93feac9e23..144990f419 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index ee2462ed74..dcab631d98 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java b/src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java index cf3b4f6668..2cba489242 100644 --- a/src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java +++ b/src/qt/android/src/org/bitcoincore/qt/BitcoinQtActivity.java @@ -18,12 +18,6 @@ public class BitcoinQtActivity extends QtActivity bitcoinDir.mkdir(); } - try { - Os.setenv("QT_QPA_PLATFORM", "android", true); - } catch (ErrnoException e) { - e.printStackTrace(); - } - super.onCreate(savedInstanceState); } } diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 5b1330b81b..f16700bfd9 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp index 6cb4a4c546..e004fba308 100644 --- a/src/qt/bantablemodel.cpp +++ b/src/qt/bantablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h index 4b5b38e43f..0a30905172 100644 --- a/src/qt/bantablemodel.h +++ b/src/qt/bantablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index d22111ce44..eb31287c56 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -41,6 +41,7 @@ #endif // ENABLE_WALLET #include <boost/signals2/connection.hpp> +#include <chrono> #include <memory> #include <QApplication> @@ -76,6 +77,8 @@ 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 @@ -265,7 +268,11 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) connect(window, &BitcoinGUI::quitRequested, this, &BitcoinApplication::requestShutdown); pollShutdownTimer = new QTimer(window); - connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown); + connect(pollShutdownTimer, &QTimer::timeout, [this]{ + if (!QApplication::activeModalWidget()) { + window->detectShutdown(); + } + }); } void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) @@ -410,10 +417,10 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) { window->message(title, message, style); }); - QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady); + QTimer::singleShot(100ms, paymentServer, &PaymentServer::uiReady); } #endif - pollShutdownTimer->start(200); + pollShutdownTimer->start(SHUTDOWN_POLLING_DELAY); } else { Q_EMIT splashFinished(); // Make sure splash screen doesn't stick around during shutdown requestShutdown(); diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h index 5678ca90d2..0703c6dcb9 100644 --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index ba59bcc660..a257e250e0 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index 4855ada513..366a6fc4b5 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 81a1d88d20..7c22880dd1 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -261,10 +261,6 @@ void BitcoinGUI::createActions() sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2)); tabGroup->addAction(sendCoinsAction); - sendCoinsMenuAction = new QAction(sendCoinsAction->text(), this); - sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip()); - sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip()); - receiveCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this); receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)")); receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip()); @@ -272,10 +268,6 @@ void BitcoinGUI::createActions() receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3)); tabGroup->addAction(receiveCoinsAction); - receiveCoinsMenuAction = new QAction(receiveCoinsAction->text(), this); - receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip()); - receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip()); - historyAction = new QAction(platformStyle->SingleColorIcon(":/icons/history"), tr("&Transactions"), this); historyAction->setStatusTip(tr("Browse transaction history")); historyAction->setToolTip(historyAction->statusTip()); @@ -290,12 +282,8 @@ void BitcoinGUI::createActions() connect(overviewAction, &QAction::triggered, this, &BitcoinGUI::gotoOverviewPage); connect(sendCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); connect(sendCoinsAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); }); - connect(sendCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); - connect(sendCoinsMenuAction, &QAction::triggered, [this]{ gotoSendCoinsPage(); }); connect(receiveCoinsAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage); - connect(receiveCoinsMenuAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); - connect(receiveCoinsMenuAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage); connect(historyAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage); #endif // ENABLE_WALLET @@ -315,8 +303,6 @@ void BitcoinGUI::createActions() optionsAction->setStatusTip(tr("Modify configuration options for %1").arg(PACKAGE_NAME)); optionsAction->setMenuRole(QAction::PreferencesRole); optionsAction->setEnabled(false); - toggleHideAction = new QAction(tr("&Show / Hide"), this); - toggleHideAction->setStatusTip(tr("Show or hide the main Window")); encryptWalletAction = new QAction(tr("&Encrypt Wallet…"), this); encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet")); @@ -376,7 +362,6 @@ void BitcoinGUI::createActions() connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked); connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt); connect(optionsAction, &QAction::triggered, this, &BitcoinGUI::optionsClicked); - connect(toggleHideAction, &QAction::triggered, this, &BitcoinGUI::toggleHidden); connect(showHelpMessageAction, &QAction::triggered, this, &BitcoinGUI::showHelpMessageClicked); connect(openRPCConsoleAction, &QAction::triggered, this, &BitcoinGUI::showDebugWindow); // prevents an open debug window from becoming stuck/unusable on client shutdown @@ -627,8 +612,6 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH trayIcon->setVisible(optionsModel->getShowTrayIcon()); } } else { - // Disable possibility to show main window via action - toggleHideAction->setEnabled(false); if(trayIconMenu) { // Disable context menu on tray icon @@ -752,9 +735,7 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) { overviewAction->setEnabled(enabled); sendCoinsAction->setEnabled(enabled); - sendCoinsMenuAction->setEnabled(enabled); receiveCoinsAction->setEnabled(enabled); - receiveCoinsMenuAction->setEnabled(enabled); historyAction->setEnabled(enabled); encryptWalletAction->setEnabled(enabled); backupWalletAction->setEnabled(enabled); @@ -784,57 +765,82 @@ void BitcoinGUI::createTrayIcon() void BitcoinGUI::createTrayIconMenu() { #ifndef Q_OS_MAC - // return if trayIcon is unset (only on non-macOSes) - if (!trayIcon) - return; - - trayIcon->setContextMenu(trayIconMenu.get()); - connect(trayIcon, &QSystemTrayIcon::activated, this, &BitcoinGUI::trayIconActivated); -#else - // Note: On macOS, the Dock icon is used to provide the tray's functionality. - MacDockIconHandler *dockIconHandler = MacDockIconHandler::instance(); - connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, this, &BitcoinGUI::macosDockIconActivated); - trayIconMenu->setAsDockMenu(); -#endif + if (!trayIcon) return; +#endif // Q_OS_MAC - // Configuration of the tray icon (or Dock icon) menu + // Configuration of the tray icon (or Dock icon) menu. + QAction* show_hide_action{nullptr}; #ifndef Q_OS_MAC // Note: On macOS, the Dock icon's menu already has Show / Hide action. - trayIconMenu->addAction(toggleHideAction); + show_hide_action = trayIconMenu->addAction(QString(), this, &BitcoinGUI::toggleHidden); trayIconMenu->addSeparator(); -#endif +#endif // Q_OS_MAC + + QAction* send_action{nullptr}; + QAction* receive_action{nullptr}; + QAction* sign_action{nullptr}; + QAction* verify_action{nullptr}; if (enableWallet) { - trayIconMenu->addAction(sendCoinsMenuAction); - trayIconMenu->addAction(receiveCoinsMenuAction); + send_action = trayIconMenu->addAction(sendCoinsAction->text(), sendCoinsAction, &QAction::trigger); + receive_action = trayIconMenu->addAction(receiveCoinsAction->text(), receiveCoinsAction, &QAction::trigger); trayIconMenu->addSeparator(); - trayIconMenu->addAction(signMessageAction); - trayIconMenu->addAction(verifyMessageAction); + sign_action = trayIconMenu->addAction(signMessageAction->text(), signMessageAction, &QAction::trigger); + verify_action = trayIconMenu->addAction(verifyMessageAction->text(), verifyMessageAction, &QAction::trigger); trayIconMenu->addSeparator(); } - trayIconMenu->addAction(optionsAction); - trayIconMenu->addAction(openRPCConsoleAction); -#ifndef Q_OS_MAC // This is built-in on macOS + QAction* options_action = trayIconMenu->addAction(optionsAction->text(), optionsAction, &QAction::trigger); + options_action->setMenuRole(QAction::PreferencesRole); + QAction* node_window_action = trayIconMenu->addAction(openRPCConsoleAction->text(), openRPCConsoleAction, &QAction::trigger); + QAction* quit_action{nullptr}; +#ifndef Q_OS_MAC + // Note: On macOS, the Dock icon's menu already has Quit action. trayIconMenu->addSeparator(); - trayIconMenu->addAction(quitAction); -#endif -} + quit_action = trayIconMenu->addAction(quitAction->text(), quitAction, &QAction::trigger); -#ifndef Q_OS_MAC -void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) -{ - if(reason == QSystemTrayIcon::Trigger) - { - // Click on system tray icon triggers show/hide of the main window - toggleHidden(); - } -} + trayIcon->setContextMenu(trayIconMenu.get()); + connect(trayIcon, &QSystemTrayIcon::activated, [this](QSystemTrayIcon::ActivationReason reason) { + if (reason == QSystemTrayIcon::Trigger) { + // Click on system tray icon triggers show/hide of the main window + toggleHidden(); + } + }); #else -void BitcoinGUI::macosDockIconActivated() -{ - show(); - activateWindow(); + // Note: On macOS, the Dock icon is used to provide the tray's functionality. + MacDockIconHandler* dockIconHandler = MacDockIconHandler::instance(); + connect(dockIconHandler, &MacDockIconHandler::dockIconClicked, [this] { + show(); + activateWindow(); + }); + trayIconMenu->setAsDockMenu(); +#endif // Q_OS_MAC + + connect( + // Using QSystemTrayIcon::Context is not reliable. + // See https://bugreports.qt.io/browse/QTBUG-91697 + trayIconMenu.get(), &QMenu::aboutToShow, + [this, show_hide_action, send_action, receive_action, sign_action, verify_action, options_action, node_window_action, quit_action] { + if (show_hide_action) show_hide_action->setText( + (!isHidden() && !isMinimized() && !GUIUtil::isObscured(this)) ? + tr("&Hide") : + tr("S&how")); + if (QApplication::activeModalWidget()) { + for (QAction* a : trayIconMenu.get()->actions()) { + a->setEnabled(false); + } + } else { + if (show_hide_action) show_hide_action->setEnabled(true); + if (enableWallet) { + send_action->setEnabled(sendCoinsAction->isEnabled()); + receive_action->setEnabled(receiveCoinsAction->isEnabled()); + sign_action->setEnabled(signMessageAction->isEnabled()); + verify_action->setEnabled(verifyMessageAction->isEnabled()); + } + options_action->setEnabled(optionsAction->isEnabled()); + node_window_action->setEnabled(openRPCConsoleAction->isEnabled()); + if (quit_action) quit_action->setEnabled(true); + } + }); } -#endif void BitcoinGUI::optionsClicked() { @@ -847,7 +853,7 @@ void BitcoinGUI::aboutClicked() return; auto dlg = new HelpMessageDialog(this, /* about */ true); - GUIUtil::ShowModalDialogAndDeleteOnClose(dlg); + GUIUtil::ShowModalDialogAsynchronously(dlg); } void BitcoinGUI::showDebugWindow() @@ -992,7 +998,7 @@ void BitcoinGUI::openOptionsDialogWithTab(OptionsDialog::Tab tab) connect(dlg, &OptionsDialog::quitOnReset, this, &BitcoinGUI::quitRequested); dlg->setCurrentTab(tab); dlg->setModel(clientModel->getOptionsModel()); - GUIUtil::ShowModalDialogAndDeleteOnClose(dlg); + GUIUtil::ShowModalDialogAsynchronously(dlg); } void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress, bool header, SynchronizationState sync_state) @@ -1242,7 +1248,7 @@ void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmoun // On new transaction, make an info balloon QString msg = tr("Date: %1\n").arg(date) + tr("Amount: %1\n").arg(BitcoinUnits::formatWithUnit(unit, amount, true)); - if (m_node.walletClient().getWallets().size() > 1 && !walletName.isEmpty()) { + if (m_node.walletLoader().getWallets().size() > 1 && !walletName.isEmpty()) { msg += tr("Wallet: %1\n").arg(walletName); } msg += tr("Type: %1\n").arg(type); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index fa7ae4b87d..0ae5f7331e 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -137,7 +137,6 @@ private: QAction* historyAction = nullptr; QAction* quitAction = nullptr; QAction* sendCoinsAction = nullptr; - QAction* sendCoinsMenuAction = nullptr; QAction* usedSendingAddressesAction = nullptr; QAction* usedReceivingAddressesAction = nullptr; QAction* signMessageAction = nullptr; @@ -146,9 +145,7 @@ private: QAction* m_load_psbt_clipboard_action = nullptr; QAction* aboutAction = nullptr; QAction* receiveCoinsAction = nullptr; - QAction* receiveCoinsMenuAction = nullptr; QAction* optionsAction = nullptr; - QAction* toggleHideAction = nullptr; QAction* encryptWalletAction = nullptr; QAction* backupWalletAction = nullptr; QAction* changePassphraseAction = nullptr; @@ -302,13 +299,6 @@ public Q_SLOTS: void showDebugWindowActivateConsole(); /** Show help message dialog */ void showHelpMessageClicked(); -#ifndef Q_OS_MAC - /** Handle tray icon clicked */ - void trayIconActivated(QSystemTrayIcon::ActivationReason reason); -#else - /** Handle macOS Dock icon clicked */ - void macosDockIconActivated(); -#endif /** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */ void showNormalIfMinimized() { showNormalIfMinimized(false); } diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index d2d4079ea9..90b15f3898 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -35,6 +35,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Error reading %s! All keys read correctly, but transaction data or address " "book entries might be missing or incorrect."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error reading %s! Transaction data may be missing or incorrect. Rescanning " +"wallet."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: Dumpfile format record is incorrect. Got \"%s\", expected \"format\"."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: Dumpfile identifier record is incorrect. Got \"%s\", expected \"%s\"."), @@ -56,6 +59,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay " "fee of %s to prevent stuck transactions)"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"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."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "More than one onion bind address is provided. Using %s for the automatically " "created Tor onion service."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -81,11 +88,18 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is " "supported"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"The -txindex upgrade started by a previous version can not be completed. " +"Restart with the previous version or run a full -reindex."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "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"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"The block index db contains a legacy 'txindex'. To clear the occupied disk " +"space, run a full -reindex, otherwise ignore this error. This error message " +"will not be displayed again."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "The transaction amount is too small to send after the fee has been deducted"), QT_TRANSLATE_NOOP("bitcoin-core", "" "This error could occur if this wallet was not shutdown cleanly and was last " @@ -129,6 +143,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "%s is set very high!"), QT_TRANSLATE_NOOP("bitcoin-core", "-maxmempool must be at least %d MB"), QT_TRANSLATE_NOOP("bitcoin-core", "A fatal internal error occurred, see debug.log for details"), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot resolve -%s address: '%s'"), +QT_TRANSLATE_NOOP("bitcoin-core", "Cannot set -forcednsseed to true when setting -dnsseed to false."), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot set -peerblockfilters without -blockfilterindex."), QT_TRANSLATE_NOOP("bitcoin-core", "Cannot write to data directory '%s'; check permissions."), QT_TRANSLATE_NOOP("bitcoin-core", "Change index out of range"), @@ -171,6 +186,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Ignoring duplicate -wallet %s."), QT_TRANSLATE_NOOP("bitcoin-core", "Importing…"), QT_TRANSLATE_NOOP("bitcoin-core", "Incorrect or no genesis block found. Wrong datadir for network?"), QT_TRANSLATE_NOOP("bitcoin-core", "Initialization sanity check failed. %s is shutting down."), +QT_TRANSLATE_NOOP("bitcoin-core", "Input not found or already spent"), QT_TRANSLATE_NOOP("bitcoin-core", "Insufficient funds"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -i2psam address or hostname: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid -onion address or hostname: '%s'"), @@ -185,7 +201,10 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Loading P2P addresses…"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading banlist…"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading block index…"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading wallet…"), +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."), @@ -217,7 +236,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amount too small"), QT_TRANSLATE_NOOP("bitcoin-core", "Transaction amounts must not be negative"), 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. %s"), +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 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."), @@ -225,6 +244,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Unable to create the PID file '%s': %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate initial keys"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to generate keys"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to open %s for writing"), +QT_TRANSLATE_NOOP("bitcoin-core", "Unable to parse -maxuploadtarget: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Unable to start HTTP server. See debug log for details."), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -blockfilterindex value %s."), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown address type '%s'"), @@ -233,7 +253,6 @@ 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", "Upgrading txindex 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/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 66d5eea7ac..69caf64d5c 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h index e78a347bb1..9fedec0d4f 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index c86cb16af6..a28329082a 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -17,6 +17,7 @@ #include <netbase.h> #include <util/system.h> #include <util/threadnames.h> +#include <util/time.h> #include <validation.h> #include <stdint.h> @@ -221,12 +222,12 @@ QString ClientModel::formatClientStartupTime() const QString ClientModel::dataDir() const { - return GUIUtil::boostPathToQString(gArgs.GetDataDirNet()); + return GUIUtil::PathToQString(gArgs.GetDataDirNet()); } QString ClientModel::blocksDir() const { - return GUIUtil::boostPathToQString(gArgs.GetBlocksDirPath()); + return GUIUtil::PathToQString(gArgs.GetBlocksDirPath()); } void ClientModel::updateBanlist() @@ -288,7 +289,7 @@ static void BlockTipChanged(ClientModel* clientmodel, SynchronizationState sync_ const bool throttle = (sync_state != SynchronizationState::POST_INIT && !fHeader) || sync_state == SynchronizationState::INIT_REINDEX; const int64_t now = throttle ? GetTimeMillis() : 0; int64_t& nLastUpdateNotification = fHeader ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification; - if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) { + if (throttle && now < nLastUpdateNotification + count_milliseconds(MODEL_UPDATE_DELAY)) { return; } diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 7a199ef19c..846691c0c0 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index e93fedad28..d7a2aaaf19 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -31,6 +31,9 @@ #include <QSettings> #include <QTreeWidget> +using wallet::CCoinControl; +using wallet::MIN_CHANGE; + QList<CAmount> CoinControlDialog::payAmounts; bool CoinControlDialog::fSubtractFeeFromAmount = false; diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index ec2619d115..ccceff10e8 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -19,7 +19,9 @@ class PlatformStyle; class WalletModel; +namespace wallet { class CCoinControl; +} // namespace wallet namespace Ui { class CoinControlDialog; @@ -42,11 +44,11 @@ class CoinControlDialog : public QDialog Q_OBJECT public: - explicit CoinControlDialog(CCoinControl& coin_control, WalletModel* model, const PlatformStyle *platformStyle, QWidget *parent = nullptr); + explicit CoinControlDialog(wallet::CCoinControl& coin_control, WalletModel* model, const PlatformStyle *platformStyle, QWidget *parent = nullptr); ~CoinControlDialog(); // static because also called from sendcoinsdialog - static void updateLabels(CCoinControl& m_coin_control, WalletModel*, QDialog*); + static void updateLabels(wallet::CCoinControl& m_coin_control, WalletModel*, QDialog*); static QList<CAmount> payAmounts; static bool fSubtractFeeFromAmount; @@ -56,7 +58,7 @@ protected: private: Ui::CoinControlDialog *ui; - CCoinControl& m_coin_control; + wallet::CCoinControl& m_coin_control; WalletModel *model; int sortColumn; Qt::SortOrder sortOrder; diff --git a/src/qt/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp index eba70331f8..5b3c8bcf48 100644 --- a/src/qt/createwalletdialog.cpp +++ b/src/qt/createwalletdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/qt/createwalletdialog.h b/src/qt/createwalletdialog.h index 63a5e012d8..939b82ff78 100644 --- a/src/qt/createwalletdialog.h +++ b/src/qt/createwalletdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index e51ed9e656..fa27635981 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 15e0d3fad9..2196801023 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -1355,10 +1355,10 @@ <item row="13" column="0"> <widget class="QLabel" name="peerLastTxLabel"> <property name="toolTip"> - <string>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</string> + <string extracomment="Tooltip text for the Last Transaction field in the peer details area.">Elapsed time since a novel transaction accepted into our mempool was received from this peer.</string> </property> <property name="text"> - <string>Last Tx</string> + <string>Last Transaction</string> </property> </widget> </item> @@ -1592,6 +1592,84 @@ </widget> </item> <item row="23" column="0"> + <widget class="QLabel" name="peerAddrRelayEnabledLabel"> + <property name="toolTip"> + <string extracomment="Tooltip text for the Address Relay field in the peer details area.">Whether we relay addresses to this peer.</string> + </property> + <property name="text"> + <string>Address Relay</string> + </property> + </widget> + </item> + <item row="23" column="1"> + <widget class="QLabel" name="peerAddrRelayEnabled"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="24" column="0"> + <widget class="QLabel" name="peerAddrProcessedLabel"> + <property name="toolTip"> + <string extracomment="Tooltip text for the Addresses Processed field in the peer details area.">Total number of addresses processed, excluding those dropped due to rate-limiting.</string> + </property> + <property name="text"> + <string>Addresses Processed</string> + </property> + </widget> + </item> + <item row="24" column="1"> + <widget class="QLabel" name="peerAddrProcessed"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="25" column="0"> + <widget class="QLabel" name="peerAddrRateLimitedLabel"> + <property name="toolTip"> + <string extracomment="Tooltip text for the Addresses Rate-Limited field in the peer details area.">Total number of addresses dropped due to rate-limiting.</string> + </property> + <property name="text"> + <string>Addresses Rate-Limited</string> + </property> + </widget> + </item> + <item row="25" column="1"> + <widget class="QLabel" name="peerAddrRateLimited"> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>N/A</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item row="26" column="0"> <spacer name="verticalSpacer_3"> <property name="orientation"> <enum>Qt::Vertical</enum> diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 6b3a4630a3..5438811aff 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -252,6 +252,16 @@ </property> </widget> </item> + <item> + <widget class="QCheckBox" name="m_enable_psbt_controls"> + <property name="text"> + <string extracomment="An options window setting to enable PSBT controls.">Enable &PSBT controls</string> + </property> + <property name="toolTip"> + <string extracomment="Tooltip text for options window setting that enables PSBT controls.">Whether to show PSBT controls.</string> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index 06d39426c9..7590dd524d 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -195,7 +195,7 @@ </widget> </item> <item> - <widget class="QCheckBox" name="useBech32"> + <widget class="QComboBox" name="addressType"> <property name="sizePolicy"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -211,12 +211,6 @@ <property name="focusPolicy"> <enum>Qt::StrongFocus</enum> </property> - <property name="toolTip"> - <string>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</string> - </property> - <property name="text"> - <string>Generate native segwit (Bech32) address</string> - </property> </widget> </item> <item> @@ -308,7 +302,7 @@ </property> <property name="icon"> <iconset resource="../bitcoin.qrc"> - <normaloff>:/icons/edit</normaloff>:/icons/edit</iconset> + <normaloff>:/icons/eye</normaloff>:/icons/eye</iconset> </property> <property name="autoDefault"> <bool>false</bool> @@ -366,7 +360,7 @@ <tabstops> <tabstop>reqLabel</tabstop> <tabstop>reqAmount</tabstop> - <tabstop>useBech32</tabstop> + <tabstop>addressType</tabstop> <tabstop>reqMessage</tabstop> <tabstop>receiveButton</tabstop> <tabstop>clearButton</tabstop> diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 882d2c8f52..fcdf6056c9 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -5,10 +5,16 @@ #ifndef BITCOIN_QT_GUICONSTANTS_H #define BITCOIN_QT_GUICONSTANTS_H +#include <chrono> #include <cstdint> -/* Milliseconds between model updates */ -static const int MODEL_UPDATE_DELAY = 250; +using namespace std::chrono_literals; + +/* A delay between model updates */ +static constexpr auto MODEL_UPDATE_DELAY{250ms}; + +/* A delay between shutdown pollings */ +static constexpr auto SHUTDOWN_POLLING_DELAY{200ms}; /* AskPassphraseDialog -- Maximum passphrase length */ static const int MAX_PASSPHRASE_SIZE = 1024; @@ -27,8 +33,6 @@ static const bool DEFAULT_SPLASHSCREEN = true; #define COLOR_NEGATIVE QColor(255, 0, 0) /* Transaction list -- bare address (without label) */ #define COLOR_BAREADDRESS QColor(140, 140, 140) -/* Transaction list -- TX status decoration - open until date */ -#define COLOR_TX_STATUS_OPENUNTILDATE QColor(64, 64, 255) /* Transaction list -- TX status decoration - danger, tx needs attention */ #define COLOR_TX_STATUS_DANGER QColor(200, 100, 100) /* Transaction list -- TX status decoration - default color */ diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 35e4ab4ecd..9565fa508f 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -12,6 +12,7 @@ #include <base58.h> #include <chainparams.h> +#include <fs.h> #include <interfaces/node.h> #include <key_io.h> #include <policy/policy.h> @@ -66,6 +67,10 @@ #include <cassert> #include <chrono> +#include <exception> +#include <fstream> +#include <string> +#include <vector> #if defined(Q_OS_MAC) @@ -281,7 +286,7 @@ void LoadFont(const QString& file_name) QString getDefaultDataDirectory() { - return boostPathToQString(GetDefaultDataDir()); + return PathToQString(GetDefaultDataDir()); } QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, @@ -418,7 +423,7 @@ void openDebugLogfile() /* Open debug.log with the associated application */ if (fs::exists(pathDebug)) - QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug))); + QDesktopServices::openUrl(QUrl::fromLocalFile(PathToQString(pathDebug))); } bool openBitcoinConf() @@ -426,7 +431,7 @@ bool openBitcoinConf() fs::path pathConfig = GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)); /* Create the file */ - fsbridge::ofstream configFile(pathConfig, std::ios_base::app); + std::ofstream configFile{pathConfig, std::ios_base::app}; if (!configFile.good()) return false; @@ -434,11 +439,11 @@ bool openBitcoinConf() configFile.close(); /* Open bitcoin.conf with the associated application */ - bool res = QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); + bool res = QDesktopServices::openUrl(QUrl::fromLocalFile(PathToQString(pathConfig))); #ifdef Q_OS_MAC // Workaround for macOS-specific behavior; see #15409. if (!res) { - res = QProcess::startDetached("/usr/bin/open", QStringList{"-t", boostPathToQString(pathConfig)}); + res = QProcess::startDetached("/usr/bin/open", QStringList{"-t", PathToQString(pathConfig)}); } #endif @@ -586,7 +591,7 @@ fs::path static GetAutostartFilePath() bool GetStartOnSystemStartup() { - fsbridge::ifstream optionFile(GetAutostartFilePath()); + std::ifstream optionFile{GetAutostartFilePath()}; if (!optionFile.good()) return false; // Scan through file for "Hidden=true": @@ -617,7 +622,7 @@ bool SetStartOnSystemStartup(bool fAutoStart) fs::create_directories(GetAutostartDir()); - fsbridge::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc); + std::ofstream optionFile{GetAutostartFilePath(), std::ios_base::out | std::ios_base::trunc}; if (!optionFile.good()) return false; std::string chain = gArgs.GetChainName(); @@ -652,12 +657,12 @@ void setClipboard(const QString& str) } } -fs::path qstringToBoostPath(const QString &path) +fs::path QStringToPath(const QString &path) { return fs::u8path(path.toStdString()); } -QString boostPathToQString(const fs::path &path) +QString PathToQString(const fs::path &path) { return QString::fromStdString(path.u8string()); } @@ -979,7 +984,7 @@ void PrintSlotException( PrintExceptionContinue(exception, description.c_str()); } -void ShowModalDialogAndDeleteOnClose(QDialog* dialog) +void ShowModalDialogAsynchronously(QDialog* dialog) { dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setWindowModality(Qt::ApplicationModal); diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index fb0dbba88b..0224b18b4e 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -209,10 +209,10 @@ namespace GUIUtil bool SetStartOnSystemStartup(bool fAutoStart); /** Convert QString to OS specific boost path through UTF-8 */ - fs::path qstringToBoostPath(const QString &path); + fs::path QStringToPath(const QString &path); /** Convert OS specific boost path to QString through UTF-8 */ - QString boostPathToQString(const fs::path &path); + QString PathToQString(const fs::path &path); /** Convert enum Network to QString */ QString NetworkToQString(Network net); @@ -426,7 +426,7 @@ namespace GUIUtil /** * Shows a QDialog instance asynchronously, and deletes it on close. */ - void ShowModalDialogAndDeleteOnClose(QDialog* dialog); + void ShowModalDialogAsynchronously(QDialog* dialog); inline bool IsEscapeOrBack(int key) { diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index 2ca4b6a21e..e9a4034e62 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -67,7 +67,7 @@ FreespaceChecker::FreespaceChecker(Intro *_intro) void FreespaceChecker::check() { QString dataDirStr = intro->getPathToCheck(); - fs::path dataDir = GUIUtil::qstringToBoostPath(dataDirStr); + fs::path dataDir = GUIUtil::QStringToPath(dataDirStr); uint64_t freeBytesAvailable = 0; int replyStatus = ST_OK; QString replyMessage = tr("A new data directory will be created."); @@ -216,7 +216,7 @@ bool Intro::showIfNeeded(bool& did_show_intro, int64_t& prune_MiB) /* 2) Allow QSettings to override default dir */ dataDir = settings.value("strDataDir", dataDir).toString(); - if(!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false)) + if(!fs::exists(GUIUtil::QStringToPath(dataDir)) || gArgs.GetBoolArg("-choosedatadir", DEFAULT_CHOOSE_DATADIR) || settings.value("fReset", false).toBool() || gArgs.GetBoolArg("-resetguisettings", false)) { /* Use selectParams here to guarantee Params() can be used by node interface */ try { @@ -240,9 +240,9 @@ bool Intro::showIfNeeded(bool& did_show_intro, int64_t& prune_MiB) } dataDir = intro.getDataDirectory(); try { - if (TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir))) { + if (TryCreateDirectories(GUIUtil::QStringToPath(dataDir))) { // If a new data directory has been created, make wallets subdirectory too - TryCreateDirectories(GUIUtil::qstringToBoostPath(dataDir) / "wallets"); + TryCreateDirectories(GUIUtil::QStringToPath(dataDir) / "wallets"); } break; } catch (const fs::filesystem_error&) { @@ -263,7 +263,7 @@ bool Intro::showIfNeeded(bool& did_show_intro, int64_t& prune_MiB) * (to be consistent with bitcoind behavior) */ if(dataDir != GUIUtil::getDefaultDataDirectory()) { - gArgs.SoftSetArg("-datadir", fs::PathToString(GUIUtil::qstringToBoostPath(dataDir))); // use OS locale for path setting + gArgs.SoftSetArg("-datadir", fs::PathToString(GUIUtil::QStringToPath(dataDir))); // use OS locale for path setting } return true; } diff --git a/src/qt/intro.h b/src/qt/intro.h index 91d57690b7..d9c45007e1 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 47c002498a..93f0aee66c 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -118,7 +118,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message> <location line="+3"/> <source>Comma separated file</source> - <extracomment>Expanded name of the CSV file format. See https://en.wikipedia.org/wiki/Comma-separated_values</extracomment> + <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment> <translation type="unfinished"></translation> </message> <message> @@ -313,7 +313,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>BitcoinApplication</name> <message> - <location filename="../bitcoin.cpp" line="+421"/> + <location filename="../bitcoin.cpp" line="+429"/> <source>Runaway exception</source> <translation type="unfinished"></translation> </message> @@ -336,7 +336,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+245"/> + <location filename="../bitcoingui.cpp" line="+250"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -396,23 +396,28 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+209"/> + <location line="+128"/> + <source>&Minimize</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+79"/> <source>Wallet:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+373"/> + <location line="+371"/> <source>Network activity disabled.</source> <extracomment>A substring of the tooltip.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+424"/> + <location line="+422"/> <source>Proxy is <b>enabled</b>: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="-1109"/> + <location line="-1103"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> @@ -497,12 +502,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> - <source>Load PSBT from clipboard…</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+14"/> + <location line="+16"/> <source>Open &URI…</source> <translation type="unfinished"></translation> </message> @@ -522,7 +522,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+97"/> + <location line="+95"/> <source>&File</source> <translation>&File</translation> </message> @@ -542,12 +542,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Tabs toolbar</translation> </message> <message> - <location line="+437"/> + <location line="+435"/> <source>Syncing Headers (%1%)…</source> <translation type="unfinished"></translation> </message> <message> - <location line="+46"/> + <location line="+47"/> <source>Synchronizing with network…</source> <translation type="unfinished"></translation> </message> @@ -572,7 +572,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-781"/> + <location line="-778"/> <source>Request payments (generates QR codes and bitcoin: URIs)</source> <translation type="unfinished"></translation> </message> @@ -592,7 +592,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+693"/> + <location line="+690"/> <source>Processed %n block(s) of transaction history.</source> <translation> <numerusform>Processed %n block of transaction history.</numerusform> @@ -640,12 +640,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Up to date</translation> </message> <message> - <location line="-730"/> + <location line="-727"/> <source>Load Partially Signed Bitcoin Transaction</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> + <location line="+1"/> + <source>Load PSBT from &clipboard…</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Load Partially Signed Bitcoin Transaction from clipboard</source> <translation type="unfinished"></translation> </message> @@ -715,22 +720,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+21"/> + <location line="+20"/> <source>No wallets available</source> <translation type="unfinished"></translation> </message> <message> - <location line="+64"/> + <location line="+63"/> <source>&Window</source> <translation type="unfinished">&Window</translation> </message> <message> - <location line="+2"/> - <source>Minimize</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+10"/> + <location line="+12"/> <source>Zoom</source> <translation type="unfinished"></translation> </message> @@ -740,7 +740,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+263"/> + <location line="+261"/> <source>%1 client</source> <translation type="unfinished"></translation> </message> @@ -778,7 +778,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+157"/> + <location line="+158"/> <source>Error: %1</source> <translation type="unfinished"></translation> </message> @@ -849,7 +849,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+19"/> + <location line="+17"/> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> <translation>Wallet is <b>encrypted</b> and currently <b>unlocked</b></translation> </message> @@ -859,7 +859,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Wallet is <b>encrypted</b> and currently <b>locked</b></translation> </message> <message> - <location line="+120"/> + <location line="+119"/> <source>Original message:</source> <translation type="unfinished"></translation> </message> @@ -952,7 +952,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished">Confirmed</translation> </message> <message> - <location filename="../coincontroldialog.cpp" line="+66"/> + <location filename="../coincontroldialog.cpp" line="+69"/> <source>Copy amount</source> <translation type="unfinished"></translation> </message> @@ -973,7 +973,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+1"/> - <source>Copy transaction &ID</source> + <source>Copy transaction &ID and output index</source> <translation type="unfinished"></translation> </message> <message> @@ -1017,7 +1017,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+302"/> + <location line="+306"/> <source>(%1 locked)</source> <translation type="unfinished"></translation> </message> @@ -1061,12 +1061,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context> <name>CreateWalletActivity</name> <message> - <location filename="../walletcontroller.cpp" line="+254"/> + <location filename="../walletcontroller.cpp" line="+243"/> + <source>Create Wallet</source> + <extracomment>Title of window indicating the progress of creation of a new wallet.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Creating Wallet <b>%1</b>…</source> + <extracomment>Descriptive text of the create wallet progress window which indicates to the user which wallet is currently being created.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+31"/> + <location line="+29"/> <source>Create wallet failed</source> <translation type="unfinished"></translation> </message> @@ -1144,7 +1151,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+10"/> <source>Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source> <translation type="unfinished"></translation> </message> @@ -1402,6 +1409,21 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> </context> <context> + <name>LoadWalletsActivity</name> + <message> + <location filename="../walletcontroller.cpp" line="+69"/> + <source>Load Wallets</source> + <extracomment>Title of progress window which is displayed when wallets are being loaded.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Loading wallets…</source> + <extracomment>Descriptive text of the load wallets progress window which indicates to the user that wallets are currently being loaded.</extracomment> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>ModalOverlay</name> <message> <location filename="../forms/modaloverlay.ui" line="+14"/> @@ -1489,11 +1511,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source>URI:</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+14"/> + <source>Paste address from clipboard</source> + <extracomment>Tooltip text for button that allows you to paste an address that is in your clipboard.</extracomment> + <translation type="unfinished">Paste address from clipboard</translation> + </message> </context> <context> <name>OpenWalletActivity</name> <message> - <location filename="../walletcontroller.cpp" line="+32"/> + <location filename="../walletcontroller.cpp" line="-42"/> <source>Open wallet failed</source> <translation type="unfinished"></translation> </message> @@ -1508,8 +1536,15 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> + <location line="+4"/> + <source>Open Wallet</source> + <extracomment>Title of window indicating the progress of opening of a wallet.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Opening Wallet <b>%1</b>…</source> + <extracomment>Descriptive text of the open wallet progress window which indicates to the user which wallet is currently being opened.</extracomment> <translation type="unfinished"></translation> </message> </context> @@ -1541,17 +1576,17 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+50"/> + <location line="+53"/> <source>Size of &database cache</source> <translation type="unfinished"></translation> </message> <message> - <location line="+43"/> + <location line="+46"/> <source>Number of script &verification threads</source> <translation type="unfinished"></translation> </message> <message> - <location line="+201"/> + <location line="+231"/> <location line="+187"/> <source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <translation type="unfinished"></translation> @@ -1569,13 +1604,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+80"/> - <location line="+13"/> - <source>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> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+179"/> + <location line="+272"/> <source>Open the %1 configuration file from the working directory.</source> <translation type="unfinished"></translation> </message> @@ -1600,7 +1629,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>&Network</translation> </message> <message> - <location line="-218"/> + <location line="-254"/> <source>Prune &block storage to</source> <translation type="unfinished"></translation> </message> @@ -1615,22 +1644,58 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+28"/> + <location line="+12"/> + <source>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> + <extracomment>Tooltip text for Options window setting that sets the size of the database cache. Explains the corresponding effects of increasing/decreasing this value.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+19"/> <source>MiB</source> <translation type="unfinished"></translation> </message> <message> - <location line="+40"/> + <location line="+27"/> + <source>Set the number of script verification threads. Negative values correspond to the number of cores you want to leave free to the system.</source> + <extracomment>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.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+16"/> <source>(0 = auto, <0 = leave that many cores free)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+36"/> + <location line="+22"/> + <source>This allows you or a third party tool to communicate with the node through command-line and JSON-RPC commands.</source> + <extracomment>Tooltip text for Options window setting that enables the RPC server.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Enable R&PC server</source> + <extracomment>An Options window setting to enable the RPC server.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+21"/> <source>W&allet</source> <translation type="unfinished"></translation> </message> <message> <location line="+6"/> + <source>Whether to set subtract fee from amount as default or not.</source> + <extracomment>Tooltip text for Options window setting that sets subtracting the fee from a sending amount as default.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Subtract &fee from amount by default</source> + <extracomment>An Options window setting to set subtracting the fee from a sending amount as default.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+7"/> <source>Expert</source> <translation type="unfinished"></translation> </message> @@ -1650,6 +1715,18 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> + <location line="+7"/> + <source>Enable &PSBT controls</source> + <extracomment>An options window setting to enable PSBT controls.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Whether to show PSBT controls.</source> + <extracomment>Tooltip text for options window setting that enables PSBT controls.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> <location line="+10"/> <source>External Signer (e.g. hardware wallet)</source> <translation type="unfinished"></translation> @@ -1798,12 +1875,23 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>Choose the default subdivision unit to show in the interface and when sending coins.</translation> </message> <message> - <location line="-493"/> + <location line="+11"/> + <location line="+13"/> + <source>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> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-10"/> + <source>&Third-party transaction URLs</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-517"/> <source>Whether to show coin control features or not.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+290"/> + <location line="+300"/> <source>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> <translation type="unfinished"></translation> </message> @@ -1813,12 +1901,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+214"/> - <source>&Third party transaction URLs</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+22"/> + <location line="+236"/> <source>Monospaced font in the Overview tab:</source> <translation type="unfinished"></translation> </message> @@ -1848,7 +1931,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation>&Cancel</translation> </message> <message> - <location filename="../optionsdialog.cpp" line="+97"/> + <location filename="../optionsdialog.cpp" line="+99"/> <source>Compiled without external signing support (required for external signing)</source> <extracomment>"External signing" means using devices such as hardware wallets.</extracomment> <translation type="unfinished"></translation> @@ -1864,33 +1947,45 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+93"/> + <location line="+97"/> <source>Confirm options reset</source> <translation>Confirm options reset</translation> </message> <message> <location line="+1"/> - <location line="+57"/> + <location line="+70"/> <source>Client restart required to activate changes.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-57"/> + <location line="-70"/> <source>Client will be shut down. Do you want to proceed?</source> <translation type="unfinished"></translation> </message> <message> - <location line="+15"/> + <location line="+18"/> <source>Configuration options</source> + <extracomment>Window title text of pop-up box that allows opening up of configuration file.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+3"/> <source>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> + <extracomment>Explanatory text about the priority order of instructions considered by client. The order from high to low being: command-line, configuration file, GUI settings.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+5"/> + <location line="+3"/> + <source>Continue</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Cancel</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> <source>Error</source> <translation type="unfinished">Error</translation> </message> @@ -2004,7 +2099,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../overviewpage.cpp" line="+188"/> + <location filename="../overviewpage.cpp" line="+187"/> <source>Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> <translation type="unfinished"></translation> </message> @@ -2042,17 +2137,22 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../psbtoperationsdialog.cpp" line="+55"/> + <location filename="../psbtoperationsdialog.cpp" line="+58"/> <source>Failed to load transaction: %1</source> <translation type="unfinished"></translation> </message> <message> - <location line="+18"/> + <location line="+25"/> <source>Failed to sign transaction: %1</source> <translation type="unfinished"></translation> </message> <message> <location line="+8"/> + <source>Cannot sign inputs while wallet is locked.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> <source>Could not sign any more inputs.</source> <translation type="unfinished"></translation> </message> @@ -2133,7 +2233,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+42"/> + <location line="+46"/> <source>Transaction is missing some information about inputs.</source> <translation type="unfinished"></translation> </message> @@ -2144,6 +2244,11 @@ Signing is only possible with addresses of the type 'legacy'.</source> </message> <message> <location line="+3"/> + <source>(But no wallet is loaded.)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>(But this wallet cannot sign transactions.)</source> <translation type="unfinished"></translation> </message> @@ -2210,7 +2315,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="+107"/> + <location filename="../peertablemodel.h" line="+108"/> <source>User Agent</source> <extracomment>Title of Peers Table column which contains the peer's User Agent string.</extracomment> <translation type="unfinished"></translation> @@ -2222,13 +2327,19 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="-12"/> + <location line="-15"/> <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="+15"/> + <location line="+6"/> + <source>Direction</source> + <extracomment>Title of Peers Table column which indicates the direction the peer connection was initiated from.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+12"/> <source>Sent</source> <extracomment>Title of Peers Table column which indicates the total amount of network information we have sent to the peer.</extracomment> <translation type="unfinished"></translation> @@ -2240,13 +2351,13 @@ 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>Address</source> <extracomment>Title of Peers Table column which contains the IP/Onion/I2P address of the connected peer.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+6"/> <source>Type</source> <extracomment>Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</extracomment> <translation type="unfinished"></translation> @@ -2257,21 +2368,33 @@ If you are receiving this error you should request the merchant provide a BIP21 <extracomment>Title of Peers Table column which states the network the peer connected through.</extracomment> <translation type="unfinished">Network</translation> </message> + <message> + <location filename="../peertablemodel.cpp" line="+79"/> + <source>Inbound</source> + <extracomment>An Inbound Connection from a Peer.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Outbound</source> + <extracomment>An Outbound Connection to a Peer.</extracomment> + <translation type="unfinished"></translation> + </message> </context> <context> <name>QObject</name> <message> - <location filename="../bitcoinunits.cpp" line="+213"/> + <location filename="../bitcoinunits.cpp" line="+215"/> <source>Amount</source> <translation type="unfinished">Amount</translation> </message> <message> - <location filename="../guiutil.cpp" line="+120"/> + <location filename="../guiutil.cpp" line="+122"/> <source>Enter a Bitcoin address (e.g. %1)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+540"/> + <location line="+546"/> <source>Unroutable</source> <translation type="unfinished"></translation> </message> @@ -2281,42 +2404,49 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+10"/> + <location line="+13"/> <source>Inbound</source> + <extracomment>An inbound connection from a peer. An inbound connection is a connection initiated by a peer.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+0"/> + <location line="+3"/> <source>Outbound</source> + <extracomment>An outbound connection to a peer. An outbound connection is a connection initiated by us.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> + <location line="+5"/> <source>Full Relay</source> + <extracomment>Peer connection type that relays all network information.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+3"/> <source>Block Relay</source> + <extracomment>Peer connection type that relays network information about blocks and not transactions or addresses.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+2"/> <source>Manual</source> + <extracomment>Peer connection type established manually through one of several methods.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+2"/> <source>Feeler</source> + <extracomment>Short-lived peer connection type that tests the aliveness of known addresses.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+2"/> <source>Address Fetch</source> + <extracomment>Short-lived peer connection type that solicits known addresses from a peer.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+15"/> <source>%1 d</source> <translation type="unfinished"></translation> </message> @@ -2426,7 +2556,19 @@ 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="+112"/> + <location filename="../bitcoin.cpp" line="-272"/> + <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> + </message> + <message> + <location line="+24"/> + <source>A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source> + <extracomment>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.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+359"/> <source>Error: Specified data directory "%1" does not exist.</source> <translation type="unfinished"></translation> </message> @@ -2441,12 +2583,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+9"/> - <source>Error initializing settings: %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+63"/> + <location line="+71"/> <source>%1 didn't yet exit safely…</source> <translation type="unfinished"></translation> </message> @@ -2491,7 +2628,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <message> <location line="+3"/> <source>PNG Image</source> - <extracomment>Expanded name of the PNG file format. See https://en.wikipedia.org/wiki/Portable_Network_Graphics</extracomment> + <extracomment>Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</extracomment> <translation type="unfinished"></translation> </message> </context> @@ -2532,12 +2669,15 @@ If you are receiving this error you should request the merchant provide a BIP21 <location line="+23"/> <location line="+23"/> <location line="+26"/> + <location line="+26"/> + <location line="+26"/> + <location line="+26"/> <location filename="../rpcconsole.h" line="+139"/> <source>N/A</source> <translation>N/A</translation> </message> <message> - <location line="-1519"/> + <location line="-1597"/> <source>Client version</source> <translation>Client version</translation> </message> @@ -2651,7 +2791,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="+1124"/> + <location filename="../rpcconsole.cpp" line="+1158"/> <source>Select a peer to view detailed information.</source> <translation type="unfinished"></translation> </message> @@ -2676,7 +2816,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+285"/> + <location line="+75"/> + <source>Last Transaction</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+210"/> <source>The mapped Autonomous System used for diversifying peer selection.</source> <translation type="unfinished"></translation> </message> @@ -2686,7 +2831,40 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="-1486"/> + <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> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Address Relay</source> + <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> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Addresses Processed</source> + <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> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Addresses Rate-Limited</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-1564"/> <location line="+1051"/> <source>User Agent</source> <translation type="unfinished"></translation> @@ -2779,15 +2957,11 @@ If you are receiving this error you should request the merchant provide a BIP21 <message> <location line="+23"/> <source>Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source> + <extracomment>Tooltip text for the Last Transaction field in the peer details area.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> - <source>Last Tx</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+23"/> + <location line="+26"/> <source>Last Send</source> <translation type="unfinished"></translation> </message> @@ -2892,38 +3066,44 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+40"/> + <location line="+41"/> <source>Never</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../rpcconsole.cpp" line="-429"/> + <location filename="../rpcconsole.cpp" line="-457"/> <source>Inbound: initiated by peer</source> + <extracomment>Explanatory text for an inbound peer connection.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+4"/> <source>Outbound Full Relay: default</source> + <extracomment>Explanatory text for an outbound peer connection that relays all network information. This is the default behavior for outbound connections.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+3"/> <source>Outbound Block Relay: does not relay transactions or addresses</source> + <extracomment>Explanatory text for an outbound peer connection that relays network information about blocks and not transactions or addresses.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+5"/> <source>Outbound Manual: added using RPC %1 or %2/%3 configuration options</source> + <extracomment>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.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> + <location line="+6"/> <source>Outbound Feeler: short-lived, for testing addresses</source> + <extracomment>Explanatory text for a short-lived outbound peer connection that is used to test the aliveness of known addresses.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+1"/> + <location line="+3"/> <source>Outbound Address Fetch: short-lived, for soliciting addresses</source> + <extracomment>Explanatory text for a short-lived outbound peer connection that is used to request addresses from a peer.</extracomment> <translation type="unfinished"></translation> </message> <message> @@ -2966,7 +3146,13 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+150"/> + <location line="+151"/> + <source>&Copy address</source> + <extracomment>Context menu action to copy the address of a peer.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> <source>&Disconnect</source> <translation type="unfinished"></translation> </message> @@ -2991,12 +3177,18 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="+22"/> + <location line="+25"/> + <source>&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's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> <source>&Unban</source> <translation type="unfinished"></translation> </message> <message> - <location line="+221"/> + <location line="+224"/> <source>Network activity disabled</source> <translation type="unfinished"></translation> </message> @@ -3011,7 +3203,7 @@ If you are receiving this error you should request the merchant provide a BIP21 <translation type="unfinished"></translation> </message> <message> - <location line="-146"/> + <location line="-145"/> <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. @@ -3023,7 +3215,7 @@ For more information on using this console, type %6. <translation type="unfinished"></translation> </message> <message> - <location line="+156"/> + <location line="+155"/> <source>Executing…</source> <extracomment>A console message indicating an entered command is currently being executed.</extracomment> <translation type="unfinished"></translation> @@ -3039,7 +3231,7 @@ For more information on using this console, type %6. <translation type="unfinished"></translation> </message> <message> - <location filename="../rpcconsole.h" line="-40"/> + <location filename="../rpcconsole.h" line="-41"/> <source>Unknown</source> <translation type="unfinished"></translation> </message> @@ -3108,17 +3300,7 @@ For more information on using this console, type %6. <translation type="unfinished"></translation> </message> <message> - <location line="+78"/> - <source>Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> - <source>Generate native segwit (Bech32) address</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+61"/> + <location line="+136"/> <source>Requested payments history</source> <translation type="unfinished"></translation> </message> @@ -3288,7 +3470,7 @@ For more information on using this console, type %6. <name>SendCoinsDialog</name> <message> <location filename="../forms/sendcoinsdialog.ui" line="+14"/> - <location filename="../sendcoinsdialog.cpp" line="+738"/> + <location filename="../sendcoinsdialog.cpp" line="+749"/> <source>Send Coins</source> <translation>Send Coins</translation> </message> @@ -3475,7 +3657,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation>S&end</translation> </message> <message> - <location filename="../sendcoinsdialog.cpp" line="-646"/> + <location filename="../sendcoinsdialog.cpp" line="-653"/> <source>Copy quantity</source> <translation type="unfinished"></translation> </message> @@ -3517,7 +3699,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <message> <location line="+30"/> <source>Sign on device</source> - <extracomment>"device" usually means a hardware wallet</extracomment> + <extracomment>"device" usually means a hardware wallet.</extracomment> <translation type="unfinished"></translation> </message> <message> @@ -3557,32 +3739,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> - <source>Do you want to draft this transaction?</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+2"/> - <source>Are you sure you want to send?</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+52"/> + <location line="+67"/> <source>To review recipient list click "Show Details…"</source> <translation type="unfinished"></translation> </message> <message> - <location line="+19"/> - <source>Create Unsigned</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+0"/> - <source>Sign and send</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+25"/> + <location line="+44"/> <source>Sign failed</source> <translation type="unfinished"></translation> </message> @@ -3615,12 +3777,12 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="+175"/> + <location line="+176"/> <source>External balance:</source> <translation type="unfinished"></translation> </message> <message> - <location line="-302"/> + <location line="-303"/> <source>or</source> <translation type="unfinished"></translation> </message> @@ -3630,13 +3792,27 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="-24"/> + <location line="-30"/> <source>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> + <extracomment>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.</extracomment> <translation type="unfinished"></translation> </message> <message> - <location line="+2"/> + <location line="-6"/> + <source>Do you want to create this transaction?</source> + <extracomment>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.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+11"/> + <source>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> + <extracomment>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.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Please, review your transaction.</source> + <extracomment>Text to prompt a user to review the details of the transaction they are attempting to send.</extracomment> <translation type="unfinished"></translation> </message> <message> @@ -3660,12 +3836,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="+0"/> - <source>Confirm transaction proposal</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+283"/> + <location line="+284"/> <source>Watch-only balance:</source> <translation type="unfinished"></translation> </message> @@ -3854,6 +4025,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </message> </context> <context> + <name>SendConfirmationDialog</name> + <message> + <location filename="../sendcoinsdialog.h" line="+131"/> + <source>Send</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> + <source>Create Unsigned</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>ShutdownWindow</name> <message> <location filename="../utilitydialog.cpp" line="+85"/> @@ -4067,6 +4251,19 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </message> </context> <context> + <name>SplashScreen</name> + <message> + <location filename="../splashscreen.cpp" line="+187"/> + <source>(press q to shutdown and continue later)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>press q to shutdown</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> <name>TrafficGraphWidget</name> <message> <location filename="../trafficgraphwidget.cpp" line="+82"/> @@ -4076,21 +4273,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </context> <context> <name>TransactionDesc</name> - <message numerus="yes"> - <location filename="../transactiondesc.cpp" line="+36"/> - <source>Open for %n more block(s)</source> - <translation> - <numerusform>Open for %n more block</numerusform> - <numerusform>Open for %n more blocks</numerusform> - </translation> - </message> - <message> - <location line="+2"/> - <source>Open until %1</source> - <translation type="unfinished"></translation> - </message> <message> - <location line="+6"/> + <location filename="../transactiondesc.cpp" line="+40"/> <source>conflicted with a transaction with %1 confirmations</source> <translation type="unfinished"></translation> </message> @@ -4337,21 +4521,8 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <source>Label</source> <translation type="unfinished"></translation> </message> - <message numerus="yes"> - <location line="+60"/> - <source>Open for %n more block(s)</source> - <translation> - <numerusform>Open for %n more block</numerusform> - <numerusform>Open for %n more blocks</numerusform> - </translation> - </message> <message> - <location line="+3"/> - <source>Open until %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> + <location line="+60"/> <source>Unconfirmed</source> <translation type="unfinished"></translation> </message> @@ -4421,7 +4592,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="+210"/> + <location line="+207"/> <source>(no label)</source> <translation type="unfinished"></translation> </message> @@ -4459,7 +4630,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <context> <name>TransactionView</name> <message> - <location filename="../transactionview.cpp" line="+70"/> + <location filename="../transactionview.cpp" line="+73"/> <location line="+16"/> <source>All</source> <translation type="unfinished"></translation> @@ -4580,14 +4751,20 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <translation type="unfinished"></translation> </message> <message> - <location line="+174"/> + <location line="+59"/> + <source>Show in %1</source> + <extracomment>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.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+119"/> <source>Export Transaction History</source> <translation type="unfinished"></translation> </message> <message> <location line="+3"/> <source>Comma separated file</source> - <extracomment>Expanded name of the CSV file format. See https://en.wikipedia.org/wiki/Comma-separated_values</extracomment> + <extracomment>Expanded name of the CSV file format. See: https://en.wikipedia.org/wiki/Comma-separated_values.</extracomment> <translation type="unfinished"></translation> </message> <message> @@ -4667,7 +4844,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <context> <name>WalletController</name> <message> - <location filename="../walletcontroller.cpp" line="-262"/> + <location filename="../walletcontroller.cpp" line="-259"/> <source>Close wallet</source> <translation type="unfinished"></translation> </message> @@ -4695,7 +4872,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <context> <name>WalletFrame</name> <message> - <location filename="../walletframe.cpp" line="+35"/> + <location filename="../walletframe.cpp" line="+42"/> <source>No wallet has been loaded. Go to File > Open Wallet to load a wallet. - OR -</source> @@ -4706,35 +4883,63 @@ Go to File > Open Wallet to load a wallet. <source>Create a new wallet</source> <translation type="unfinished"></translation> </message> + <message> + <location line="+154"/> + <location line="+9"/> + <location line="+10"/> + <source>Error</source> + <translation type="unfinished">Error</translation> + </message> + <message> + <location line="-19"/> + <source>Unable to decode PSBT from clipboard (invalid base64)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Load Transaction Data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Partially Signed Transaction (*.psbt)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>PSBT file must be smaller than 100 MiB</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Unable to decode PSBT</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>WalletModel</name> <message> - <location filename="../walletmodel.cpp" line="+218"/> + <location filename="../walletmodel.cpp" line="+221"/> <source>Send Coins</source> <translation type="unfinished">Send Coins</translation> </message> <message> <location line="+260"/> <location line="+52"/> - <location line="+13"/> + <location line="+15"/> <location line="+5"/> <source>Fee bump error</source> <translation type="unfinished"></translation> </message> <message> - <location line="-70"/> + <location line="-72"/> <source>Increasing transaction fee failed</source> <translation type="unfinished"></translation> </message> <message> - <location line="+8"/> + <location line="+7"/> <source>Do you want to increase the fee?</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+0"/> - <source>Do you want to draft a transaction with fee increase?</source> + <extracomment>Asks a user if they would like to manually increase the fee of a transaction that has already been created.</extracomment> <translation type="unfinished"></translation> </message> <message> @@ -4763,7 +4968,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+21"/> + <location line="+22"/> <source>Can't draft transaction.</source> <translation type="unfinished"></translation> </message> @@ -4773,7 +4978,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="+8"/> <source>Can't sign transaction.</source> <translation type="unfinished"></translation> </message> @@ -4796,7 +5001,7 @@ Go to File > Open Wallet to load a wallet. <context> <name>WalletView</name> <message> - <location filename="../walletview.cpp" line="+51"/> + <location filename="../walletview.cpp" line="+52"/> <source>&Export</source> <translation type="unfinished">&Export</translation> </message> @@ -4806,39 +5011,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished">Export the data in the current tab to a file</translation> </message> <message> - <location line="+165"/> - <location line="+9"/> - <location line="+10"/> - <source>Error</source> - <translation type="unfinished">Error</translation> - </message> - <message> - <location line="-19"/> - <source>Unable to decode PSBT from clipboard (invalid base64)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+5"/> - <source>Load Transaction Data</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+1"/> - <source>Partially Signed Transaction (*.psbt)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+3"/> - <source>PSBT file must be smaller than 100 MiB</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+10"/> - <source>Unable to decode PSBT</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+39"/> + <location line="+164"/> <source>Backup Wallet</source> <translation type="unfinished"></translation> </message> @@ -4869,7 +5042,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+44"/> + <location line="+35"/> <source>Cancel</source> <translation type="unfinished"></translation> </message> @@ -4923,6 +5096,11 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+3"/> + <source>Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> <translation type="unfinished"></translation> </message> @@ -4963,6 +5141,11 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+3"/> + <source>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> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> <source>More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> <translation type="unfinished"></translation> </message> @@ -5008,11 +5191,21 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+3"/> + <source>The -txindex upgrade started by a previous version can not be completed. Restart with the previous version or run a full -reindex.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>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</source> <translation type="unfinished"></translation> </message> <message> <location line="+5"/> + <source>The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+4"/> <source>The transaction amount is too small to send after the fee has been deducted</source> <translation type="unfinished"></translation> </message> @@ -5103,6 +5296,11 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> + <source>Cannot set -forcednsseed to true when setting -dnsseed to false.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Cannot set -peerblockfilters without -blockfilterindex.</source> <translation type="unfinished"></translation> </message> @@ -5313,6 +5511,11 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> + <source>Input not found or already spent</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Insufficient funds</source> <translation type="unfinished"></translation> </message> @@ -5383,11 +5586,26 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> + <source>Missing amount</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Missing solving data for estimating transaction size</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Need to specify a port with -whitebind: '%s'</source> <translation type="unfinished"></translation> </message> <message> <location line="+1"/> + <source>No addresses available</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> <translation type="unfinished"></translation> </message> @@ -5543,7 +5761,7 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> - <source>Transaction needs a change address, but we can't generate it. %s</source> + <source>Transaction needs a change address, but we can't generate it.</source> <translation type="unfinished"></translation> </message> <message> @@ -5583,6 +5801,11 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> + <source>Unable to parse -maxuploadtarget: '%s'</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Unable to start HTTP server. See debug log for details.</source> <translation type="unfinished"></translation> </message> @@ -5623,11 +5846,6 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> - <source>Upgrading txindex 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> @@ -5646,5 +5864,15 @@ Go to File > Open Wallet to load a wallet. <source>Wallet needed to be rewritten: restart %s to complete</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../bitcoin.cpp" line="-482"/> + <source>Settings file could not be read</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+23"/> + <source>Settings file could not be written</source> + <translation type="unfinished"></translation> + </message> </context> </TS> diff --git a/src/qt/locale/bitcoin_en.xlf b/src/qt/locale/bitcoin_en.xlf index caefddc663..0acc69b3bc 100644 --- a/src/qt/locale/bitcoin_en.xlf +++ b/src/qt/locale/bitcoin_en.xlf @@ -122,7 +122,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <source xml:space="preserve">Comma separated file</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">286</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> + <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> @@ -326,680 +326,699 @@ Signing is only possible with addresses of the type 'legacy'.</source> <trans-unit id="_msg58"> <source xml:space="preserve">Runaway exception</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">421</context></context-group> + <context-group purpose="location"><context context-type="linenumber">429</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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">422</context></context-group> + <context-group purpose="location"><context context-type="linenumber">430</context></context-group> </trans-unit> <trans-unit id="_msg60"> <source xml:space="preserve">Internal error</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">431</context></context-group> + <context-group purpose="location"><context context-type="linenumber">439</context></context-group> </trans-unit> <trans-unit id="_msg61"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">432</context></context-group> + <context-group purpose="location"><context context-type="linenumber">440</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="QObject"> <trans-unit id="_msg62"> - <source xml:space="preserve">Error: Specified data directory "%1" does not exist.</source> + <source xml:space="preserve">Do you want to reset settings to default values, or to abort without making changes?</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">544</context></context-group> + <context-group purpose="location"><context context-type="linenumber">168</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"> - <source xml:space="preserve">Error: Cannot parse configuration file: %1.</source> + <source xml:space="preserve">A fatal error occurred. Check that settings file is writable, or try running with -nosettings.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">550</context></context-group> + <context-group purpose="location"><context context-type="linenumber">192</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"> - <source xml:space="preserve">Error: %1</source> + <source xml:space="preserve">Error: Specified data directory "%1" does not exist.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">565</context></context-group> + <context-group purpose="location"><context context-type="linenumber">551</context></context-group> </trans-unit> <trans-unit id="_msg65"> - <source xml:space="preserve">Error initializing settings: %1</source> + <source xml:space="preserve">Error: Cannot parse configuration file: %1.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">574</context></context-group> + <context-group purpose="location"><context context-type="linenumber">557</context></context-group> </trans-unit> <trans-unit id="_msg66"> + <source xml:space="preserve">Error: %1</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">572</context></context-group> + </trans-unit> + <trans-unit id="_msg67"> <source xml:space="preserve">%1 didn't yet exit safely…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">637</context></context-group> + <context-group purpose="location"><context context-type="linenumber">643</context></context-group> + </trans-unit> + </group> + <group restype="x-trolltech-linguist-context" resname="bitcoin-core"> + <trans-unit id="_msg68"> + <source xml:space="preserve">Settings file could not be read</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">161</context></context-group> + </trans-unit> + <trans-unit id="_msg69"> + <source xml:space="preserve">Settings file could not be written</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">184</context></context-group> </trans-unit> </group> </body></file> <file original="../bitcoingui.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="BitcoinGUI"> - <trans-unit id="_msg67" approved="yes"> + <trans-unit id="_msg70" approved="yes"> <source xml:space="preserve">&Overview</source> <target xml:space="preserve">&Overview</target> - <context-group purpose="location"><context context-type="linenumber">245</context></context-group> + <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> - <trans-unit id="_msg68" approved="yes"> + <trans-unit id="_msg71" approved="yes"> <source xml:space="preserve">Show general overview of wallet</source> <target xml:space="preserve">Show general overview of wallet</target> - <context-group purpose="location"><context context-type="linenumber">246</context></context-group> + <context-group purpose="location"><context context-type="linenumber">251</context></context-group> </trans-unit> - <trans-unit id="_msg69" approved="yes"> + <trans-unit id="_msg72" approved="yes"> <source xml:space="preserve">&Transactions</source> <target xml:space="preserve">&Transactions</target> - <context-group purpose="location"><context context-type="linenumber">274</context></context-group> + <context-group purpose="location"><context context-type="linenumber">279</context></context-group> </trans-unit> - <trans-unit id="_msg70" approved="yes"> + <trans-unit id="_msg73" approved="yes"> <source xml:space="preserve">Browse transaction history</source> <target xml:space="preserve">Browse transaction history</target> - <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="_msg71" approved="yes"> + <trans-unit id="_msg74" approved="yes"> <source xml:space="preserve">E&xit</source> <target xml:space="preserve">E&xit</target> - <context-group purpose="location"><context context-type="linenumber">298</context></context-group> + <context-group purpose="location"><context context-type="linenumber">303</context></context-group> </trans-unit> - <trans-unit id="_msg72" approved="yes"> + <trans-unit id="_msg75" approved="yes"> <source xml:space="preserve">Quit application</source> <target xml:space="preserve">Quit application</target> - <context-group purpose="location"><context context-type="linenumber">299</context></context-group> + <context-group purpose="location"><context context-type="linenumber">304</context></context-group> </trans-unit> - <trans-unit id="_msg73"> + <trans-unit id="_msg76"> <source xml:space="preserve">&About %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">302</context></context-group> + <context-group purpose="location"><context context-type="linenumber">307</context></context-group> </trans-unit> - <trans-unit id="_msg74"> + <trans-unit id="_msg77"> <source xml:space="preserve">Show information about %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">303</context></context-group> + <context-group purpose="location"><context context-type="linenumber">308</context></context-group> </trans-unit> - <trans-unit id="_msg75" approved="yes"> + <trans-unit id="_msg78" approved="yes"> <source xml:space="preserve">About &Qt</source> <target xml:space="preserve">About &Qt</target> - <context-group purpose="location"><context context-type="linenumber">306</context></context-group> + <context-group purpose="location"><context context-type="linenumber">311</context></context-group> </trans-unit> - <trans-unit id="_msg76" approved="yes"> + <trans-unit id="_msg79" approved="yes"> <source xml:space="preserve">Show information about Qt</source> <target xml:space="preserve">Show information about Qt</target> - <context-group purpose="location"><context context-type="linenumber">307</context></context-group> + <context-group purpose="location"><context context-type="linenumber">312</context></context-group> </trans-unit> - <trans-unit id="_msg77"> + <trans-unit id="_msg80"> <source xml:space="preserve">Modify configuration options for %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">310</context></context-group> + <context-group purpose="location"><context context-type="linenumber">315</context></context-group> </trans-unit> - <trans-unit id="_msg78"> + <trans-unit id="_msg81"> <source xml:space="preserve">Create a new wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">356</context></context-group> + <context-group purpose="location"><context context-type="linenumber">361</context></context-group> + </trans-unit> + <trans-unit id="_msg82"> + <source xml:space="preserve">&Minimize</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">489</context></context-group> </trans-unit> - <trans-unit id="_msg79"> + <trans-unit id="_msg83"> <source xml:space="preserve">Wallet:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">565</context></context-group> + <context-group purpose="location"><context context-type="linenumber">568</context></context-group> </trans-unit> - <trans-unit id="_msg80"> + <trans-unit id="_msg84"> <source xml:space="preserve">Network activity disabled.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">938</context></context-group> + <context-group purpose="location"><context context-type="linenumber">939</context></context-group> <note annotates="source" from="developer">A substring of the tooltip.</note> </trans-unit> - <trans-unit id="_msg81"> + <trans-unit id="_msg85"> <source xml:space="preserve">Proxy is <b>enabled</b>: %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1362</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1361</context></context-group> </trans-unit> - <trans-unit id="_msg82" approved="yes"> + <trans-unit id="_msg86" approved="yes"> <source xml:space="preserve">Send coins to a Bitcoin address</source> <target xml:space="preserve">Send coins to a Bitcoin address</target> - <context-group purpose="location"><context context-type="linenumber">253</context></context-group> + <context-group purpose="location"><context context-type="linenumber">258</context></context-group> </trans-unit> - <trans-unit id="_msg83" approved="yes"> + <trans-unit id="_msg87" approved="yes"> <source xml:space="preserve">Backup wallet to another location</source> <target xml:space="preserve">Backup wallet to another location</target> - <context-group purpose="location"><context context-type="linenumber">320</context></context-group> + <context-group purpose="location"><context context-type="linenumber">325</context></context-group> </trans-unit> - <trans-unit id="_msg84" approved="yes"> + <trans-unit id="_msg88" approved="yes"> <source xml:space="preserve">Change the passphrase used for wallet encryption</source> <target xml:space="preserve">Change the passphrase used for wallet encryption</target> - <context-group purpose="location"><context context-type="linenumber">322</context></context-group> + <context-group purpose="location"><context context-type="linenumber">327</context></context-group> </trans-unit> - <trans-unit id="_msg85" approved="yes"> + <trans-unit id="_msg89" approved="yes"> <source xml:space="preserve">&Send</source> <target xml:space="preserve">&Send</target> - <context-group purpose="location"><context context-type="linenumber">252</context></context-group> + <context-group purpose="location"><context context-type="linenumber">257</context></context-group> </trans-unit> - <trans-unit id="_msg86" approved="yes"> + <trans-unit id="_msg90" approved="yes"> <source xml:space="preserve">&Receive</source> <target xml:space="preserve">&Receive</target> - <context-group purpose="location"><context context-type="linenumber">263</context></context-group> + <context-group purpose="location"><context context-type="linenumber">268</context></context-group> </trans-unit> - <trans-unit id="_msg87"> + <trans-unit id="_msg91"> <source xml:space="preserve">&Options…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">309</context></context-group> + <context-group purpose="location"><context context-type="linenumber">314</context></context-group> </trans-unit> - <trans-unit id="_msg88" approved="yes"> + <trans-unit id="_msg92" approved="yes"> <source xml:space="preserve">&Show / Hide</source> <target xml:space="preserve">&Show / Hide</target> - <context-group purpose="location"><context context-type="linenumber">313</context></context-group> + <context-group purpose="location"><context context-type="linenumber">318</context></context-group> </trans-unit> - <trans-unit id="_msg89" approved="yes"> + <trans-unit id="_msg93" approved="yes"> <source xml:space="preserve">Show or hide the main Window</source> <target xml:space="preserve">Show or hide the main Window</target> - <context-group purpose="location"><context context-type="linenumber">314</context></context-group> + <context-group purpose="location"><context context-type="linenumber">319</context></context-group> </trans-unit> - <trans-unit id="_msg90"> + <trans-unit id="_msg94"> <source xml:space="preserve">&Encrypt Wallet…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">316</context></context-group> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> - <trans-unit id="_msg91" approved="yes"> + <trans-unit id="_msg95" approved="yes"> <source xml:space="preserve">Encrypt the private keys that belong to your wallet</source> <target xml:space="preserve">Encrypt the private keys that belong to your wallet</target> - <context-group purpose="location"><context context-type="linenumber">317</context></context-group> + <context-group purpose="location"><context context-type="linenumber">322</context></context-group> </trans-unit> - <trans-unit id="_msg92"> + <trans-unit id="_msg96"> <source xml:space="preserve">&Backup Wallet…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> </trans-unit> - <trans-unit id="_msg93"> + <trans-unit id="_msg97"> <source xml:space="preserve">&Change Passphrase…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">321</context></context-group> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> </trans-unit> - <trans-unit id="_msg94"> + <trans-unit id="_msg98"> <source xml:space="preserve">Sign &message…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">323</context></context-group> + <context-group purpose="location"><context context-type="linenumber">328</context></context-group> </trans-unit> - <trans-unit id="_msg95" approved="yes"> + <trans-unit id="_msg99" approved="yes"> <source xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</source> <target xml:space="preserve">Sign messages with your Bitcoin addresses to prove you own them</target> - <context-group purpose="location"><context context-type="linenumber">324</context></context-group> + <context-group purpose="location"><context context-type="linenumber">329</context></context-group> </trans-unit> - <trans-unit id="_msg96"> + <trans-unit id="_msg100"> <source xml:space="preserve">&Verify message…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">325</context></context-group> + <context-group purpose="location"><context context-type="linenumber">330</context></context-group> </trans-unit> - <trans-unit id="_msg97" approved="yes"> + <trans-unit id="_msg101" approved="yes"> <source xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</source> <target xml:space="preserve">Verify messages to ensure they were signed with specified Bitcoin addresses</target> - <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + <context-group purpose="location"><context context-type="linenumber">331</context></context-group> </trans-unit> - <trans-unit id="_msg98"> + <trans-unit id="_msg102"> <source xml:space="preserve">&Load PSBT from file…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">327</context></context-group> - </trans-unit> - <trans-unit id="_msg99"> - <source xml:space="preserve">Load PSBT from clipboard…</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + <context-group purpose="location"><context context-type="linenumber">332</context></context-group> </trans-unit> - <trans-unit id="_msg100"> + <trans-unit id="_msg103"> <source xml:space="preserve">Open &URI…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">343</context></context-group> + <context-group purpose="location"><context context-type="linenumber">348</context></context-group> </trans-unit> - <trans-unit id="_msg101"> + <trans-unit id="_msg104"> <source xml:space="preserve">Close Wallet…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">351</context></context-group> + <context-group purpose="location"><context context-type="linenumber">356</context></context-group> </trans-unit> - <trans-unit id="_msg102"> + <trans-unit id="_msg105"> <source xml:space="preserve">Create Wallet…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">354</context></context-group> + <context-group purpose="location"><context context-type="linenumber">359</context></context-group> </trans-unit> - <trans-unit id="_msg103"> + <trans-unit id="_msg106"> <source xml:space="preserve">Close All Wallets…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">358</context></context-group> + <context-group purpose="location"><context context-type="linenumber">363</context></context-group> </trans-unit> - <trans-unit id="_msg104" approved="yes"> + <trans-unit id="_msg107" approved="yes"> <source xml:space="preserve">&File</source> <target xml:space="preserve">&File</target> - <context-group purpose="location"><context context-type="linenumber">455</context></context-group> + <context-group purpose="location"><context context-type="linenumber">458</context></context-group> </trans-unit> - <trans-unit id="_msg105" approved="yes"> + <trans-unit id="_msg108" approved="yes"> <source xml:space="preserve">&Settings</source> <target xml:space="preserve">&Settings</target> - <context-group purpose="location"><context context-type="linenumber">473</context></context-group> + <context-group purpose="location"><context context-type="linenumber">476</context></context-group> </trans-unit> - <trans-unit id="_msg106" approved="yes"> + <trans-unit id="_msg109" approved="yes"> <source xml:space="preserve">&Help</source> <target xml:space="preserve">&Help</target> - <context-group purpose="location"><context context-type="linenumber">534</context></context-group> + <context-group purpose="location"><context context-type="linenumber">537</context></context-group> </trans-unit> - <trans-unit id="_msg107" approved="yes"> + <trans-unit id="_msg110" approved="yes"> <source xml:space="preserve">Tabs toolbar</source> <target xml:space="preserve">Tabs toolbar</target> - <context-group purpose="location"><context context-type="linenumber">545</context></context-group> + <context-group purpose="location"><context context-type="linenumber">548</context></context-group> </trans-unit> - <trans-unit id="_msg108"> + <trans-unit id="_msg111"> <source xml:space="preserve">Syncing Headers (%1%)…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">982</context></context-group> + <context-group purpose="location"><context context-type="linenumber">983</context></context-group> </trans-unit> - <trans-unit id="_msg109"> + <trans-unit id="_msg112"> <source xml:space="preserve">Synchronizing with network…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1028</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1030</context></context-group> </trans-unit> - <trans-unit id="_msg110"> + <trans-unit id="_msg113"> <source xml:space="preserve">Indexing blocks on disk…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1033</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1035</context></context-group> </trans-unit> - <trans-unit id="_msg111"> + <trans-unit id="_msg114"> <source xml:space="preserve">Processing blocks on disk…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1035</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1037</context></context-group> </trans-unit> - <trans-unit id="_msg112"> + <trans-unit id="_msg115"> <source xml:space="preserve">Reindexing blocks on disk…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1039</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1041</context></context-group> </trans-unit> - <trans-unit id="_msg113"> + <trans-unit id="_msg116"> <source xml:space="preserve">Connecting to peers…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1045</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1047</context></context-group> </trans-unit> - <trans-unit id="_msg114"> + <trans-unit id="_msg117"> <source xml:space="preserve">Request payments (generates QR codes and bitcoin: URIs)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">264</context></context-group> + <context-group purpose="location"><context context-type="linenumber">269</context></context-group> </trans-unit> - <trans-unit id="_msg115"> + <trans-unit id="_msg118"> <source xml:space="preserve">Show the list of used sending addresses and labels</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">339</context></context-group> + <context-group purpose="location"><context context-type="linenumber">344</context></context-group> </trans-unit> - <trans-unit id="_msg116"> + <trans-unit id="_msg119"> <source xml:space="preserve">Show the list of used receiving addresses and labels</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">341</context></context-group> + <context-group purpose="location"><context context-type="linenumber">346</context></context-group> </trans-unit> - <trans-unit id="_msg117"> + <trans-unit id="_msg120"> <source xml:space="preserve">&Command-line options</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">361</context></context-group> + <context-group purpose="location"><context context-type="linenumber">366</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">1054</context></context-group> - <trans-unit id="_msg118[0]" approved="yes"> + <context-group purpose="location"><context context-type="linenumber">1056</context></context-group> + <trans-unit id="_msg121[0]" approved="yes"> <source xml:space="preserve">Processed %n block(s) of transaction history.</source> <target xml:space="preserve">Processed %n block of transaction history.</target> </trans-unit> - <trans-unit id="_msg118[1]" approved="yes"> + <trans-unit id="_msg121[1]" approved="yes"> <source xml:space="preserve">Processed %n block(s) of transaction history.</source> <target xml:space="preserve">Processed %n blocks of transaction history.</target> </trans-unit> </group> - <trans-unit id="_msg119" approved="yes"> + <trans-unit id="_msg122" approved="yes"> <source xml:space="preserve">%1 behind</source> <target xml:space="preserve">%1 behind</target> - <context-group purpose="location"><context context-type="linenumber">1077</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1079</context></context-group> </trans-unit> - <trans-unit id="_msg120"> + <trans-unit id="_msg123"> <source xml:space="preserve">Catching up…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1082</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1084</context></context-group> </trans-unit> - <trans-unit id="_msg121" approved="yes"> + <trans-unit id="_msg124" approved="yes"> <source xml:space="preserve">Last received block was generated %1 ago.</source> <target xml:space="preserve">Last received block was generated %1 ago.</target> - <context-group purpose="location"><context context-type="linenumber">1101</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1103</context></context-group> </trans-unit> - <trans-unit id="_msg122" approved="yes"> + <trans-unit id="_msg125" approved="yes"> <source xml:space="preserve">Transactions after this will not yet be visible.</source> <target xml:space="preserve">Transactions after this will not yet be visible.</target> - <context-group purpose="location"><context context-type="linenumber">1103</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1105</context></context-group> </trans-unit> - <trans-unit id="_msg123" approved="yes"> + <trans-unit id="_msg126" approved="yes"> <source xml:space="preserve">Error</source> <target xml:space="preserve">Error</target> - <context-group purpose="location"><context context-type="linenumber">1128</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1130</context></context-group> </trans-unit> - <trans-unit id="_msg124" approved="yes"> + <trans-unit id="_msg127" approved="yes"> <source xml:space="preserve">Warning</source> <target xml:space="preserve">Warning</target> - <context-group purpose="location"><context context-type="linenumber">1132</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1134</context></context-group> </trans-unit> - <trans-unit id="_msg125" approved="yes"> + <trans-unit id="_msg128" approved="yes"> <source xml:space="preserve">Information</source> <target xml:space="preserve">Information</target> - <context-group purpose="location"><context context-type="linenumber">1136</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1138</context></context-group> </trans-unit> - <trans-unit id="_msg126" approved="yes"> + <trans-unit id="_msg129" approved="yes"> <source xml:space="preserve">Up to date</source> <target xml:space="preserve">Up to date</target> - <context-group purpose="location"><context context-type="linenumber">1058</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1060</context></context-group> </trans-unit> - <trans-unit id="_msg127"> + <trans-unit id="_msg130"> <source xml:space="preserve">Load Partially Signed Bitcoin Transaction</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">328</context></context-group> + <context-group purpose="location"><context context-type="linenumber">333</context></context-group> + </trans-unit> + <trans-unit id="_msg131"> + <source xml:space="preserve">Load PSBT from &clipboard…</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">334</context></context-group> </trans-unit> - <trans-unit id="_msg128"> + <trans-unit id="_msg132"> <source xml:space="preserve">Load Partially Signed Bitcoin Transaction from clipboard</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">330</context></context-group> + <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> - <trans-unit id="_msg129"> + <trans-unit id="_msg133"> <source xml:space="preserve">Node window</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">332</context></context-group> + <context-group purpose="location"><context context-type="linenumber">337</context></context-group> </trans-unit> - <trans-unit id="_msg130"> + <trans-unit id="_msg134"> <source xml:space="preserve">Open node debugging and diagnostic console</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">333</context></context-group> + <context-group purpose="location"><context context-type="linenumber">338</context></context-group> </trans-unit> - <trans-unit id="_msg131"> + <trans-unit id="_msg135"> <source xml:space="preserve">&Sending addresses</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">338</context></context-group> + <context-group purpose="location"><context context-type="linenumber">343</context></context-group> </trans-unit> - <trans-unit id="_msg132"> + <trans-unit id="_msg136"> <source xml:space="preserve">&Receiving addresses</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">340</context></context-group> + <context-group purpose="location"><context context-type="linenumber">345</context></context-group> </trans-unit> - <trans-unit id="_msg133"> + <trans-unit id="_msg137"> <source xml:space="preserve">Open a bitcoin: URI</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">344</context></context-group> + <context-group purpose="location"><context context-type="linenumber">349</context></context-group> </trans-unit> - <trans-unit id="_msg134"> + <trans-unit id="_msg138"> <source xml:space="preserve">Open Wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">346</context></context-group> + <context-group purpose="location"><context context-type="linenumber">351</context></context-group> </trans-unit> - <trans-unit id="_msg135"> + <trans-unit id="_msg139"> <source xml:space="preserve">Open a wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">348</context></context-group> + <context-group purpose="location"><context context-type="linenumber">353</context></context-group> </trans-unit> - <trans-unit id="_msg136"> + <trans-unit id="_msg140"> <source xml:space="preserve">Close wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">352</context></context-group> + <context-group purpose="location"><context context-type="linenumber">357</context></context-group> </trans-unit> - <trans-unit id="_msg137"> + <trans-unit id="_msg141"> <source xml:space="preserve">Close all wallets</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">359</context></context-group> + <context-group purpose="location"><context context-type="linenumber">364</context></context-group> </trans-unit> - <trans-unit id="_msg138"> + <trans-unit id="_msg142"> <source xml:space="preserve">Show the %1 help message to get a list with possible Bitcoin command-line options</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">363</context></context-group> + <context-group purpose="location"><context context-type="linenumber">368</context></context-group> </trans-unit> - <trans-unit id="_msg139"> + <trans-unit id="_msg143"> <source xml:space="preserve">&Mask values</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">365</context></context-group> + <context-group purpose="location"><context context-type="linenumber">370</context></context-group> </trans-unit> - <trans-unit id="_msg140"> + <trans-unit id="_msg144"> <source xml:space="preserve">Mask the values in the Overview tab</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">367</context></context-group> + <context-group purpose="location"><context context-type="linenumber">372</context></context-group> </trans-unit> - <trans-unit id="_msg141"> + <trans-unit id="_msg145"> <source xml:space="preserve">default wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">399</context></context-group> + <context-group purpose="location"><context context-type="linenumber">404</context></context-group> </trans-unit> - <trans-unit id="_msg142"> + <trans-unit id="_msg146"> <source xml:space="preserve">No wallets available</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">420</context></context-group> + <context-group purpose="location"><context context-type="linenumber">424</context></context-group> </trans-unit> - <trans-unit id="_msg143"> + <trans-unit id="_msg147"> <source xml:space="preserve">&Window</source> <target xml:space="preserve" state="needs-review-translation">&Window</target> - <context-group purpose="location"><context context-type="linenumber">484</context></context-group> - </trans-unit> - <trans-unit id="_msg144"> - <source xml:space="preserve">Minimize</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">486</context></context-group> + <context-group purpose="location"><context context-type="linenumber">487</context></context-group> </trans-unit> - <trans-unit id="_msg145"> + <trans-unit id="_msg148"> <source xml:space="preserve">Zoom</source> <target xml:space="preserve"></target> - <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="_msg146"> + <trans-unit id="_msg149"> <source xml:space="preserve">Main Window</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">514</context></context-group> + <context-group purpose="location"><context context-type="linenumber">517</context></context-group> </trans-unit> - <trans-unit id="_msg147"> + <trans-unit id="_msg150"> <source xml:space="preserve">%1 client</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">777</context></context-group> + <context-group purpose="location"><context context-type="linenumber">778</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">935</context></context-group> + <context-group purpose="location"><context context-type="linenumber">936</context></context-group> <note annotates="source" from="developer">A substring of the tooltip.</note> - <trans-unit id="_msg148[0]"> + <trans-unit id="_msg151[0]"> <source xml:space="preserve">%n active connection(s) to Bitcoin network.</source> - <target xml:space="preserve"></target> + <target xml:space="preserve" state="needs-review-translation">%n active connection to Bitcoin network.</target> </trans-unit> - <trans-unit id="_msg148[1]"> + <trans-unit id="_msg151[1]"> <source xml:space="preserve">%n active connection(s) to Bitcoin network.</source> - <target xml:space="preserve"></target> + <target xml:space="preserve" state="needs-review-translation">%n active connections to Bitcoin network.</target> </trans-unit> </group> - <trans-unit id="_msg149"> + <trans-unit id="_msg152"> <source xml:space="preserve">Click for more actions.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">945</context></context-group> + <context-group purpose="location"><context context-type="linenumber">946</context></context-group> <note annotates="source" from="developer">A substring of the tooltip. "More actions" are available via the context menu.</note> </trans-unit> - <trans-unit id="_msg150"> + <trans-unit id="_msg153"> <source xml:space="preserve">Show Peers tab</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">962</context></context-group> + <context-group purpose="location"><context context-type="linenumber">963</context></context-group> <note annotates="source" from="developer">A context menu item. The "Peers tab" is an element of the "Node window".</note> </trans-unit> - <trans-unit id="_msg151"> + <trans-unit id="_msg154"> <source xml:space="preserve">Disable network activity</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">970</context></context-group> + <context-group purpose="location"><context context-type="linenumber">971</context></context-group> <note annotates="source" from="developer">A context menu item.</note> </trans-unit> - <trans-unit id="_msg152"> + <trans-unit id="_msg155"> <source xml:space="preserve">Enable network activity</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">972</context></context-group> + <context-group purpose="location"><context context-type="linenumber">973</context></context-group> <note annotates="source" from="developer">A context menu item. The network activity was disabled previously.</note> </trans-unit> - <trans-unit id="_msg153"> + <trans-unit id="_msg156"> <source xml:space="preserve">Error: %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1129</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1131</context></context-group> </trans-unit> - <trans-unit id="_msg154"> + <trans-unit id="_msg157"> <source xml:space="preserve">Warning: %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1133</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1135</context></context-group> </trans-unit> - <trans-unit id="_msg155"> + <trans-unit id="_msg158"> <source xml:space="preserve">Date: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1241</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1243</context></context-group> </trans-unit> - <trans-unit id="_msg156"> + <trans-unit id="_msg159"> <source xml:space="preserve">Amount: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1242</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1244</context></context-group> </trans-unit> - <trans-unit id="_msg157"> + <trans-unit id="_msg160"> <source xml:space="preserve">Wallet: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1244</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1246</context></context-group> </trans-unit> - <trans-unit id="_msg158"> + <trans-unit id="_msg161"> <source xml:space="preserve">Type: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1246</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1248</context></context-group> </trans-unit> - <trans-unit id="_msg159"> + <trans-unit id="_msg162"> <source xml:space="preserve">Label: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1248</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1250</context></context-group> </trans-unit> - <trans-unit id="_msg160"> + <trans-unit id="_msg163"> <source xml:space="preserve">Address: %1 </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1250</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1252</context></context-group> </trans-unit> - <trans-unit id="_msg161" approved="yes"> + <trans-unit id="_msg164" approved="yes"> <source xml:space="preserve">Sent transaction</source> <target xml:space="preserve">Sent transaction</target> - <context-group purpose="location"><context context-type="linenumber">1251</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1253</context></context-group> </trans-unit> - <trans-unit id="_msg162" approved="yes"> + <trans-unit id="_msg165" approved="yes"> <source xml:space="preserve">Incoming transaction</source> <target xml:space="preserve">Incoming transaction</target> - <context-group purpose="location"><context context-type="linenumber">1251</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1253</context></context-group> </trans-unit> - <trans-unit id="_msg163"> + <trans-unit id="_msg166"> <source xml:space="preserve">HD key generation is <b>enabled</b></source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1303</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1305</context></context-group> </trans-unit> - <trans-unit id="_msg164"> + <trans-unit id="_msg167"> <source xml:space="preserve">HD key generation is <b>disabled</b></source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1303</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1305</context></context-group> </trans-unit> - <trans-unit id="_msg165"> + <trans-unit id="_msg168"> <source xml:space="preserve">Private key <b>disabled</b></source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1303</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1305</context></context-group> </trans-unit> - <trans-unit id="_msg166" approved="yes"> + <trans-unit id="_msg169" approved="yes"> <source xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> <target xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>unlocked</b></target> <context-group purpose="location"><context context-type="linenumber">1322</context></context-group> </trans-unit> - <trans-unit id="_msg167" approved="yes"> + <trans-unit id="_msg170" approved="yes"> <source xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>locked</b></source> <target xml:space="preserve">Wallet is <b>encrypted</b> and currently <b>locked</b></target> <context-group purpose="location"><context context-type="linenumber">1330</context></context-group> </trans-unit> - <trans-unit id="_msg168"> + <trans-unit id="_msg171"> <source xml:space="preserve">Original message:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1450</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1449</context></context-group> </trans-unit> </group> <group restype="x-trolltech-linguist-context" resname="UnitDisplayStatusBarControl"> - <trans-unit id="_msg169"> + <trans-unit id="_msg172"> <source xml:space="preserve">Unit to show amounts in. Click to select another unit.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1491</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1490</context></context-group> </trans-unit> </group> </body></file> <file original="../forms/coincontroldialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CoinControlDialog"> - <trans-unit id="_msg170"> + <trans-unit id="_msg173"> <source xml:space="preserve">Coin Selection</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg171"> + <trans-unit id="_msg174"> <source xml:space="preserve">Quantity:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">48</context></context-group> </trans-unit> - <trans-unit id="_msg172"> + <trans-unit id="_msg175"> <source xml:space="preserve">Bytes:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">77</context></context-group> </trans-unit> - <trans-unit id="_msg173"> + <trans-unit id="_msg176"> <source xml:space="preserve">Amount:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">122</context></context-group> </trans-unit> - <trans-unit id="_msg174"> + <trans-unit id="_msg177"> <source xml:space="preserve">Fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">202</context></context-group> </trans-unit> - <trans-unit id="_msg175"> + <trans-unit id="_msg178"> <source xml:space="preserve">Dust:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">154</context></context-group> </trans-unit> - <trans-unit id="_msg176"> + <trans-unit id="_msg179"> <source xml:space="preserve">After Fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">247</context></context-group> </trans-unit> - <trans-unit id="_msg177"> + <trans-unit id="_msg180"> <source xml:space="preserve">Change:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">279</context></context-group> </trans-unit> - <trans-unit id="_msg178"> + <trans-unit id="_msg181"> <source xml:space="preserve">(un)select all</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> - <trans-unit id="_msg179"> + <trans-unit id="_msg182"> <source xml:space="preserve">Tree mode</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">351</context></context-group> </trans-unit> - <trans-unit id="_msg180"> + <trans-unit id="_msg183"> <source xml:space="preserve">List mode</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">364</context></context-group> </trans-unit> - <trans-unit id="_msg181"> + <trans-unit id="_msg184"> <source xml:space="preserve">Amount</source> <target xml:space="preserve" state="needs-review-translation">Amount</target> <context-group purpose="location"><context context-type="linenumber">420</context></context-group> </trans-unit> - <trans-unit id="_msg182"> + <trans-unit id="_msg185"> <source xml:space="preserve">Received with label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">425</context></context-group> </trans-unit> - <trans-unit id="_msg183"> + <trans-unit id="_msg186"> <source xml:space="preserve">Received with address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">430</context></context-group> </trans-unit> - <trans-unit id="_msg184"> + <trans-unit id="_msg187"> <source xml:space="preserve">Date</source> <target xml:space="preserve" state="needs-review-translation">Date</target> <context-group purpose="location"><context context-type="linenumber">435</context></context-group> </trans-unit> - <trans-unit id="_msg185"> + <trans-unit id="_msg188"> <source xml:space="preserve">Confirmations</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">440</context></context-group> </trans-unit> - <trans-unit id="_msg186"> + <trans-unit id="_msg189"> <source xml:space="preserve">Confirmed</source> <target xml:space="preserve" state="needs-review-translation">Confirmed</target> <context-group purpose="location"><context context-type="linenumber">443</context></context-group> @@ -1008,274 +1027,302 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../coincontroldialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CoinControlDialog"> - <trans-unit id="_msg187"> + <trans-unit id="_msg190"> <source xml:space="preserve">Copy amount</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">66</context></context-group> + <context-group purpose="location"><context context-type="linenumber">69</context></context-group> </trans-unit> - <trans-unit id="_msg188"> + <trans-unit id="_msg191"> <source xml:space="preserve">&Copy address</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">55</context></context-group> + <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg189"> + <trans-unit id="_msg192"> <source xml:space="preserve">Copy &label</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">56</context></context-group> + <context-group purpose="location"><context context-type="linenumber">59</context></context-group> </trans-unit> - <trans-unit id="_msg190"> + <trans-unit id="_msg193"> <source xml:space="preserve">Copy &amount</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">57</context></context-group> + <context-group purpose="location"><context context-type="linenumber">60</context></context-group> </trans-unit> - <trans-unit id="_msg191"> - <source xml:space="preserve">Copy transaction &ID</source> + <trans-unit id="_msg194"> + <source xml:space="preserve">Copy transaction &ID and output index</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">58</context></context-group> + <context-group purpose="location"><context context-type="linenumber">61</context></context-group> </trans-unit> - <trans-unit id="_msg192"> + <trans-unit id="_msg195"> <source xml:space="preserve">L&ock unspent</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">60</context></context-group> + <context-group purpose="location"><context context-type="linenumber">63</context></context-group> </trans-unit> - <trans-unit id="_msg193"> + <trans-unit id="_msg196"> <source xml:space="preserve">&Unlock unspent</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">61</context></context-group> + <context-group purpose="location"><context context-type="linenumber">64</context></context-group> </trans-unit> - <trans-unit id="_msg194"> + <trans-unit id="_msg197"> <source xml:space="preserve">Copy quantity</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">65</context></context-group> + <context-group purpose="location"><context context-type="linenumber">68</context></context-group> </trans-unit> - <trans-unit id="_msg195"> + <trans-unit id="_msg198"> <source xml:space="preserve">Copy fee</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">67</context></context-group> + <context-group purpose="location"><context context-type="linenumber">70</context></context-group> </trans-unit> - <trans-unit id="_msg196"> + <trans-unit id="_msg199"> <source xml:space="preserve">Copy after fee</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">68</context></context-group> + <context-group purpose="location"><context context-type="linenumber">71</context></context-group> </trans-unit> - <trans-unit id="_msg197"> + <trans-unit id="_msg200"> <source xml:space="preserve">Copy bytes</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">69</context></context-group> + <context-group purpose="location"><context context-type="linenumber">72</context></context-group> </trans-unit> - <trans-unit id="_msg198"> + <trans-unit id="_msg201"> <source xml:space="preserve">Copy dust</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">70</context></context-group> + <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> - <trans-unit id="_msg199"> + <trans-unit id="_msg202"> <source xml:space="preserve">Copy change</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">71</context></context-group> + <context-group purpose="location"><context context-type="linenumber">74</context></context-group> </trans-unit> - <trans-unit id="_msg200"> + <trans-unit id="_msg203"> <source xml:space="preserve">(%1 locked)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">373</context></context-group> + <context-group purpose="location"><context context-type="linenumber">380</context></context-group> </trans-unit> - <trans-unit id="_msg201"> + <trans-unit id="_msg204"> <source xml:space="preserve">yes</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">528</context></context-group> + <context-group purpose="location"><context context-type="linenumber">535</context></context-group> </trans-unit> - <trans-unit id="_msg202"> + <trans-unit id="_msg205"> <source xml:space="preserve">no</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">528</context></context-group> + <context-group purpose="location"><context context-type="linenumber">535</context></context-group> </trans-unit> - <trans-unit id="_msg203"> + <trans-unit id="_msg206"> <source xml:space="preserve">This label turns red if any recipient receives an amount smaller than the current dust threshold.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">542</context></context-group> + <context-group purpose="location"><context context-type="linenumber">549</context></context-group> </trans-unit> - <trans-unit id="_msg204"> + <trans-unit id="_msg207"> <source xml:space="preserve">Can vary +/- %1 satoshi(s) per input.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">547</context></context-group> + <context-group purpose="location"><context context-type="linenumber">554</context></context-group> </trans-unit> - <trans-unit id="_msg205"> + <trans-unit id="_msg208"> <source xml:space="preserve">(no label)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">594</context></context-group> - <context-group purpose="location"><context context-type="linenumber">648</context></context-group> + <context-group purpose="location"><context context-type="linenumber">601</context></context-group> + <context-group purpose="location"><context context-type="linenumber">655</context></context-group> </trans-unit> - <trans-unit id="_msg206"> + <trans-unit id="_msg209"> <source xml:space="preserve">change from %1 (%2)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">641</context></context-group> + <context-group purpose="location"><context context-type="linenumber">648</context></context-group> </trans-unit> - <trans-unit id="_msg207"> + <trans-unit id="_msg210"> <source xml:space="preserve">(change)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">642</context></context-group> + <context-group purpose="location"><context context-type="linenumber">649</context></context-group> </trans-unit> </group> </body></file> <file original="../walletcontroller.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CreateWalletActivity"> - <trans-unit id="_msg208"> + <trans-unit id="_msg211"> + <source xml:space="preserve">Create Wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">243</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"> <source xml:space="preserve">Creating Wallet <b>%1</b>…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">254</context></context-group> + <context-group purpose="location"><context context-type="linenumber">246</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="_msg209"> + <trans-unit id="_msg213"> <source xml:space="preserve">Create wallet failed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">285</context></context-group> + <context-group purpose="location"><context context-type="linenumber">275</context></context-group> </trans-unit> - <trans-unit id="_msg210"> + <trans-unit id="_msg214"> <source xml:space="preserve">Create wallet warning</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">287</context></context-group> + <context-group purpose="location"><context context-type="linenumber">277</context></context-group> </trans-unit> - <trans-unit id="_msg211"> + <trans-unit id="_msg215"> <source xml:space="preserve">Can't list signers</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">303</context></context-group> + <context-group purpose="location"><context context-type="linenumber">293</context></context-group> + </trans-unit> + </group> + <group restype="x-trolltech-linguist-context" resname="LoadWalletsActivity"> + <trans-unit id="_msg216"> + <source xml:space="preserve">Load Wallets</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">362</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"> + <source xml:space="preserve">Loading wallets…</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">365</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="_msg212"> + <trans-unit id="_msg218"> <source xml:space="preserve">Open wallet failed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + <context-group purpose="location"><context context-type="linenumber">323</context></context-group> </trans-unit> - <trans-unit id="_msg213"> + <trans-unit id="_msg219"> <source xml:space="preserve">Open wallet warning</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">337</context></context-group> + <context-group purpose="location"><context context-type="linenumber">325</context></context-group> </trans-unit> - <trans-unit id="_msg214"> + <trans-unit id="_msg220"> <source xml:space="preserve">default wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">347</context></context-group> + <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> - <trans-unit id="_msg215"> + <trans-unit id="_msg221"> + <source xml:space="preserve">Open Wallet</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">339</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"> <source xml:space="preserve">Opening Wallet <b>%1</b>…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">349</context></context-group> + <context-group purpose="location"><context context-type="linenumber">342</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="WalletController"> - <trans-unit id="_msg216"> + <trans-unit id="_msg223"> <source xml:space="preserve">Close wallet</source> <target xml:space="preserve"></target> - <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="_msg217"> + <trans-unit id="_msg224"> <source xml:space="preserve">Are you sure you wish to close the wallet <i>%1</i>?</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">88</context></context-group> + <context-group purpose="location"><context context-type="linenumber">84</context></context-group> </trans-unit> - <trans-unit id="_msg218"> + <trans-unit id="_msg225"> <source xml:space="preserve">Closing the wallet for too long can result in having to resync the entire chain if pruning is enabled.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">89</context></context-group> + <context-group purpose="location"><context context-type="linenumber">85</context></context-group> </trans-unit> - <trans-unit id="_msg219"> + <trans-unit id="_msg226"> <source xml:space="preserve">Close all wallets</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">102</context></context-group> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg220"> + <trans-unit id="_msg227"> <source xml:space="preserve">Are you sure you wish to close all wallets?</source> <target xml:space="preserve"></target> - <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> </group> </body></file> <file original="../forms/createwalletdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CreateWalletDialog"> - <trans-unit id="_msg221"> + <trans-unit id="_msg228"> <source xml:space="preserve">Create Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg222"> + <trans-unit id="_msg229"> <source xml:space="preserve">Wallet Name</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">25</context></context-group> </trans-unit> - <trans-unit id="_msg223"> + <trans-unit id="_msg230"> <source xml:space="preserve">Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">38</context></context-group> </trans-unit> - <trans-unit id="_msg224"> + <trans-unit id="_msg231"> <source xml:space="preserve">Encrypt the wallet. The wallet will be encrypted with a passphrase of your choice.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg225"> + <trans-unit id="_msg232"> <source xml:space="preserve">Encrypt Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">50</context></context-group> </trans-unit> - <trans-unit id="_msg226"> + <trans-unit id="_msg233"> <source xml:space="preserve">Advanced Options</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">76</context></context-group> </trans-unit> - <trans-unit id="_msg227"> + <trans-unit id="_msg234"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">85</context></context-group> </trans-unit> - <trans-unit id="_msg228"> + <trans-unit id="_msg235"> <source xml:space="preserve">Disable Private Keys</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">88</context></context-group> </trans-unit> - <trans-unit id="_msg229"> + <trans-unit id="_msg236"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> - <trans-unit id="_msg230"> + <trans-unit id="_msg237"> <source xml:space="preserve">Make Blank Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg231"> + <trans-unit id="_msg238"> <source xml:space="preserve">Use descriptors for scriptPubKey management</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">105</context></context-group> </trans-unit> - <trans-unit id="_msg232"> + <trans-unit id="_msg239"> <source xml:space="preserve">Descriptor Wallet</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">108</context></context-group> </trans-unit> - <trans-unit id="_msg233"> + <trans-unit id="_msg240"> <source xml:space="preserve">Use an external signing device such as a hardware wallet. Configure the external signer script in wallet preferences first.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">115</context></context-group> + <context-group purpose="location"><context context-type="linenumber">118</context></context-group> </trans-unit> - <trans-unit id="_msg234"> + <trans-unit id="_msg241"> <source xml:space="preserve">External signer</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">118</context></context-group> + <context-group purpose="location"><context context-type="linenumber">121</context></context-group> </trans-unit> </group> </body></file> <file original="../createwalletdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="CreateWalletDialog"> - <trans-unit id="_msg235"> + <trans-unit id="_msg242"> <source xml:space="preserve">Create</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">22</context></context-group> </trans-unit> - <trans-unit id="_msg236"> + <trans-unit id="_msg243"> <source xml:space="preserve">Compiled without sqlite support (required for descriptor wallets)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg237"> + <trans-unit id="_msg244"> <source xml:space="preserve">Compiled without external signing support (required for external signing)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">104</context></context-group> @@ -1285,27 +1332,27 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/editaddressdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="EditAddressDialog"> - <trans-unit id="_msg238" approved="yes"> + <trans-unit id="_msg245" approved="yes"> <source xml:space="preserve">Edit Address</source> <target xml:space="preserve">Edit Address</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg239" approved="yes"> + <trans-unit id="_msg246" approved="yes"> <source xml:space="preserve">&Label</source> <target xml:space="preserve">&Label</target> <context-group purpose="location"><context context-type="linenumber">25</context></context-group> </trans-unit> - <trans-unit id="_msg240"> + <trans-unit id="_msg247"> <source xml:space="preserve">The label associated with this address list entry</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">35</context></context-group> </trans-unit> - <trans-unit id="_msg241"> + <trans-unit id="_msg248"> <source xml:space="preserve">The address associated with this address list entry. This can only be modified for sending addresses.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">52</context></context-group> </trans-unit> - <trans-unit id="_msg242" approved="yes"> + <trans-unit id="_msg249" approved="yes"> <source xml:space="preserve">&Address</source> <target xml:space="preserve">&Address</target> <context-group purpose="location"><context context-type="linenumber">42</context></context-group> @@ -1314,42 +1361,42 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../editaddressdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="EditAddressDialog"> - <trans-unit id="_msg243"> + <trans-unit id="_msg250"> <source xml:space="preserve">New sending address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">29</context></context-group> </trans-unit> - <trans-unit id="_msg244"> + <trans-unit id="_msg251"> <source xml:space="preserve">Edit receiving address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">32</context></context-group> </trans-unit> - <trans-unit id="_msg245"> + <trans-unit id="_msg252"> <source xml:space="preserve">Edit sending address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">36</context></context-group> </trans-unit> - <trans-unit id="_msg246"> + <trans-unit id="_msg253"> <source xml:space="preserve">The entered address "%1" is not a valid Bitcoin address.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">113</context></context-group> </trans-unit> - <trans-unit id="_msg247"> + <trans-unit id="_msg254"> <source xml:space="preserve">Address "%1" already exists as a receiving address with label "%2" and so cannot be added as a sending address.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">146</context></context-group> </trans-unit> - <trans-unit id="_msg248"> + <trans-unit id="_msg255"> <source xml:space="preserve">The entered address "%1" is already in the address book with label "%2".</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">151</context></context-group> </trans-unit> - <trans-unit id="_msg249"> + <trans-unit id="_msg256"> <source xml:space="preserve">Could not unlock wallet.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">123</context></context-group> </trans-unit> - <trans-unit id="_msg250"> + <trans-unit id="_msg257"> <source xml:space="preserve">New key generation failed.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">128</context></context-group> @@ -1358,59 +1405,59 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../intro.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="FreespaceChecker"> - <trans-unit id="_msg251" approved="yes"> + <trans-unit id="_msg258" approved="yes"> <source xml:space="preserve">A new data directory will be created.</source> <target xml:space="preserve">A new data directory will be created.</target> <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> - <trans-unit id="_msg252" approved="yes"> + <trans-unit id="_msg259" approved="yes"> <source xml:space="preserve">name</source> <target xml:space="preserve">name</target> <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> - <trans-unit id="_msg253" approved="yes"> + <trans-unit id="_msg260" approved="yes"> <source xml:space="preserve">Directory already exists. Add %1 if you intend to create a new directory here.</source> <target xml:space="preserve">Directory already exists. Add %1 if you intend to create a new directory here.</target> <context-group purpose="location"><context context-type="linenumber">97</context></context-group> </trans-unit> - <trans-unit id="_msg254" approved="yes"> + <trans-unit id="_msg261" approved="yes"> <source xml:space="preserve">Path already exists, and is not a directory.</source> <target xml:space="preserve">Path already exists, and is not a directory.</target> <context-group purpose="location"><context context-type="linenumber">100</context></context-group> </trans-unit> - <trans-unit id="_msg255" approved="yes"> + <trans-unit id="_msg262" approved="yes"> <source xml:space="preserve">Cannot create data directory here.</source> <target xml:space="preserve">Cannot create data directory here.</target> <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="_msg256"> + <trans-unit id="_msg263"> <source xml:space="preserve">Bitcoin</source> <target xml:space="preserve" state="needs-review-translation">Bitcoin</target> <context-group purpose="location"><context context-type="linenumber">139</context></context-group> </trans-unit> - <trans-unit id="_msg257"> + <trans-unit id="_msg264"> <source xml:space="preserve">%1 GB of free space available</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">301</context></context-group> </trans-unit> - <trans-unit id="_msg258"> + <trans-unit id="_msg265"> <source xml:space="preserve">(of %1 GB needed)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">303</context></context-group> </trans-unit> - <trans-unit id="_msg259"> + <trans-unit id="_msg266"> <source xml:space="preserve">(%1 GB needed for full chain)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">306</context></context-group> </trans-unit> - <trans-unit id="_msg260"> + <trans-unit id="_msg267"> <source xml:space="preserve">At least %1 GB of data will be stored in this directory, and it will grow over time.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">378</context></context-group> </trans-unit> - <trans-unit id="_msg261"> + <trans-unit id="_msg268"> <source xml:space="preserve">Approximately %1 GB of data will be stored in this directory.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">381</context></context-group> @@ -1418,31 +1465,31 @@ Signing is only possible with addresses of the type 'legacy'.</source> <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="_msg262[0]"> + <trans-unit id="_msg269[0]"> <source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source> - <target xml:space="preserve"></target> + <target xml:space="preserve" state="needs-review-translation">(sufficient to restore backups %n day old)</target> </trans-unit> - <trans-unit id="_msg262[1]"> + <trans-unit id="_msg269[1]"> <source xml:space="preserve">(sufficient to restore backups %n day(s) old)</source> - <target xml:space="preserve"></target> + <target xml:space="preserve" state="needs-review-translation">(sufficient to restore backups %n days old)</target> </trans-unit> </group> - <trans-unit id="_msg263"> + <trans-unit id="_msg270"> <source xml:space="preserve">%1 will download and store a copy of the Bitcoin block chain.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">392</context></context-group> </trans-unit> - <trans-unit id="_msg264"> + <trans-unit id="_msg271"> <source xml:space="preserve">The wallet will also be stored in this directory.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">394</context></context-group> </trans-unit> - <trans-unit id="_msg265"> + <trans-unit id="_msg272"> <source xml:space="preserve">Error: Specified data directory "%1" cannot be created.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> - <trans-unit id="_msg266" approved="yes"> + <trans-unit id="_msg273" approved="yes"> <source xml:space="preserve">Error</source> <target xml:space="preserve">Error</target> <context-group purpose="location"><context context-type="linenumber">280</context></context-group> @@ -1451,29 +1498,29 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../utilitydialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="HelpMessageDialog"> - <trans-unit id="_msg267"> + <trans-unit id="_msg274"> <source xml:space="preserve">version</source> <target xml:space="preserve" state="needs-review-translation">version</target> <context-group purpose="location"><context context-type="linenumber">37</context></context-group> </trans-unit> - <trans-unit id="_msg268"> + <trans-unit id="_msg275"> <source xml:space="preserve">About %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">41</context></context-group> </trans-unit> - <trans-unit id="_msg269"> + <trans-unit id="_msg276"> <source xml:space="preserve">Command-line options</source> <target xml:space="preserve"></target> <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="_msg270"> + <trans-unit id="_msg277"> <source xml:space="preserve">%1 is shutting down…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">145</context></context-group> </trans-unit> - <trans-unit id="_msg271"> + <trans-unit id="_msg278"> <source xml:space="preserve">Do not shut down the computer until this window disappears.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">146</context></context-group> @@ -1482,57 +1529,57 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/intro.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="Intro"> - <trans-unit id="_msg272" approved="yes"> + <trans-unit id="_msg279" approved="yes"> <source xml:space="preserve">Welcome</source> <target xml:space="preserve">Welcome</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg273"> + <trans-unit id="_msg280"> <source xml:space="preserve">Welcome to %1.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">23</context></context-group> </trans-unit> - <trans-unit id="_msg274"> + <trans-unit id="_msg281"> <source xml:space="preserve">As this is the first time the program is launched, you can choose where %1 will store its data.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> - <trans-unit id="_msg275"> + <trans-unit id="_msg282"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">206</context></context-group> </trans-unit> - <trans-unit id="_msg276"> + <trans-unit id="_msg283"> <source xml:space="preserve">Limit block chain storage to</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">238</context></context-group> </trans-unit> - <trans-unit id="_msg277"> + <trans-unit id="_msg284"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">241</context></context-group> </trans-unit> - <trans-unit id="_msg278"> + <trans-unit id="_msg285"> <source xml:space="preserve"> GB</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">248</context></context-group> </trans-unit> - <trans-unit id="_msg279"> + <trans-unit id="_msg286"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">216</context></context-group> </trans-unit> - <trans-unit id="_msg280"> + <trans-unit id="_msg287"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">226</context></context-group> </trans-unit> - <trans-unit id="_msg281" approved="yes"> + <trans-unit id="_msg288" approved="yes"> <source xml:space="preserve">Use the default data directory</source> <target xml:space="preserve">Use the default data directory</target> <context-group purpose="location"><context context-type="linenumber">66</context></context-group> </trans-unit> - <trans-unit id="_msg282" approved="yes"> + <trans-unit id="_msg289" approved="yes"> <source xml:space="preserve">Use a custom data directory:</source> <target xml:space="preserve">Use a custom data directory:</target> <context-group purpose="location"><context context-type="linenumber">73</context></context-group> @@ -1541,65 +1588,65 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/modaloverlay.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ModalOverlay"> - <trans-unit id="_msg283"> + <trans-unit id="_msg290"> <source xml:space="preserve">Form</source> <target xml:space="preserve" state="needs-review-translation">Form</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg284"> + <trans-unit id="_msg291"> <source xml:space="preserve">Recent transactions may not yet be visible, and therefore your wallet's balance might be incorrect. This information will be correct once your wallet has finished synchronizing with the bitcoin network, as detailed below.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">133</context></context-group> </trans-unit> - <trans-unit id="_msg285"> + <trans-unit id="_msg292"> <source xml:space="preserve">Attempting to spend bitcoins that are affected by not-yet-displayed transactions will not be accepted by the network.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg286"> + <trans-unit id="_msg293"> <source xml:space="preserve">Number of blocks left</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">215</context></context-group> </trans-unit> - <trans-unit id="_msg287"> + <trans-unit id="_msg294"> <source xml:space="preserve">Unknown…</source> <target xml:space="preserve"></target> <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="_msg288"> + <trans-unit id="_msg295"> <source xml:space="preserve">calculating…</source> <target xml:space="preserve"></target> <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="_msg289"> + <trans-unit id="_msg296"> <source xml:space="preserve">Last block time</source> <target xml:space="preserve" state="needs-review-translation">Last block time</target> <context-group purpose="location"><context context-type="linenumber">235</context></context-group> </trans-unit> - <trans-unit id="_msg290"> + <trans-unit id="_msg297"> <source xml:space="preserve">Progress</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">261</context></context-group> </trans-unit> - <trans-unit id="_msg291"> + <trans-unit id="_msg298"> <source xml:space="preserve">Progress increase per hour</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">285</context></context-group> </trans-unit> - <trans-unit id="_msg292"> + <trans-unit id="_msg299"> <source xml:space="preserve">Estimated time left until synced</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">305</context></context-group> </trans-unit> - <trans-unit id="_msg293"> + <trans-unit id="_msg300"> <source xml:space="preserve">Hide</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">342</context></context-group> </trans-unit> - <trans-unit id="_msg294"> + <trans-unit id="_msg301"> <source xml:space="preserve">Esc</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">345</context></context-group> @@ -1608,19 +1655,19 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../modaloverlay.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ModalOverlay"> - <trans-unit id="_msg295"> + <trans-unit id="_msg302"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">34</context></context-group> </trans-unit> - <trans-unit id="_msg296"> + <trans-unit id="_msg303"> <source xml:space="preserve">Unknown. Syncing Headers (%1, %2%)…</source> <target xml:space="preserve"></target> <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="_msg297"> + <trans-unit id="_msg304"> <source xml:space="preserve">unknown</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">123</context></context-group> @@ -1629,509 +1676,575 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../forms/openuridialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="OpenURIDialog"> - <trans-unit id="_msg298"> + <trans-unit id="_msg305"> <source xml:space="preserve">Open bitcoin URI</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg299"> + <trans-unit id="_msg306"> <source xml:space="preserve">URI:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">22</context></context-group> </trans-unit> + <trans-unit id="_msg307"> + <source xml:space="preserve">Paste address from clipboard</source> + <target xml:space="preserve" state="needs-review-translation">Paste address from clipboard</target> + <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> + </trans-unit> </group> </body></file> <file original="../forms/optionsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="OptionsDialog"> - <trans-unit id="_msg300" approved="yes"> + <trans-unit id="_msg308" approved="yes"> <source xml:space="preserve">Options</source> <target xml:space="preserve">Options</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg301" approved="yes"> + <trans-unit id="_msg309" approved="yes"> <source xml:space="preserve">&Main</source> <target xml:space="preserve">&Main</target> <context-group purpose="location"><context context-type="linenumber">27</context></context-group> </trans-unit> - <trans-unit id="_msg302"> + <trans-unit id="_msg310"> <source xml:space="preserve">Automatically start %1 after logging in to the system.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">33</context></context-group> </trans-unit> - <trans-unit id="_msg303"> + <trans-unit id="_msg311"> <source xml:space="preserve">&Start %1 on system login</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">36</context></context-group> </trans-unit> - <trans-unit id="_msg304"> + <trans-unit id="_msg312"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg305"> + <trans-unit id="_msg313"> <source xml:space="preserve">Size of &database cache</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">108</context></context-group> + <context-group purpose="location"><context context-type="linenumber">111</context></context-group> </trans-unit> - <trans-unit id="_msg306"> + <trans-unit id="_msg314"> <source xml:space="preserve">Number of script &verification threads</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">151</context></context-group> + <context-group purpose="location"><context context-type="linenumber">157</context></context-group> </trans-unit> - <trans-unit id="_msg307"> + <trans-unit id="_msg315"> <source xml:space="preserve">IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">352</context></context-group> - <context-group purpose="location"><context context-type="linenumber">539</context></context-group> + <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="_msg308"> + <trans-unit id="_msg316"> <source xml:space="preserve">Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">421</context></context-group> - <context-group purpose="location"><context context-type="linenumber">444</context></context-group> - <context-group purpose="location"><context context-type="linenumber">467</context></context-group> + <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="_msg309"> + <trans-unit id="_msg317"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">636</context></context-group> - </trans-unit> - <trans-unit id="_msg310"> - <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> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">716</context></context-group> - <context-group purpose="location"><context context-type="linenumber">729</context></context-group> + <context-group purpose="location"><context context-type="linenumber">672</context></context-group> </trans-unit> - <trans-unit id="_msg311"> + <trans-unit id="_msg318"> <source xml:space="preserve">Open the %1 configuration file from the working directory.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">908</context></context-group> + <context-group purpose="location"><context context-type="linenumber">944</context></context-group> </trans-unit> - <trans-unit id="_msg312"> + <trans-unit id="_msg319"> <source xml:space="preserve">Open Configuration File</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">911</context></context-group> + <context-group purpose="location"><context context-type="linenumber">947</context></context-group> </trans-unit> - <trans-unit id="_msg313" approved="yes"> + <trans-unit id="_msg320" approved="yes"> <source xml:space="preserve">Reset all client options to default.</source> <target xml:space="preserve">Reset all client options to default.</target> - <context-group purpose="location"><context context-type="linenumber">921</context></context-group> + <context-group purpose="location"><context context-type="linenumber">957</context></context-group> </trans-unit> - <trans-unit id="_msg314" approved="yes"> + <trans-unit id="_msg321" approved="yes"> <source xml:space="preserve">&Reset Options</source> <target xml:space="preserve">&Reset Options</target> - <context-group purpose="location"><context context-type="linenumber">924</context></context-group> + <context-group purpose="location"><context context-type="linenumber">960</context></context-group> </trans-unit> - <trans-unit id="_msg315" approved="yes"> + <trans-unit id="_msg322" approved="yes"> <source xml:space="preserve">&Network</source> <target xml:space="preserve">&Network</target> - <context-group purpose="location"><context context-type="linenumber">279</context></context-group> + <context-group purpose="location"><context context-type="linenumber">315</context></context-group> </trans-unit> - <trans-unit id="_msg316"> + <trans-unit id="_msg323"> <source xml:space="preserve">Prune &block storage to</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">61</context></context-group> </trans-unit> - <trans-unit id="_msg317"> + <trans-unit id="_msg324"> <source xml:space="preserve">GB</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">71</context></context-group> </trans-unit> - <trans-unit id="_msg318"> + <trans-unit id="_msg325"> <source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> - <trans-unit id="_msg319"> + <trans-unit id="_msg326"> + <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> + <target xml:space="preserve"></target> + <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"> <source xml:space="preserve">MiB</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">124</context></context-group> + <context-group purpose="location"><context context-type="linenumber">127</context></context-group> + </trans-unit> + <trans-unit id="_msg328"> + <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> + <target xml:space="preserve"></target> + <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="_msg320"> + <trans-unit id="_msg329"> <source xml:space="preserve">(0 = auto, <0 = leave that many cores free)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">164</context></context-group> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> + </trans-unit> + <trans-unit id="_msg330"> + <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> + <target xml:space="preserve"></target> + <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="_msg321"> + <trans-unit id="_msg331"> + <source xml:space="preserve">Enable R&PC server</source> + <target xml:space="preserve"></target> + <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"> <source xml:space="preserve">W&allet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">200</context></context-group> + <context-group purpose="location"><context context-type="linenumber">216</context></context-group> + </trans-unit> + <trans-unit id="_msg333"> + <source xml:space="preserve">Whether to set subtract fee from amount as default or not.</source> + <target xml:space="preserve"></target> + <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="_msg322"> + <trans-unit id="_msg334"> + <source xml:space="preserve">Subtract &fee from amount by default</source> + <target xml:space="preserve"></target> + <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"> <source xml:space="preserve">Expert</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + <context-group purpose="location"><context context-type="linenumber">232</context></context-group> </trans-unit> - <trans-unit id="_msg323"> + <trans-unit id="_msg336"> <source xml:space="preserve">Enable coin &control features</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">215</context></context-group> + <context-group purpose="location"><context context-type="linenumber">241</context></context-group> </trans-unit> - <trans-unit id="_msg324"> + <trans-unit id="_msg337"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">222</context></context-group> + <context-group purpose="location"><context context-type="linenumber">248</context></context-group> </trans-unit> - <trans-unit id="_msg325"> + <trans-unit id="_msg338"> <source xml:space="preserve">&Spend unconfirmed change</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">225</context></context-group> + <context-group purpose="location"><context context-type="linenumber">251</context></context-group> </trans-unit> - <trans-unit id="_msg326"> + <trans-unit id="_msg339"> + <source xml:space="preserve">Enable &PSBT controls</source> + <target xml:space="preserve"></target> + <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"> + <source xml:space="preserve">Whether to show PSBT controls.</source> + <target xml:space="preserve"></target> + <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"> <source xml:space="preserve">External Signer (e.g. hardware wallet)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">235</context></context-group> + <context-group purpose="location"><context context-type="linenumber">271</context></context-group> </trans-unit> - <trans-unit id="_msg327"> + <trans-unit id="_msg342"> <source xml:space="preserve">&External signer script path</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">243</context></context-group> + <context-group purpose="location"><context context-type="linenumber">279</context></context-group> </trans-unit> - <trans-unit id="_msg328"> + <trans-unit id="_msg343"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">253</context></context-group> + <context-group purpose="location"><context context-type="linenumber">289</context></context-group> </trans-unit> - <trans-unit id="_msg329" approved="yes"> + <trans-unit id="_msg344" approved="yes"> <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> <target xml:space="preserve">Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</target> - <context-group purpose="location"><context context-type="linenumber">285</context></context-group> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> - <trans-unit id="_msg330" approved="yes"> + <trans-unit id="_msg345" approved="yes"> <source xml:space="preserve">Map port using &UPnP</source> <target xml:space="preserve">Map port using &UPnP</target> - <context-group purpose="location"><context context-type="linenumber">288</context></context-group> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> </trans-unit> - <trans-unit id="_msg331"> + <trans-unit id="_msg346"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">295</context></context-group> + <context-group purpose="location"><context context-type="linenumber">331</context></context-group> </trans-unit> - <trans-unit id="_msg332"> + <trans-unit id="_msg347"> <source xml:space="preserve">Map port using NA&T-PMP</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">298</context></context-group> + <context-group purpose="location"><context context-type="linenumber">334</context></context-group> </trans-unit> - <trans-unit id="_msg333"> + <trans-unit id="_msg348"> <source xml:space="preserve">Accept connections from outside.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">305</context></context-group> + <context-group purpose="location"><context context-type="linenumber">341</context></context-group> </trans-unit> - <trans-unit id="_msg334"> + <trans-unit id="_msg349"> <source xml:space="preserve">Allow incomin&g connections</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">308</context></context-group> + <context-group purpose="location"><context context-type="linenumber">344</context></context-group> </trans-unit> - <trans-unit id="_msg335"> + <trans-unit id="_msg350"> <source xml:space="preserve">Connect to the Bitcoin network through a SOCKS5 proxy.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">315</context></context-group> + <context-group purpose="location"><context context-type="linenumber">351</context></context-group> </trans-unit> - <trans-unit id="_msg336"> + <trans-unit id="_msg351"> <source xml:space="preserve">&Connect through SOCKS5 proxy (default proxy):</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">318</context></context-group> + <context-group purpose="location"><context context-type="linenumber">354</context></context-group> </trans-unit> - <trans-unit id="_msg337" approved="yes"> + <trans-unit id="_msg352" approved="yes"> <source xml:space="preserve">Proxy &IP:</source> <target xml:space="preserve">Proxy &IP:</target> - <context-group purpose="location"><context context-type="linenumber">327</context></context-group> - <context-group purpose="location"><context context-type="linenumber">514</context></context-group> + <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="_msg338" approved="yes"> + <trans-unit id="_msg353" approved="yes"> <source xml:space="preserve">&Port:</source> <target xml:space="preserve">&Port:</target> - <context-group purpose="location"><context context-type="linenumber">359</context></context-group> - <context-group purpose="location"><context context-type="linenumber">546</context></context-group> + <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="_msg339" approved="yes"> + <trans-unit id="_msg354" approved="yes"> <source xml:space="preserve">Port of the proxy (e.g. 9050)</source> <target xml:space="preserve">Port of the proxy (e.g. 9050)</target> - <context-group purpose="location"><context context-type="linenumber">384</context></context-group> - <context-group purpose="location"><context context-type="linenumber">571</context></context-group> + <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="_msg340"> + <trans-unit id="_msg355"> <source xml:space="preserve">Used for reaching peers via:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">408</context></context-group> + <context-group purpose="location"><context context-type="linenumber">444</context></context-group> </trans-unit> - <trans-unit id="_msg341"> + <trans-unit id="_msg356"> <source xml:space="preserve">IPv4</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">431</context></context-group> + <context-group purpose="location"><context context-type="linenumber">467</context></context-group> </trans-unit> - <trans-unit id="_msg342"> + <trans-unit id="_msg357"> <source xml:space="preserve">IPv6</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">454</context></context-group> + <context-group purpose="location"><context context-type="linenumber">490</context></context-group> </trans-unit> - <trans-unit id="_msg343"> + <trans-unit id="_msg358"> <source xml:space="preserve">Tor</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">477</context></context-group> + <context-group purpose="location"><context context-type="linenumber">513</context></context-group> </trans-unit> - <trans-unit id="_msg344" approved="yes"> + <trans-unit id="_msg359" approved="yes"> <source xml:space="preserve">&Window</source> <target xml:space="preserve">&Window</target> - <context-group purpose="location"><context context-type="linenumber">607</context></context-group> + <context-group purpose="location"><context context-type="linenumber">643</context></context-group> </trans-unit> - <trans-unit id="_msg345"> + <trans-unit id="_msg360"> <source xml:space="preserve">Show the icon in the system tray.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">613</context></context-group> + <context-group purpose="location"><context context-type="linenumber">649</context></context-group> </trans-unit> - <trans-unit id="_msg346"> + <trans-unit id="_msg361"> <source xml:space="preserve">&Show tray icon</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">616</context></context-group> + <context-group purpose="location"><context context-type="linenumber">652</context></context-group> </trans-unit> - <trans-unit id="_msg347" approved="yes"> + <trans-unit id="_msg362" approved="yes"> <source xml:space="preserve">Show only a tray icon after minimizing the window.</source> <target xml:space="preserve">Show only a tray icon after minimizing the window.</target> - <context-group purpose="location"><context context-type="linenumber">626</context></context-group> + <context-group purpose="location"><context context-type="linenumber">662</context></context-group> </trans-unit> - <trans-unit id="_msg348" approved="yes"> + <trans-unit id="_msg363" approved="yes"> <source xml:space="preserve">&Minimize to the tray instead of the taskbar</source> <target xml:space="preserve">&Minimize to the tray instead of the taskbar</target> - <context-group purpose="location"><context context-type="linenumber">629</context></context-group> + <context-group purpose="location"><context context-type="linenumber">665</context></context-group> </trans-unit> - <trans-unit id="_msg349" approved="yes"> + <trans-unit id="_msg364" approved="yes"> <source xml:space="preserve">M&inimize on close</source> <target xml:space="preserve">M&inimize on close</target> - <context-group purpose="location"><context context-type="linenumber">639</context></context-group> + <context-group purpose="location"><context context-type="linenumber">675</context></context-group> </trans-unit> - <trans-unit id="_msg350" approved="yes"> + <trans-unit id="_msg365" approved="yes"> <source xml:space="preserve">&Display</source> <target xml:space="preserve">&Display</target> - <context-group purpose="location"><context context-type="linenumber">660</context></context-group> + <context-group purpose="location"><context context-type="linenumber">696</context></context-group> </trans-unit> - <trans-unit id="_msg351" approved="yes"> + <trans-unit id="_msg366" approved="yes"> <source xml:space="preserve">User Interface &language:</source> <target xml:space="preserve">User Interface &language:</target> - <context-group purpose="location"><context context-type="linenumber">668</context></context-group> + <context-group purpose="location"><context context-type="linenumber">704</context></context-group> </trans-unit> - <trans-unit id="_msg352"> + <trans-unit id="_msg367"> <source xml:space="preserve">The user interface language can be set here. This setting will take effect after restarting %1.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">681</context></context-group> + <context-group purpose="location"><context context-type="linenumber">717</context></context-group> </trans-unit> - <trans-unit id="_msg353" approved="yes"> + <trans-unit id="_msg368" approved="yes"> <source xml:space="preserve">&Unit to show amounts in:</source> <target xml:space="preserve">&Unit to show amounts in:</target> - <context-group purpose="location"><context context-type="linenumber">692</context></context-group> + <context-group purpose="location"><context context-type="linenumber">728</context></context-group> </trans-unit> - <trans-unit id="_msg354" approved="yes"> + <trans-unit id="_msg369" approved="yes"> <source xml:space="preserve">Choose the default subdivision unit to show in the interface and when sending coins.</source> <target xml:space="preserve">Choose the default subdivision unit to show in the interface and when sending coins.</target> - <context-group purpose="location"><context context-type="linenumber">705</context></context-group> + <context-group purpose="location"><context context-type="linenumber">741</context></context-group> </trans-unit> - <trans-unit id="_msg355"> + <trans-unit id="_msg370"> + <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> + <target xml:space="preserve"></target> + <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"> + <source xml:space="preserve">&Third-party transaction URLs</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">755</context></context-group> + </trans-unit> + <trans-unit id="_msg372"> <source xml:space="preserve">Whether to show coin control features or not.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">212</context></context-group> + <context-group purpose="location"><context context-type="linenumber">238</context></context-group> </trans-unit> - <trans-unit id="_msg356"> + <trans-unit id="_msg373"> <source xml:space="preserve">Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor onion services.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">502</context></context-group> + <context-group purpose="location"><context context-type="linenumber">538</context></context-group> </trans-unit> - <trans-unit id="_msg357"> + <trans-unit id="_msg374"> <source xml:space="preserve">Use separate SOCKS&5 proxy to reach peers via Tor onion services:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">505</context></context-group> - </trans-unit> - <trans-unit id="_msg358"> - <source xml:space="preserve">&Third party transaction URLs</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">719</context></context-group> + <context-group purpose="location"><context context-type="linenumber">541</context></context-group> </trans-unit> - <trans-unit id="_msg359"> + <trans-unit id="_msg375"> <source xml:space="preserve">Monospaced font in the Overview tab:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">741</context></context-group> + <context-group purpose="location"><context context-type="linenumber">777</context></context-group> </trans-unit> - <trans-unit id="_msg360"> + <trans-unit id="_msg376"> <source xml:space="preserve">embedded "%1"</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">749</context></context-group> + <context-group purpose="location"><context context-type="linenumber">785</context></context-group> </trans-unit> - <trans-unit id="_msg361"> + <trans-unit id="_msg377"> <source xml:space="preserve">closest matching "%1"</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">798</context></context-group> + <context-group purpose="location"><context context-type="linenumber">834</context></context-group> </trans-unit> - <trans-unit id="_msg362"> + <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">863</context></context-group> + <context-group purpose="location"><context context-type="linenumber">899</context></context-group> </trans-unit> - <trans-unit id="_msg363" approved="yes"> + <trans-unit id="_msg379" approved="yes"> <source xml:space="preserve">&OK</source> <target xml:space="preserve">&OK</target> - <context-group purpose="location"><context context-type="linenumber">1004</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1040</context></context-group> </trans-unit> - <trans-unit id="_msg364" approved="yes"> + <trans-unit id="_msg380" approved="yes"> <source xml:space="preserve">&Cancel</source> <target xml:space="preserve">&Cancel</target> - <context-group purpose="location"><context context-type="linenumber">1017</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1053</context></context-group> </trans-unit> </group> </body></file> <file original="../optionsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="OptionsDialog"> - <trans-unit id="_msg365"> + <trans-unit id="_msg381"> <source xml:space="preserve">Compiled without external signing support (required for external signing)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">97</context></context-group> + <context-group purpose="location"><context context-type="linenumber">99</context></context-group> <note annotates="source" from="developer">"External signing" means using devices such as hardware wallets.</note> </trans-unit> - <trans-unit id="_msg366" approved="yes"> + <trans-unit id="_msg382" approved="yes"> <source xml:space="preserve">default</source> <target xml:space="preserve">default</target> - <context-group purpose="location"><context context-type="linenumber">109</context></context-group> + <context-group purpose="location"><context context-type="linenumber">111</context></context-group> </trans-unit> - <trans-unit id="_msg367"> + <trans-unit id="_msg383"> <source xml:space="preserve">none</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">190</context></context-group> + <context-group purpose="location"><context context-type="linenumber">192</context></context-group> </trans-unit> - <trans-unit id="_msg368" approved="yes"> + <trans-unit id="_msg384" approved="yes"> <source xml:space="preserve">Confirm options reset</source> <target xml:space="preserve">Confirm options reset</target> - <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="_msg369"> + <trans-unit id="_msg385"> <source xml:space="preserve">Client restart required to activate changes.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">284</context></context-group> - <context-group purpose="location"><context context-type="linenumber">341</context></context-group> + <context-group purpose="location"><context context-type="linenumber">290</context></context-group> + <context-group purpose="location"><context context-type="linenumber">360</context></context-group> </trans-unit> - <trans-unit id="_msg370"> + <trans-unit id="_msg386"> <source xml:space="preserve">Client will be shut down. Do you want to proceed?</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">284</context></context-group> + <context-group purpose="location"><context context-type="linenumber">290</context></context-group> </trans-unit> - <trans-unit id="_msg371"> + <trans-unit id="_msg387"> <source xml:space="preserve">Configuration options</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">299</context></context-group> + <context-group purpose="location"><context context-type="linenumber">308</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="_msg372"> + <trans-unit id="_msg388"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">300</context></context-group> + <context-group purpose="location"><context context-type="linenumber">311</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="_msg373"> + <trans-unit id="_msg389"> + <source xml:space="preserve">Continue</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">314</context></context-group> + </trans-unit> + <trans-unit id="_msg390"> + <source xml:space="preserve">Cancel</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">315</context></context-group> + </trans-unit> + <trans-unit id="_msg391"> <source xml:space="preserve">Error</source> <target xml:space="preserve" state="needs-review-translation">Error</target> - <context-group purpose="location"><context context-type="linenumber">305</context></context-group> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> </trans-unit> - <trans-unit id="_msg374"> + <trans-unit id="_msg392"> <source xml:space="preserve">The configuration file could not be opened.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">305</context></context-group> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> </trans-unit> - <trans-unit id="_msg375"> + <trans-unit id="_msg393"> <source xml:space="preserve">This change would require a client restart.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">345</context></context-group> + <context-group purpose="location"><context context-type="linenumber">364</context></context-group> </trans-unit> - <trans-unit id="_msg376" approved="yes"> + <trans-unit id="_msg394" approved="yes"> <source xml:space="preserve">The supplied proxy address is invalid.</source> <target xml:space="preserve">The supplied proxy address is invalid.</target> - <context-group purpose="location"><context context-type="linenumber">373</context></context-group> + <context-group purpose="location"><context context-type="linenumber">392</context></context-group> </trans-unit> </group> </body></file> <file original="../forms/overviewpage.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="OverviewPage"> - <trans-unit id="_msg377" approved="yes"> + <trans-unit id="_msg395" approved="yes"> <source xml:space="preserve">Form</source> <target xml:space="preserve">Form</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg378" approved="yes"> + <trans-unit id="_msg396" approved="yes"> <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> <target 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.</target> <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="_msg379"> + <trans-unit id="_msg397"> <source xml:space="preserve">Watch-only:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">284</context></context-group> </trans-unit> - <trans-unit id="_msg380"> + <trans-unit id="_msg398"> <source xml:space="preserve">Available:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">294</context></context-group> </trans-unit> - <trans-unit id="_msg381" approved="yes"> + <trans-unit id="_msg399" approved="yes"> <source xml:space="preserve">Your current spendable balance</source> <target xml:space="preserve">Your current spendable balance</target> <context-group purpose="location"><context context-type="linenumber">304</context></context-group> </trans-unit> - <trans-unit id="_msg382"> + <trans-unit id="_msg400"> <source xml:space="preserve">Pending:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">339</context></context-group> </trans-unit> - <trans-unit id="_msg383" approved="yes"> + <trans-unit id="_msg401" approved="yes"> <source xml:space="preserve">Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> <target xml:space="preserve">Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</target> <context-group purpose="location"><context context-type="linenumber">139</context></context-group> </trans-unit> - <trans-unit id="_msg384" approved="yes"> + <trans-unit id="_msg402" approved="yes"> <source xml:space="preserve">Immature:</source> <target xml:space="preserve">Immature:</target> <context-group purpose="location"><context context-type="linenumber">239</context></context-group> </trans-unit> - <trans-unit id="_msg385" approved="yes"> + <trans-unit id="_msg403" approved="yes"> <source xml:space="preserve">Mined balance that has not yet matured</source> <target xml:space="preserve">Mined balance that has not yet matured</target> <context-group purpose="location"><context context-type="linenumber">210</context></context-group> </trans-unit> - <trans-unit id="_msg386"> + <trans-unit id="_msg404"> <source xml:space="preserve">Balances</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">60</context></context-group> </trans-unit> - <trans-unit id="_msg387" approved="yes"> + <trans-unit id="_msg405" approved="yes"> <source xml:space="preserve">Total:</source> <target xml:space="preserve">Total:</target> <context-group purpose="location"><context context-type="linenumber">200</context></context-group> </trans-unit> - <trans-unit id="_msg388" approved="yes"> + <trans-unit id="_msg406" approved="yes"> <source xml:space="preserve">Your current total balance</source> <target xml:space="preserve">Your current total balance</target> <context-group purpose="location"><context context-type="linenumber">249</context></context-group> </trans-unit> - <trans-unit id="_msg389"> + <trans-unit id="_msg407"> <source xml:space="preserve">Your current balance in watch-only addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">323</context></context-group> </trans-unit> - <trans-unit id="_msg390"> + <trans-unit id="_msg408"> <source xml:space="preserve">Spendable:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">346</context></context-group> </trans-unit> - <trans-unit id="_msg391"> + <trans-unit id="_msg409"> <source xml:space="preserve">Recent transactions</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">395</context></context-group> </trans-unit> - <trans-unit id="_msg392"> + <trans-unit id="_msg410"> <source xml:space="preserve">Unconfirmed transactions to watch-only addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg393"> + <trans-unit id="_msg411"> <source xml:space="preserve">Mined balance in watch-only addresses that has not yet matured</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">158</context></context-group> </trans-unit> - <trans-unit id="_msg394"> + <trans-unit id="_msg412"> <source xml:space="preserve">Current total balance in watch-only addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">268</context></context-group> @@ -2140,41 +2253,41 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../overviewpage.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="OverviewPage"> - <trans-unit id="_msg395"> + <trans-unit id="_msg413"> <source xml:space="preserve">Privacy mode activated for the Overview tab. To unmask the values, uncheck Settings->Mask values.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">188</context></context-group> + <context-group purpose="location"><context context-type="linenumber">187</context></context-group> </trans-unit> </group> </body></file> <file original="../forms/psbtoperationsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog"> - <trans-unit id="_msg396"> + <trans-unit id="_msg414"> <source xml:space="preserve">Dialog</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg397"> + <trans-unit id="_msg415"> <source xml:space="preserve">Sign Tx</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">86</context></context-group> </trans-unit> - <trans-unit id="_msg398"> + <trans-unit id="_msg416"> <source xml:space="preserve">Broadcast Tx</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">102</context></context-group> </trans-unit> - <trans-unit id="_msg399"> + <trans-unit id="_msg417"> <source xml:space="preserve">Copy to Clipboard</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">122</context></context-group> </trans-unit> - <trans-unit id="_msg400"> + <trans-unit id="_msg418"> <source xml:space="preserve">Save…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">129</context></context-group> </trans-unit> - <trans-unit id="_msg401"> + <trans-unit id="_msg419"> <source xml:space="preserve">Close</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">136</context></context-group> @@ -2183,142 +2296,152 @@ Signing is only possible with addresses of the type 'legacy'.</source> </body></file> <file original="../psbtoperationsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="PSBTOperationsDialog"> - <trans-unit id="_msg402"> + <trans-unit id="_msg420"> <source xml:space="preserve">Failed to load transaction: %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">55</context></context-group> + <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg403"> + <trans-unit id="_msg421"> <source xml:space="preserve">Failed to sign transaction: %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">73</context></context-group> + <context-group purpose="location"><context context-type="linenumber">83</context></context-group> </trans-unit> - <trans-unit id="_msg404"> + <trans-unit id="_msg422"> + <source xml:space="preserve">Cannot sign inputs while wallet is locked.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + </trans-unit> + <trans-unit id="_msg423"> <source xml:space="preserve">Could not sign any more inputs.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">81</context></context-group> + <context-group purpose="location"><context context-type="linenumber">93</context></context-group> </trans-unit> - <trans-unit id="_msg405"> + <trans-unit id="_msg424"> <source xml:space="preserve">Signed %1 inputs, but more signatures are still required.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">83</context></context-group> + <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> - <trans-unit id="_msg406"> + <trans-unit id="_msg425"> <source xml:space="preserve">Signed transaction successfully. Transaction is ready to broadcast.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">86</context></context-group> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg407"> + <trans-unit id="_msg426"> <source xml:space="preserve">Unknown error processing transaction.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + <context-group purpose="location"><context context-type="linenumber">110</context></context-group> </trans-unit> - <trans-unit id="_msg408"> + <trans-unit id="_msg427"> <source xml:space="preserve">Transaction broadcast successfully! Transaction ID: %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">108</context></context-group> + <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg409"> + <trans-unit id="_msg428"> <source xml:space="preserve">Transaction broadcast failed: %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">111</context></context-group> + <context-group purpose="location"><context context-type="linenumber">123</context></context-group> </trans-unit> - <trans-unit id="_msg410"> + <trans-unit id="_msg429"> <source xml:space="preserve">PSBT copied to clipboard.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + <context-group purpose="location"><context context-type="linenumber">132</context></context-group> </trans-unit> - <trans-unit id="_msg411"> + <trans-unit id="_msg430"> <source xml:space="preserve">Save Transaction Data</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">143</context></context-group> + <context-group purpose="location"><context context-type="linenumber">155</context></context-group> </trans-unit> - <trans-unit id="_msg412"> + <trans-unit id="_msg431"> <source xml:space="preserve">Partially Signed Transaction (Binary)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">145</context></context-group> + <context-group purpose="location"><context context-type="linenumber">157</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="_msg413"> + <trans-unit id="_msg432"> <source xml:space="preserve">PSBT saved to disk.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">152</context></context-group> + <context-group purpose="location"><context context-type="linenumber">164</context></context-group> </trans-unit> - <trans-unit id="_msg414"> + <trans-unit id="_msg433"> <source xml:space="preserve"> * Sends %1 to %2</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">168</context></context-group> + <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg415"> + <trans-unit id="_msg434"> <source xml:space="preserve">Unable to calculate transaction fee or total transaction amount.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">178</context></context-group> + <context-group purpose="location"><context context-type="linenumber">190</context></context-group> </trans-unit> - <trans-unit id="_msg416"> + <trans-unit id="_msg435"> <source xml:space="preserve">Pays transaction fee: </source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">180</context></context-group> + <context-group purpose="location"><context context-type="linenumber">192</context></context-group> </trans-unit> - <trans-unit id="_msg417"> + <trans-unit id="_msg436"> <source xml:space="preserve">Total Amount</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">192</context></context-group> + <context-group purpose="location"><context context-type="linenumber">204</context></context-group> </trans-unit> - <trans-unit id="_msg418"> + <trans-unit id="_msg437"> <source xml:space="preserve">or</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">195</context></context-group> + <context-group purpose="location"><context context-type="linenumber">207</context></context-group> </trans-unit> - <trans-unit id="_msg419"> + <trans-unit id="_msg438"> <source xml:space="preserve">Transaction has %1 unsigned inputs.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">201</context></context-group> + <context-group purpose="location"><context context-type="linenumber">213</context></context-group> </trans-unit> - <trans-unit id="_msg420"> + <trans-unit id="_msg439"> <source xml:space="preserve">Transaction is missing some information about inputs.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">243</context></context-group> + <context-group purpose="location"><context context-type="linenumber">259</context></context-group> </trans-unit> - <trans-unit id="_msg421"> + <trans-unit id="_msg440"> <source xml:space="preserve">Transaction still needs signature(s).</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">247</context></context-group> + <context-group purpose="location"><context context-type="linenumber">263</context></context-group> </trans-unit> - <trans-unit id="_msg422"> + <trans-unit id="_msg441"> + <source xml:space="preserve">(But no wallet is loaded.)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">266</context></context-group> + </trans-unit> + <trans-unit id="_msg442"> <source xml:space="preserve">(But this wallet cannot sign transactions.)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">250</context></context-group> + <context-group purpose="location"><context context-type="linenumber">269</context></context-group> </trans-unit> - <trans-unit id="_msg423"> + <trans-unit id="_msg443"> <source xml:space="preserve">(But this wallet does not have the right keys.)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">253</context></context-group> + <context-group purpose="location"><context context-type="linenumber">272</context></context-group> </trans-unit> - <trans-unit id="_msg424"> + <trans-unit id="_msg444"> <source xml:space="preserve">Transaction is fully signed and ready for broadcast.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">261</context></context-group> + <context-group purpose="location"><context context-type="linenumber">280</context></context-group> </trans-unit> - <trans-unit id="_msg425"> + <trans-unit id="_msg445"> <source xml:space="preserve">Transaction status is unknown.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">265</context></context-group> + <context-group purpose="location"><context context-type="linenumber">284</context></context-group> </trans-unit> </group> </body></file> <file original="../paymentserver.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="PaymentServer"> - <trans-unit id="_msg426"> + <trans-unit id="_msg446"> <source xml:space="preserve">Payment request error</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">173</context></context-group> </trans-unit> - <trans-unit id="_msg427"> + <trans-unit id="_msg447"> <source xml:space="preserve">Cannot start bitcoin: click-to-pay handler</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">174</context></context-group> </trans-unit> - <trans-unit id="_msg428"> + <trans-unit id="_msg448"> <source xml:space="preserve">URI handling</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">224</context></context-group> @@ -2326,12 +2449,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context-group purpose="location"><context context-type="linenumber">246</context></context-group> <context-group purpose="location"><context context-type="linenumber">253</context></context-group> </trans-unit> - <trans-unit id="_msg429"> + <trans-unit id="_msg449"> <source xml:space="preserve">'bitcoin://' is not a valid URI. Use 'bitcoin:' instead.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">224</context></context-group> </trans-unit> - <trans-unit id="_msg430"> + <trans-unit id="_msg450"> <source xml:space="preserve">Cannot process payment request because BIP70 is not supported. Due to widespread security flaws in BIP70 it'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> @@ -2339,12 +2462,12 @@ If you are receiving this error you should request the merchant provide a BIP21 <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="_msg431"> + <trans-unit id="_msg451"> <source xml:space="preserve">URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">254</context></context-group> </trans-unit> - <trans-unit id="_msg432"> + <trans-unit id="_msg452"> <source xml:space="preserve">Payment request file handling</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">263</context></context-group> @@ -2353,290 +2476,319 @@ If you are receiving this error you should request the merchant provide a BIP21 </body></file> <file original="../peertablemodel.h" datatype="c" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="PeerTableModel"> - <trans-unit id="_msg433"> + <trans-unit id="_msg453"> <source xml:space="preserve">User Agent</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">107</context></context-group> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> <note annotates="source" from="developer">Title of Peers Table column which contains the peer's User Agent string.</note> </trans-unit> - <trans-unit id="_msg434"> + <trans-unit id="_msg454"> <source xml:space="preserve">Ping</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + <context-group purpose="location"><context context-type="linenumber">99</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="_msg435"> + <trans-unit id="_msg455"> <source xml:space="preserve">Peer</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">86</context></context-group> + <context-group purpose="location"><context context-type="linenumber">84</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="_msg436"> + <trans-unit id="_msg456"> + <source xml:space="preserve">Direction</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">90</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"> <source xml:space="preserve">Sent</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">101</context></context-group> + <context-group purpose="location"><context context-type="linenumber">102</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="_msg437"> + <trans-unit id="_msg458"> <source xml:space="preserve">Received</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">104</context></context-group> + <context-group purpose="location"><context context-type="linenumber">105</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="_msg438"> + <trans-unit id="_msg459"> <source xml:space="preserve">Address</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">89</context></context-group> + <context-group purpose="location"><context context-type="linenumber">87</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="_msg439"> + <trans-unit id="_msg460"> <source xml:space="preserve">Type</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">92</context></context-group> + <context-group purpose="location"><context context-type="linenumber">93</context></context-group> <note annotates="source" from="developer">Title of Peers Table column which describes the type of peer connection. The "type" describes why the connection exists.</note> </trans-unit> - <trans-unit id="_msg440"> + <trans-unit id="_msg461"> <source xml:space="preserve">Network</source> <target xml:space="preserve" state="needs-review-translation">Network</target> - <context-group purpose="location"><context context-type="linenumber">95</context></context-group> + <context-group purpose="location"><context context-type="linenumber">96</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" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="PeerTableModel"> + <trans-unit id="_msg462"> + <source xml:space="preserve">Inbound</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">79</context></context-group> + <note annotates="source" from="developer">An Inbound Connection from a Peer.</note> + </trans-unit> + <trans-unit id="_msg463"> + <source xml:space="preserve">Outbound</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">81</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" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="QObject"> - <trans-unit id="_msg441"> + <trans-unit id="_msg464"> <source xml:space="preserve">Amount</source> <target xml:space="preserve" state="needs-review-translation">Amount</target> - <context-group purpose="location"><context context-type="linenumber">213</context></context-group> + <context-group purpose="location"><context context-type="linenumber">215</context></context-group> </trans-unit> </group> </body></file> <file original="../guiutil.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="QObject"> - <trans-unit id="_msg442"> + <trans-unit id="_msg465"> <source xml:space="preserve">Enter a Bitcoin address (e.g. %1)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + <context-group purpose="location"><context context-type="linenumber">122</context></context-group> </trans-unit> - <trans-unit id="_msg443"> + <trans-unit id="_msg466"> <source xml:space="preserve">Unroutable</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">660</context></context-group> + <context-group purpose="location"><context context-type="linenumber">668</context></context-group> </trans-unit> - <trans-unit id="_msg444"> + <trans-unit id="_msg467"> <source xml:space="preserve">Internal</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">666</context></context-group> + <context-group purpose="location"><context context-type="linenumber">674</context></context-group> </trans-unit> - <trans-unit id="_msg445"> + <trans-unit id="_msg468"> <source xml:space="preserve">Inbound</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">676</context></context-group> + <context-group purpose="location"><context context-type="linenumber">687</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="_msg446"> + <trans-unit id="_msg469"> <source xml:space="preserve">Outbound</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">676</context></context-group> + <context-group purpose="location"><context context-type="linenumber">690</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="_msg447"> + <trans-unit id="_msg470"> <source xml:space="preserve">Full Relay</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">680</context></context-group> + <context-group purpose="location"><context context-type="linenumber">695</context></context-group> + <note annotates="source" from="developer">Peer connection type that relays all network information.</note> </trans-unit> - <trans-unit id="_msg448"> + <trans-unit id="_msg471"> <source xml:space="preserve">Block Relay</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">681</context></context-group> + <context-group purpose="location"><context context-type="linenumber">698</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="_msg449"> + <trans-unit id="_msg472"> <source xml:space="preserve">Manual</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">682</context></context-group> + <context-group purpose="location"><context context-type="linenumber">700</context></context-group> + <note annotates="source" from="developer">Peer connection type established manually through one of several methods.</note> </trans-unit> - <trans-unit id="_msg450"> + <trans-unit id="_msg473"> <source xml:space="preserve">Feeler</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">683</context></context-group> + <context-group purpose="location"><context context-type="linenumber">702</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="_msg451"> + <trans-unit id="_msg474"> <source xml:space="preserve">Address Fetch</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">684</context></context-group> + <context-group purpose="location"><context context-type="linenumber">704</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="_msg452"> + <trans-unit id="_msg475"> <source xml:space="preserve">%1 d</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">698</context></context-group> + <context-group purpose="location"><context context-type="linenumber">719</context></context-group> </trans-unit> - <trans-unit id="_msg453"> + <trans-unit id="_msg476"> <source xml:space="preserve">%1 h</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">700</context></context-group> + <context-group purpose="location"><context context-type="linenumber">721</context></context-group> </trans-unit> - <trans-unit id="_msg454"> + <trans-unit id="_msg477"> <source xml:space="preserve">%1 m</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">702</context></context-group> + <context-group purpose="location"><context context-type="linenumber">723</context></context-group> </trans-unit> - <trans-unit id="_msg455"> + <trans-unit id="_msg478"> <source xml:space="preserve">%1 s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">704</context></context-group> - <context-group purpose="location"><context context-type="linenumber">732</context></context-group> + <context-group purpose="location"><context context-type="linenumber">725</context></context-group> + <context-group purpose="location"><context context-type="linenumber">753</context></context-group> </trans-unit> - <trans-unit id="_msg456"> + <trans-unit id="_msg479"> <source xml:space="preserve">None</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">720</context></context-group> + <context-group purpose="location"><context context-type="linenumber">741</context></context-group> </trans-unit> - <trans-unit id="_msg457"> + <trans-unit id="_msg480"> <source xml:space="preserve">N/A</source> <target xml:space="preserve" state="needs-review-translation">N/A</target> - <context-group purpose="location"><context context-type="linenumber">726</context></context-group> + <context-group purpose="location"><context context-type="linenumber">747</context></context-group> </trans-unit> - <trans-unit id="_msg458"> + <trans-unit id="_msg481"> <source xml:space="preserve">%1 ms</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">727</context></context-group> + <context-group purpose="location"><context context-type="linenumber">748</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">745</context></context-group> - <trans-unit id="_msg459[0]" approved="yes"> + <context-group purpose="location"><context context-type="linenumber">766</context></context-group> + <trans-unit id="_msg482[0]" approved="yes"> <source xml:space="preserve">%n second(s)</source> <target xml:space="preserve">%n second</target> </trans-unit> - <trans-unit id="_msg459[1]" approved="yes"> + <trans-unit id="_msg482[1]" approved="yes"> <source xml:space="preserve">%n second(s)</source> <target xml:space="preserve">%n seconds</target> </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">749</context></context-group> - <trans-unit id="_msg460[0]" approved="yes"> + <context-group purpose="location"><context context-type="linenumber">770</context></context-group> + <trans-unit id="_msg483[0]" approved="yes"> <source xml:space="preserve">%n minute(s)</source> <target xml:space="preserve">%n minute</target> </trans-unit> - <trans-unit id="_msg460[1]" approved="yes"> + <trans-unit id="_msg483[1]" approved="yes"> <source xml:space="preserve">%n minute(s)</source> <target xml:space="preserve">%n minutes</target> </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">753</context></context-group> - <trans-unit id="_msg461[0]"> + <context-group purpose="location"><context context-type="linenumber">774</context></context-group> + <trans-unit id="_msg484[0]"> <source xml:space="preserve">%n hour(s)</source> <target xml:space="preserve" state="needs-review-translation">%n hour</target> </trans-unit> - <trans-unit id="_msg461[1]"> + <trans-unit id="_msg484[1]"> <source xml:space="preserve">%n hour(s)</source> <target xml:space="preserve" state="needs-review-translation">%n hours</target> </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">757</context></context-group> - <trans-unit id="_msg462[0]"> + <context-group purpose="location"><context context-type="linenumber">778</context></context-group> + <trans-unit id="_msg485[0]"> <source xml:space="preserve">%n day(s)</source> <target xml:space="preserve" state="needs-review-translation">%n day</target> </trans-unit> - <trans-unit id="_msg462[1]"> + <trans-unit id="_msg485[1]"> <source xml:space="preserve">%n day(s)</source> <target xml:space="preserve" state="needs-review-translation">%n days</target> </trans-unit> </group> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">761</context></context-group> - <context-group purpose="location"><context context-type="linenumber">767</context></context-group> - <trans-unit id="_msg463[0]"> + <context-group purpose="location"><context context-type="linenumber">782</context></context-group> + <context-group purpose="location"><context context-type="linenumber">788</context></context-group> + <trans-unit id="_msg486[0]"> <source xml:space="preserve">%n week(s)</source> <target xml:space="preserve" state="needs-review-translation">%n week</target> </trans-unit> - <trans-unit id="_msg463[1]"> + <trans-unit id="_msg486[1]"> <source xml:space="preserve">%n week(s)</source> <target xml:space="preserve" state="needs-review-translation">%n weeks</target> </trans-unit> </group> - <trans-unit id="_msg464"> + <trans-unit id="_msg487"> <source xml:space="preserve">%1 and %2</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">767</context></context-group> + <context-group purpose="location"><context context-type="linenumber">788</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">767</context></context-group> - <trans-unit id="_msg465[0]"> + <context-group purpose="location"><context context-type="linenumber">788</context></context-group> + <trans-unit id="_msg488[0]"> <source xml:space="preserve">%n year(s)</source> <target xml:space="preserve" state="needs-review-translation">%n year</target> </trans-unit> - <trans-unit id="_msg465[1]"> + <trans-unit id="_msg488[1]"> <source xml:space="preserve">%n year(s)</source> <target xml:space="preserve" state="needs-review-translation">%n years</target> </trans-unit> </group> - <trans-unit id="_msg466"> + <trans-unit id="_msg489"> <source xml:space="preserve">%1 B</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">775</context></context-group> + <context-group purpose="location"><context context-type="linenumber">796</context></context-group> </trans-unit> - <trans-unit id="_msg467"> + <trans-unit id="_msg490"> <source xml:space="preserve">%1 kB</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">777</context></context-group> + <context-group purpose="location"><context context-type="linenumber">798</context></context-group> </trans-unit> - <trans-unit id="_msg468"> + <trans-unit id="_msg491"> <source xml:space="preserve">%1 MB</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">779</context></context-group> + <context-group purpose="location"><context context-type="linenumber">800</context></context-group> </trans-unit> - <trans-unit id="_msg469"> + <trans-unit id="_msg492"> <source xml:space="preserve">%1 GB</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">781</context></context-group> + <context-group purpose="location"><context context-type="linenumber">802</context></context-group> </trans-unit> </group> </body></file> <file original="../qrimagewidget.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="QRImageWidget"> - <trans-unit id="_msg470"> + <trans-unit id="_msg493"> <source xml:space="preserve">&Save Image…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">30</context></context-group> </trans-unit> - <trans-unit id="_msg471"> + <trans-unit id="_msg494"> <source xml:space="preserve">&Copy Image</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">31</context></context-group> </trans-unit> - <trans-unit id="_msg472"> + <trans-unit id="_msg495"> <source xml:space="preserve">Resulting URI too long, try to reduce the text for label / message.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">42</context></context-group> </trans-unit> - <trans-unit id="_msg473"> + <trans-unit id="_msg496"> <source xml:space="preserve">Error encoding URI into QR Code.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> - <trans-unit id="_msg474"> + <trans-unit id="_msg497"> <source xml:space="preserve">QR code support not available.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg475"> + <trans-unit id="_msg498"> <source xml:space="preserve">Save QR Code</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg476"> + <trans-unit id="_msg499"> <source xml:space="preserve">PNG Image</source> <target xml:space="preserve"></target> <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> + <note annotates="source" from="developer">Expanded name of the PNG file format. See: https://en.wikipedia.org/wiki/Portable_Network_Graphics.</note> </trans-unit> </group> </body></file> <file original="../forms/debugwindow.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RPCConsole"> - <trans-unit id="_msg477" approved="yes"> + <trans-unit id="_msg500" approved="yes"> <source xml:space="preserve">N/A</source> <target xml:space="preserve">N/A</target> <context-group purpose="location"><context context-type="linenumber">75</context></context-group> @@ -2673,324 +2825,361 @@ If you are receiving this error you should request the merchant provide a BIP21 <context-group purpose="location"><context context-type="linenumber">1535</context></context-group> <context-group purpose="location"><context context-type="linenumber">1558</context></context-group> <context-group purpose="location"><context context-type="linenumber">1584</context></context-group> + <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> </trans-unit> - <trans-unit id="_msg478" approved="yes"> + <trans-unit id="_msg501" approved="yes"> <source xml:space="preserve">Client version</source> <target xml:space="preserve">Client version</target> <context-group purpose="location"><context context-type="linenumber">65</context></context-group> </trans-unit> - <trans-unit id="_msg479" approved="yes"> + <trans-unit id="_msg502" approved="yes"> <source xml:space="preserve">&Information</source> <target xml:space="preserve">&Information</target> <context-group purpose="location"><context context-type="linenumber">43</context></context-group> </trans-unit> - <trans-unit id="_msg480"> + <trans-unit id="_msg503"> <source xml:space="preserve">General</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg481"> + <trans-unit id="_msg504"> <source xml:space="preserve">Datadir</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">114</context></context-group> </trans-unit> - <trans-unit id="_msg482"> + <trans-unit id="_msg505"> <source xml:space="preserve">To specify a non-default location of the data directory use the '%1' option.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">124</context></context-group> </trans-unit> - <trans-unit id="_msg483"> + <trans-unit id="_msg506"> <source xml:space="preserve">Blocksdir</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">143</context></context-group> </trans-unit> - <trans-unit id="_msg484"> + <trans-unit id="_msg507"> <source xml:space="preserve">To specify a non-default location of the blocks directory use the '%1' option.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">153</context></context-group> </trans-unit> - <trans-unit id="_msg485" approved="yes"> + <trans-unit id="_msg508" approved="yes"> <source xml:space="preserve">Startup time</source> <target xml:space="preserve">Startup time</target> <context-group purpose="location"><context context-type="linenumber">172</context></context-group> </trans-unit> - <trans-unit id="_msg486" approved="yes"> + <trans-unit id="_msg509" approved="yes"> <source xml:space="preserve">Network</source> <target xml:space="preserve">Network</target> <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="_msg487"> + <trans-unit id="_msg510"> <source xml:space="preserve">Name</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">208</context></context-group> </trans-unit> - <trans-unit id="_msg488" approved="yes"> + <trans-unit id="_msg511" approved="yes"> <source xml:space="preserve">Number of connections</source> <target xml:space="preserve">Number of connections</target> <context-group purpose="location"><context context-type="linenumber">231</context></context-group> </trans-unit> - <trans-unit id="_msg489" approved="yes"> + <trans-unit id="_msg512" approved="yes"> <source xml:space="preserve">Block chain</source> <target xml:space="preserve">Block chain</target> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <trans-unit id="_msg490"> + <trans-unit id="_msg513"> <source xml:space="preserve">Memory Pool</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">319</context></context-group> </trans-unit> - <trans-unit id="_msg491"> + <trans-unit id="_msg514"> <source xml:space="preserve">Current number of transactions</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">326</context></context-group> </trans-unit> - <trans-unit id="_msg492"> + <trans-unit id="_msg515"> <source xml:space="preserve">Memory usage</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">349</context></context-group> </trans-unit> - <trans-unit id="_msg493"> + <trans-unit id="_msg516"> <source xml:space="preserve">Wallet: </source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">443</context></context-group> </trans-unit> - <trans-unit id="_msg494"> + <trans-unit id="_msg517"> <source xml:space="preserve">(none)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">454</context></context-group> </trans-unit> - <trans-unit id="_msg495"> + <trans-unit id="_msg518"> <source xml:space="preserve">&Reset</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">665</context></context-group> </trans-unit> - <trans-unit id="_msg496"> + <trans-unit id="_msg519"> <source xml:space="preserve">Received</source> <target xml:space="preserve"></target> <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="_msg497"> + <trans-unit id="_msg520"> <source xml:space="preserve">Sent</source> <target xml:space="preserve"></target> <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="_msg498"> + <trans-unit id="_msg521"> <source xml:space="preserve">&Peers</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">866</context></context-group> </trans-unit> - <trans-unit id="_msg499"> + <trans-unit id="_msg522"> <source xml:space="preserve">Banned peers</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">942</context></context-group> </trans-unit> - <trans-unit id="_msg500"> + <trans-unit id="_msg523"> <source xml:space="preserve">Select a peer to view detailed information.</source> <target xml:space="preserve"></target> <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">1124</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../rpcconsole.cpp</context><context context-type="linenumber">1158</context></context-group> </trans-unit> - <trans-unit id="_msg501"> + <trans-unit id="_msg524"> <source xml:space="preserve">Version</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1116</context></context-group> </trans-unit> - <trans-unit id="_msg502"> + <trans-unit id="_msg525"> <source xml:space="preserve">Starting Block</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1240</context></context-group> </trans-unit> - <trans-unit id="_msg503"> + <trans-unit id="_msg526"> <source xml:space="preserve">Synced Headers</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1263</context></context-group> </trans-unit> - <trans-unit id="_msg504"> + <trans-unit id="_msg527"> <source xml:space="preserve">Synced Blocks</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1286</context></context-group> </trans-unit> - <trans-unit id="_msg505"> + <trans-unit id="_msg528"> + <source xml:space="preserve">Last Transaction</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1361</context></context-group> + </trans-unit> + <trans-unit id="_msg529"> <source xml:space="preserve">The mapped Autonomous System used for diversifying peer selection.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1571</context></context-group> </trans-unit> - <trans-unit id="_msg506"> + <trans-unit id="_msg530"> <source xml:space="preserve">Mapped AS</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1574</context></context-group> </trans-unit> - <trans-unit id="_msg507"> + <trans-unit id="_msg531"> + <source xml:space="preserve">Whether we relay addresses to this peer.</source> + <target xml:space="preserve"></target> + <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> + </trans-unit> + <trans-unit id="_msg532"> + <source xml:space="preserve">Address Relay</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1600</context></context-group> + </trans-unit> + <trans-unit id="_msg533"> + <source xml:space="preserve">Total number of addresses processed, excluding those dropped due to rate-limiting.</source> + <target xml:space="preserve"></target> + <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> + </trans-unit> + <trans-unit id="_msg534"> + <source xml:space="preserve">Addresses Processed</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1626</context></context-group> + </trans-unit> + <trans-unit id="_msg535"> + <source xml:space="preserve">Total number of addresses dropped due to rate-limiting.</source> + <target xml:space="preserve"></target> + <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"> + <source xml:space="preserve">Addresses Rate-Limited</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">1652</context></context-group> + </trans-unit> + <trans-unit id="_msg537"> <source xml:space="preserve">User Agent</source> <target xml:space="preserve"></target> <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="_msg508"> + <trans-unit id="_msg538"> <source xml:space="preserve">Node window</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg509"> + <trans-unit id="_msg539"> <source xml:space="preserve">Current block height</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">267</context></context-group> </trans-unit> - <trans-unit id="_msg510"> + <trans-unit id="_msg540"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">397</context></context-group> </trans-unit> - <trans-unit id="_msg511"> + <trans-unit id="_msg541"> <source xml:space="preserve">Decrease font size</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">475</context></context-group> </trans-unit> - <trans-unit id="_msg512"> + <trans-unit id="_msg542"> <source xml:space="preserve">Increase font size</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">495</context></context-group> </trans-unit> - <trans-unit id="_msg513"> + <trans-unit id="_msg543"> <source xml:space="preserve">Permissions</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1041</context></context-group> </trans-unit> - <trans-unit id="_msg514"> + <trans-unit id="_msg544"> <source xml:space="preserve">The direction and type of peer connection: %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1064</context></context-group> </trans-unit> - <trans-unit id="_msg515"> + <trans-unit id="_msg545"> <source xml:space="preserve">Direction/Type</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1067</context></context-group> </trans-unit> - <trans-unit id="_msg516"> + <trans-unit id="_msg546"> <source xml:space="preserve">The network protocol this peer is connected through: IPv4, IPv6, Onion, I2P, or CJDNS.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1090</context></context-group> </trans-unit> - <trans-unit id="_msg517"> + <trans-unit id="_msg547"> <source xml:space="preserve">Services</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1162</context></context-group> </trans-unit> - <trans-unit id="_msg518"> + <trans-unit id="_msg548"> <source xml:space="preserve">Whether the peer requested us to relay transactions.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1188</context></context-group> </trans-unit> - <trans-unit id="_msg519"> + <trans-unit id="_msg549"> <source xml:space="preserve">Wants Tx Relay</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1191</context></context-group> </trans-unit> - <trans-unit id="_msg520"> + <trans-unit id="_msg550"> <source xml:space="preserve">High bandwidth BIP152 compact block relay: %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1214</context></context-group> </trans-unit> - <trans-unit id="_msg521"> + <trans-unit id="_msg551"> <source xml:space="preserve">High Bandwidth</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1217</context></context-group> </trans-unit> - <trans-unit id="_msg522"> + <trans-unit id="_msg552"> <source xml:space="preserve">Connection Time</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1309</context></context-group> </trans-unit> - <trans-unit id="_msg523"> + <trans-unit id="_msg553"> <source xml:space="preserve">Elapsed time since a novel block passing initial validity checks was received from this peer.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1332</context></context-group> </trans-unit> - <trans-unit id="_msg524"> + <trans-unit id="_msg554"> <source xml:space="preserve">Last Block</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1335</context></context-group> </trans-unit> - <trans-unit id="_msg525"> + <trans-unit id="_msg555"> <source xml:space="preserve">Elapsed time since a novel transaction accepted into our mempool was received from this peer.</source> <target xml:space="preserve"></target> <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="_msg526"> - <source xml:space="preserve">Last Tx</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1361</context></context-group> - </trans-unit> - <trans-unit id="_msg527"> + <trans-unit id="_msg556"> <source xml:space="preserve">Last Send</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1384</context></context-group> </trans-unit> - <trans-unit id="_msg528"> + <trans-unit id="_msg557"> <source xml:space="preserve">Last Receive</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1407</context></context-group> </trans-unit> - <trans-unit id="_msg529"> + <trans-unit id="_msg558"> <source xml:space="preserve">Ping Time</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1476</context></context-group> </trans-unit> - <trans-unit id="_msg530"> + <trans-unit id="_msg559"> <source xml:space="preserve">The duration of a currently outstanding ping.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1499</context></context-group> </trans-unit> - <trans-unit id="_msg531"> + <trans-unit id="_msg560"> <source xml:space="preserve">Ping Wait</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1502</context></context-group> </trans-unit> - <trans-unit id="_msg532"> + <trans-unit id="_msg561"> <source xml:space="preserve">Min Ping</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1525</context></context-group> </trans-unit> - <trans-unit id="_msg533"> + <trans-unit id="_msg562"> <source xml:space="preserve">Time Offset</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1548</context></context-group> </trans-unit> - <trans-unit id="_msg534" approved="yes"> + <trans-unit id="_msg563" approved="yes"> <source xml:space="preserve">Last block time</source> <target xml:space="preserve">Last block time</target> <context-group purpose="location"><context context-type="linenumber">290</context></context-group> </trans-unit> - <trans-unit id="_msg535" approved="yes"> + <trans-unit id="_msg564" approved="yes"> <source xml:space="preserve">&Open</source> <target xml:space="preserve">&Open</target> <context-group purpose="location"><context context-type="linenumber">400</context></context-group> </trans-unit> - <trans-unit id="_msg536" approved="yes"> + <trans-unit id="_msg565" approved="yes"> <source xml:space="preserve">&Console</source> <target xml:space="preserve">&Console</target> <context-group purpose="location"><context context-type="linenumber">426</context></context-group> </trans-unit> - <trans-unit id="_msg537"> + <trans-unit id="_msg566"> <source xml:space="preserve">&Network Traffic</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">613</context></context-group> </trans-unit> - <trans-unit id="_msg538"> + <trans-unit id="_msg567"> <source xml:space="preserve">Totals</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">681</context></context-group> </trans-unit> - <trans-unit id="_msg539" approved="yes"> + <trans-unit id="_msg568" approved="yes"> <source xml:space="preserve">Debug log file</source> <target xml:space="preserve">Debug log file</target> <context-group purpose="location"><context context-type="linenumber">390</context></context-group> </trans-unit> - <trans-unit id="_msg540" approved="yes"> + <trans-unit id="_msg569" approved="yes"> <source xml:space="preserve">Clear console</source> <target xml:space="preserve">Clear console</target> <context-group purpose="location"><context context-type="linenumber">515</context></context-group> @@ -2999,131 +3188,149 @@ 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" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RPCConsole"> - <trans-unit id="_msg541"> + <trans-unit id="_msg570"> <source xml:space="preserve">In:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">923</context></context-group> + <context-group purpose="location"><context context-type="linenumber">957</context></context-group> </trans-unit> - <trans-unit id="_msg542"> + <trans-unit id="_msg571"> <source xml:space="preserve">Out:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">924</context></context-group> + <context-group purpose="location"><context context-type="linenumber">958</context></context-group> </trans-unit> - <trans-unit id="_msg543"> + <trans-unit id="_msg572"> <source xml:space="preserve">Inbound: initiated by peer</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">495</context></context-group> + <context-group purpose="location"><context context-type="linenumber">501</context></context-group> + <note annotates="source" from="developer">Explanatory text for an inbound peer connection.</note> </trans-unit> - <trans-unit id="_msg544"> + <trans-unit id="_msg573"> <source xml:space="preserve">Outbound Full Relay: default</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">496</context></context-group> + <context-group purpose="location"><context context-type="linenumber">505</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="_msg545"> + <trans-unit id="_msg574"> <source xml:space="preserve">Outbound Block Relay: does not relay transactions or addresses</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">497</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 relays network information about blocks and not transactions or addresses.</note> </trans-unit> - <trans-unit id="_msg546"> + <trans-unit id="_msg575"> <source xml:space="preserve">Outbound Manual: added using RPC %1 or %2/%3 configuration options</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">498</context></context-group> + <context-group purpose="location"><context context-type="linenumber">513</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="_msg547"> + <trans-unit id="_msg576"> <source xml:space="preserve">Outbound Feeler: short-lived, for testing addresses</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">502</context></context-group> + <context-group purpose="location"><context context-type="linenumber">519</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="_msg548"> + <trans-unit id="_msg577"> <source xml:space="preserve">Outbound Address Fetch: short-lived, for soliciting addresses</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">503</context></context-group> + <context-group purpose="location"><context context-type="linenumber">522</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="_msg549"> + <trans-unit id="_msg578"> <source xml:space="preserve">we selected the peer for high bandwidth relay</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">507</context></context-group> + <context-group purpose="location"><context context-type="linenumber">526</context></context-group> </trans-unit> - <trans-unit id="_msg550"> + <trans-unit id="_msg579"> <source xml:space="preserve">the peer selected us for high bandwidth relay</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">508</context></context-group> + <context-group purpose="location"><context context-type="linenumber">527</context></context-group> </trans-unit> - <trans-unit id="_msg551"> + <trans-unit id="_msg580"> <source xml:space="preserve">no high bandwidth relay selected</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">509</context></context-group> + <context-group purpose="location"><context context-type="linenumber">528</context></context-group> </trans-unit> - <trans-unit id="_msg552"> + <trans-unit id="_msg581"> <source xml:space="preserve">Ctrl++</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">522</context></context-group> + <context-group purpose="location"><context context-type="linenumber">541</context></context-group> <note annotates="source" from="developer">Main shortcut to increase the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg553"> + <trans-unit id="_msg582"> <source xml:space="preserve">Ctrl+=</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">524</context></context-group> + <context-group purpose="location"><context context-type="linenumber">543</context></context-group> <note annotates="source" from="developer">Secondary shortcut to increase the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg554"> + <trans-unit id="_msg583"> <source xml:space="preserve">Ctrl+-</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">528</context></context-group> + <context-group purpose="location"><context context-type="linenumber">547</context></context-group> <note annotates="source" from="developer">Main shortcut to decrease the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg555"> + <trans-unit id="_msg584"> <source xml:space="preserve">Ctrl+_</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">530</context></context-group> + <context-group purpose="location"><context context-type="linenumber">549</context></context-group> <note annotates="source" from="developer">Secondary shortcut to decrease the RPC console font size.</note> </trans-unit> - <trans-unit id="_msg556"> + <trans-unit id="_msg585"> + <source xml:space="preserve">&Copy address</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">700</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"> <source xml:space="preserve">&Disconnect</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">680</context></context-group> + <context-group purpose="location"><context context-type="linenumber">704</context></context-group> </trans-unit> - <trans-unit id="_msg557"> + <trans-unit id="_msg587"> <source xml:space="preserve">1 &hour</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">681</context></context-group> + <context-group purpose="location"><context context-type="linenumber">705</context></context-group> </trans-unit> - <trans-unit id="_msg558"> + <trans-unit id="_msg588"> <source xml:space="preserve">1 d&ay</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">682</context></context-group> + <context-group purpose="location"><context context-type="linenumber">706</context></context-group> </trans-unit> - <trans-unit id="_msg559"> + <trans-unit id="_msg589"> <source xml:space="preserve">1 &week</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">683</context></context-group> + <context-group purpose="location"><context context-type="linenumber">707</context></context-group> </trans-unit> - <trans-unit id="_msg560"> + <trans-unit id="_msg590"> <source xml:space="preserve">1 &year</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">684</context></context-group> + <context-group purpose="location"><context context-type="linenumber">708</context></context-group> </trans-unit> - <trans-unit id="_msg561"> + <trans-unit id="_msg591"> + <source xml:space="preserve">&Copy IP/Netmask</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">733</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's IP address and its Netmask. For IP address, see: https://en.wikipedia.org/wiki/IP_address.</note> + </trans-unit> + <trans-unit id="_msg592"> <source xml:space="preserve">&Unban</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">706</context></context-group> + <context-group purpose="location"><context context-type="linenumber">737</context></context-group> </trans-unit> - <trans-unit id="_msg562"> + <trans-unit id="_msg593"> <source xml:space="preserve">Network activity disabled</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">927</context></context-group> + <context-group purpose="location"><context context-type="linenumber">961</context></context-group> </trans-unit> - <trans-unit id="_msg563"> + <trans-unit id="_msg594"> <source xml:space="preserve">Executing command without any wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1004</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1038</context></context-group> </trans-unit> - <trans-unit id="_msg564"> + <trans-unit id="_msg595"> <source xml:space="preserve">Executing command using "%1" wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1002</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1036</context></context-group> </trans-unit> - <trans-unit id="_msg565"> + <trans-unit id="_msg596"> <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. @@ -3132,60 +3339,60 @@ 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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">856</context></context-group> + <context-group purpose="location"><context context-type="linenumber">891</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="_msg566"> + <trans-unit id="_msg597"> <source xml:space="preserve">Executing…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1012</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1046</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="_msg567"> + <trans-unit id="_msg598"> <source xml:space="preserve">(peer: %1)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1130</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1164</context></context-group> </trans-unit> - <trans-unit id="_msg568"> + <trans-unit id="_msg599"> <source xml:space="preserve">via %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">1132</context></context-group> + <context-group purpose="location"><context context-type="linenumber">1166</context></context-group> </trans-unit> </group> </body></file> <file original="../rpcconsole.h" datatype="c" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RPCConsole"> - <trans-unit id="_msg569"> + <trans-unit id="_msg600"> <source xml:space="preserve">Yes</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">138</context></context-group> </trans-unit> - <trans-unit id="_msg570"> + <trans-unit id="_msg601"> <source xml:space="preserve">No</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">138</context></context-group> </trans-unit> - <trans-unit id="_msg571"> + <trans-unit id="_msg602"> <source xml:space="preserve">To</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">138</context></context-group> </trans-unit> - <trans-unit id="_msg572"> + <trans-unit id="_msg603"> <source xml:space="preserve">From</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">138</context></context-group> </trans-unit> - <trans-unit id="_msg573"> + <trans-unit id="_msg604"> <source xml:space="preserve">Ban for</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">139</context></context-group> </trans-unit> - <trans-unit id="_msg574"> + <trans-unit id="_msg605"> <source xml:space="preserve">Never</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">179</context></context-group> + <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg575"> + <trans-unit id="_msg606"> <source xml:space="preserve">Unknown</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">139</context></context-group> @@ -3194,137 +3401,127 @@ For more information on using this console, type %6. </body></file> <file original="../forms/receivecoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog"> - <trans-unit id="_msg576"> + <trans-unit id="_msg607"> <source xml:space="preserve">&Amount:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">37</context></context-group> </trans-unit> - <trans-unit id="_msg577"> + <trans-unit id="_msg608"> <source xml:space="preserve">&Label:</source> <target xml:space="preserve" state="needs-review-translation">&Label:</target> <context-group purpose="location"><context context-type="linenumber">83</context></context-group> </trans-unit> - <trans-unit id="_msg578"> + <trans-unit id="_msg609"> <source xml:space="preserve">&Message:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">53</context></context-group> </trans-unit> - <trans-unit id="_msg579"> + <trans-unit id="_msg610"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">50</context></context-group> </trans-unit> - <trans-unit id="_msg580"> + <trans-unit id="_msg611"> <source xml:space="preserve">An optional label to associate with the new receiving address.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">80</context></context-group> </trans-unit> - <trans-unit id="_msg581"> + <trans-unit id="_msg612"> <source xml:space="preserve">Use this form to request payments. All fields are <b>optional</b>.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> - <trans-unit id="_msg582"> + <trans-unit id="_msg613"> <source xml:space="preserve">An optional amount to request. Leave this empty or zero to not request a specific amount.</source> <target xml:space="preserve"></target> <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="_msg583"> + <trans-unit id="_msg614"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">66</context></context-group> </trans-unit> - <trans-unit id="_msg584"> + <trans-unit id="_msg615"> <source xml:space="preserve">An optional message that is attached to the payment request and may be displayed to the sender.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> - <trans-unit id="_msg585"> + <trans-unit id="_msg616"> <source xml:space="preserve">&Create new receiving address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">111</context></context-group> </trans-unit> - <trans-unit id="_msg586"> + <trans-unit id="_msg617"> <source xml:space="preserve">Clear all fields of the form.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">134</context></context-group> </trans-unit> - <trans-unit id="_msg587"> + <trans-unit id="_msg618"> <source xml:space="preserve">Clear</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">137</context></context-group> </trans-unit> - <trans-unit id="_msg588"> - <source xml:space="preserve">Native segwit addresses (aka Bech32 or BIP-173) reduce your transaction fees later on and offer better protection against typos, but old wallets don't support them. When unchecked, an address compatible with older wallets will be created instead.</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">215</context></context-group> - </trans-unit> - <trans-unit id="_msg589"> - <source xml:space="preserve">Generate native segwit (Bech32) address</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">218</context></context-group> - </trans-unit> - <trans-unit id="_msg590"> + <trans-unit id="_msg619"> <source xml:space="preserve">Requested payments history</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">279</context></context-group> + <context-group purpose="location"><context context-type="linenumber">273</context></context-group> </trans-unit> - <trans-unit id="_msg591"> + <trans-unit id="_msg620"> <source xml:space="preserve">Show the selected request (does the same as double clicking an entry)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">304</context></context-group> + <context-group purpose="location"><context context-type="linenumber">298</context></context-group> </trans-unit> - <trans-unit id="_msg592"> + <trans-unit id="_msg621"> <source xml:space="preserve">Show</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">307</context></context-group> + <context-group purpose="location"><context context-type="linenumber">301</context></context-group> </trans-unit> - <trans-unit id="_msg593"> + <trans-unit id="_msg622"> <source xml:space="preserve">Remove the selected entries from the list</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">324</context></context-group> + <context-group purpose="location"><context context-type="linenumber">318</context></context-group> </trans-unit> - <trans-unit id="_msg594"> + <trans-unit id="_msg623"> <source xml:space="preserve">Remove</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">327</context></context-group> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> </group> </body></file> <file original="../receivecoinsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ReceiveCoinsDialog"> - <trans-unit id="_msg595"> + <trans-unit id="_msg624"> <source xml:space="preserve">Copy &URI</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg596"> + <trans-unit id="_msg625"> <source xml:space="preserve">&Copy address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">48</context></context-group> </trans-unit> - <trans-unit id="_msg597"> + <trans-unit id="_msg626"> <source xml:space="preserve">Copy &label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> - <trans-unit id="_msg598"> + <trans-unit id="_msg627"> <source xml:space="preserve">Copy &message</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">50</context></context-group> </trans-unit> - <trans-unit id="_msg599"> + <trans-unit id="_msg628"> <source xml:space="preserve">Copy &amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">51</context></context-group> </trans-unit> - <trans-unit id="_msg600"> + <trans-unit id="_msg629"> <source xml:space="preserve">Could not unlock wallet.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">176</context></context-group> </trans-unit> - <trans-unit id="_msg601"> + <trans-unit id="_msg630"> <source xml:space="preserve">Could not generate new %1 address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">181</context></context-group> @@ -3333,62 +3530,62 @@ For more information on using this console, type %6. </body></file> <file original="../forms/receiverequestdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog"> - <trans-unit id="_msg602"> + <trans-unit id="_msg631"> <source xml:space="preserve">Request payment to …</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg603"> + <trans-unit id="_msg632"> <source xml:space="preserve">Address:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg604"> + <trans-unit id="_msg633"> <source xml:space="preserve">Amount:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">119</context></context-group> </trans-unit> - <trans-unit id="_msg605"> + <trans-unit id="_msg634"> <source xml:space="preserve">Label:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">148</context></context-group> </trans-unit> - <trans-unit id="_msg606"> + <trans-unit id="_msg635"> <source xml:space="preserve">Message:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg607"> + <trans-unit id="_msg636"> <source xml:space="preserve">Wallet:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">212</context></context-group> </trans-unit> - <trans-unit id="_msg608"> + <trans-unit id="_msg637"> <source xml:space="preserve">Copy &URI</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> - <trans-unit id="_msg609"> + <trans-unit id="_msg638"> <source xml:space="preserve">Copy &Address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> - <trans-unit id="_msg610"> + <trans-unit id="_msg639"> <source xml:space="preserve">&Verify</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <trans-unit id="_msg611"> + <trans-unit id="_msg640"> <source xml:space="preserve">Verify this address on e.g. a hardware wallet screen</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">263</context></context-group> </trans-unit> - <trans-unit id="_msg612"> + <trans-unit id="_msg641"> <source xml:space="preserve">&Save Image…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">273</context></context-group> </trans-unit> - <trans-unit id="_msg613"> + <trans-unit id="_msg642"> <source xml:space="preserve">Payment information</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">39</context></context-group> @@ -3397,7 +3594,7 @@ For more information on using this console, type %6. </body></file> <file original="../receiverequestdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="ReceiveRequestDialog"> - <trans-unit id="_msg614"> + <trans-unit id="_msg643"> <source xml:space="preserve">Request payment to %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> @@ -3406,37 +3603,37 @@ For more information on using this console, type %6. </body></file> <file original="../recentrequeststablemodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="RecentRequestsTableModel"> - <trans-unit id="_msg615"> + <trans-unit id="_msg644"> <source xml:space="preserve">Date</source> <target xml:space="preserve" state="needs-review-translation">Date</target> <context-group purpose="location"><context context-type="linenumber">32</context></context-group> </trans-unit> - <trans-unit id="_msg616"> + <trans-unit id="_msg645"> <source xml:space="preserve">Label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">32</context></context-group> </trans-unit> - <trans-unit id="_msg617"> + <trans-unit id="_msg646"> <source xml:space="preserve">Message</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">32</context></context-group> </trans-unit> - <trans-unit id="_msg618"> + <trans-unit id="_msg647"> <source xml:space="preserve">(no label)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> - <trans-unit id="_msg619"> + <trans-unit id="_msg648"> <source xml:space="preserve">(no message)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">82</context></context-group> </trans-unit> - <trans-unit id="_msg620"> + <trans-unit id="_msg649"> <source xml:space="preserve">(no amount requested)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg621"> + <trans-unit id="_msg650"> <source xml:space="preserve">Requested</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">133</context></context-group> @@ -3445,190 +3642,190 @@ For more information on using this console, type %6. </body></file> <file original="../forms/sendcoinsdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SendCoinsDialog"> - <trans-unit id="_msg622" approved="yes"> + <trans-unit id="_msg651" approved="yes"> <source xml:space="preserve">Send Coins</source> <target xml:space="preserve">Send Coins</target> <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">738</context></context-group> + <context-group purpose="location"><context context-type="sourcefile">../sendcoinsdialog.cpp</context><context context-type="linenumber">749</context></context-group> </trans-unit> - <trans-unit id="_msg623"> + <trans-unit id="_msg652"> <source xml:space="preserve">Coin Control Features</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg624"> + <trans-unit id="_msg653"> <source xml:space="preserve">automatically selected</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> </trans-unit> - <trans-unit id="_msg625"> + <trans-unit id="_msg654"> <source xml:space="preserve">Insufficient funds!</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">139</context></context-group> </trans-unit> - <trans-unit id="_msg626"> + <trans-unit id="_msg655"> <source xml:space="preserve">Quantity:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">228</context></context-group> </trans-unit> - <trans-unit id="_msg627"> + <trans-unit id="_msg656"> <source xml:space="preserve">Bytes:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">263</context></context-group> </trans-unit> - <trans-unit id="_msg628"> + <trans-unit id="_msg657"> <source xml:space="preserve">Amount:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">311</context></context-group> </trans-unit> - <trans-unit id="_msg629"> + <trans-unit id="_msg658"> <source xml:space="preserve">Fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">391</context></context-group> </trans-unit> - <trans-unit id="_msg630"> + <trans-unit id="_msg659"> <source xml:space="preserve">After Fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">442</context></context-group> </trans-unit> - <trans-unit id="_msg631"> + <trans-unit id="_msg660"> <source xml:space="preserve">Change:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">474</context></context-group> </trans-unit> - <trans-unit id="_msg632"> + <trans-unit id="_msg661"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">518</context></context-group> </trans-unit> - <trans-unit id="_msg633"> + <trans-unit id="_msg662"> <source xml:space="preserve">Custom change address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">521</context></context-group> </trans-unit> - <trans-unit id="_msg634"> + <trans-unit id="_msg663"> <source xml:space="preserve">Transaction Fee:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">727</context></context-group> </trans-unit> - <trans-unit id="_msg635"> + <trans-unit id="_msg664"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">765</context></context-group> </trans-unit> - <trans-unit id="_msg636"> + <trans-unit id="_msg665"> <source xml:space="preserve">Warning: Fee estimation is currently not possible.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">774</context></context-group> </trans-unit> - <trans-unit id="_msg637"> + <trans-unit id="_msg666"> <source xml:space="preserve">per kilobyte</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">856</context></context-group> </trans-unit> - <trans-unit id="_msg638"> + <trans-unit id="_msg667"> <source xml:space="preserve">Hide</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">803</context></context-group> </trans-unit> - <trans-unit id="_msg639"> + <trans-unit id="_msg668"> <source xml:space="preserve">Recommended:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">915</context></context-group> </trans-unit> - <trans-unit id="_msg640"> + <trans-unit id="_msg669"> <source xml:space="preserve">Custom:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">945</context></context-group> </trans-unit> - <trans-unit id="_msg641" approved="yes"> + <trans-unit id="_msg670" approved="yes"> <source xml:space="preserve">Send to multiple recipients at once</source> <target xml:space="preserve">Send to multiple recipients at once</target> <context-group purpose="location"><context context-type="linenumber">1160</context></context-group> </trans-unit> - <trans-unit id="_msg642" approved="yes"> + <trans-unit id="_msg671" approved="yes"> <source xml:space="preserve">Add &Recipient</source> <target xml:space="preserve">Add &Recipient</target> <context-group purpose="location"><context context-type="linenumber">1163</context></context-group> </trans-unit> - <trans-unit id="_msg643"> + <trans-unit id="_msg672"> <source xml:space="preserve">Clear all fields of the form.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1143</context></context-group> </trans-unit> - <trans-unit id="_msg644"> + <trans-unit id="_msg673"> <source xml:space="preserve">Inputs…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">110</context></context-group> </trans-unit> - <trans-unit id="_msg645"> + <trans-unit id="_msg674"> <source xml:space="preserve">Dust:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">343</context></context-group> </trans-unit> - <trans-unit id="_msg646"> + <trans-unit id="_msg675"> <source xml:space="preserve">Choose…</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">741</context></context-group> </trans-unit> - <trans-unit id="_msg647"> + <trans-unit id="_msg676"> <source xml:space="preserve">Hide transaction fee settings</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">800</context></context-group> </trans-unit> - <trans-unit id="_msg648"> + <trans-unit id="_msg677"> <source xml:space="preserve">Specify a custom fee per kB (1,000 bytes) of the transaction's virtual size. Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 satoshis per kvB" for a transaction size of 500 virtual bytes (half of 1 kvB) would ultimately yield a fee of only 50 satoshis.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">851</context></context-group> </trans-unit> - <trans-unit id="_msg649"> + <trans-unit id="_msg678"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">886</context></context-group> </trans-unit> - <trans-unit id="_msg650"> + <trans-unit id="_msg679"> <source xml:space="preserve">A too low fee might result in a never confirming transaction (read the tooltip)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">889</context></context-group> </trans-unit> - <trans-unit id="_msg651"> + <trans-unit id="_msg680"> <source xml:space="preserve">(Smart fee not initialized yet. This usually takes a few blocks…)</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">994</context></context-group> </trans-unit> - <trans-unit id="_msg652"> + <trans-unit id="_msg681"> <source xml:space="preserve">Confirmation time target:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1020</context></context-group> </trans-unit> - <trans-unit id="_msg653"> + <trans-unit id="_msg682"> <source xml:space="preserve">Enable Replace-By-Fee</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1078</context></context-group> </trans-unit> - <trans-unit id="_msg654"> + <trans-unit id="_msg683"> <source xml:space="preserve">With Replace-By-Fee (BIP-125) you can increase a transaction's fee after it is sent. Without this, a higher fee may be recommended to compensate for increased transaction delay risk.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1081</context></context-group> </trans-unit> - <trans-unit id="_msg655" approved="yes"> + <trans-unit id="_msg684" approved="yes"> <source xml:space="preserve">Clear &All</source> <target xml:space="preserve">Clear &All</target> <context-group purpose="location"><context context-type="linenumber">1146</context></context-group> </trans-unit> - <trans-unit id="_msg656" approved="yes"> + <trans-unit id="_msg685" approved="yes"> <source xml:space="preserve">Balance:</source> <target xml:space="preserve">Balance:</target> <context-group purpose="location"><context context-type="linenumber">1201</context></context-group> </trans-unit> - <trans-unit id="_msg657" approved="yes"> + <trans-unit id="_msg686" approved="yes"> <source xml:space="preserve">Confirm the send action</source> <target xml:space="preserve">Confirm the send action</target> <context-group purpose="location"><context context-type="linenumber">1117</context></context-group> </trans-unit> - <trans-unit id="_msg658" approved="yes"> + <trans-unit id="_msg687" approved="yes"> <source xml:space="preserve">S&end</source> <target xml:space="preserve">S&end</target> <context-group purpose="location"><context context-type="linenumber">1120</context></context-group> @@ -3637,383 +3834,372 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../sendcoinsdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SendCoinsDialog"> - <trans-unit id="_msg659"> + <trans-unit id="_msg688"> <source xml:space="preserve">Copy quantity</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">92</context></context-group> + <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> - <trans-unit id="_msg660"> + <trans-unit id="_msg689"> <source xml:space="preserve">Copy amount</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">93</context></context-group> + <context-group purpose="location"><context context-type="linenumber">97</context></context-group> </trans-unit> - <trans-unit id="_msg661"> + <trans-unit id="_msg690"> <source xml:space="preserve">Copy fee</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">94</context></context-group> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg662"> + <trans-unit id="_msg691"> <source xml:space="preserve">Copy after fee</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">95</context></context-group> + <context-group purpose="location"><context context-type="linenumber">99</context></context-group> </trans-unit> - <trans-unit id="_msg663"> + <trans-unit id="_msg692"> <source xml:space="preserve">Copy bytes</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">96</context></context-group> + <context-group purpose="location"><context context-type="linenumber">100</context></context-group> </trans-unit> - <trans-unit id="_msg664"> + <trans-unit id="_msg693"> <source xml:space="preserve">Copy dust</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">97</context></context-group> + <context-group purpose="location"><context context-type="linenumber">101</context></context-group> </trans-unit> - <trans-unit id="_msg665"> + <trans-unit id="_msg694"> <source xml:space="preserve">Copy change</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + <context-group purpose="location"><context context-type="linenumber">102</context></context-group> </trans-unit> - <trans-unit id="_msg666"> + <trans-unit id="_msg695"> <source xml:space="preserve">%1 (%2 blocks)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">174</context></context-group> + <context-group purpose="location"><context context-type="linenumber">178</context></context-group> </trans-unit> - <trans-unit id="_msg667"> + <trans-unit id="_msg696"> <source xml:space="preserve">Sign on device</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">204</context></context-group> - <note annotates="source" from="developer">"device" usually means a hardware wallet</note> + <context-group purpose="location"><context context-type="linenumber">208</context></context-group> + <note annotates="source" from="developer">"device" usually means a hardware wallet.</note> </trans-unit> - <trans-unit id="_msg668"> + <trans-unit id="_msg697"> <source xml:space="preserve">Connect your hardware wallet first.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">207</context></context-group> + <context-group purpose="location"><context context-type="linenumber">211</context></context-group> </trans-unit> - <trans-unit id="_msg669"> + <trans-unit id="_msg698"> <source xml:space="preserve">Set external signer script path in Options -> Wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">211</context></context-group> + <context-group purpose="location"><context context-type="linenumber">215</context></context-group> <note annotates="source" from="developer">"External signer" means using devices such as hardware wallets.</note> </trans-unit> - <trans-unit id="_msg670"> + <trans-unit id="_msg699"> <source xml:space="preserve">Cr&eate Unsigned</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">214</context></context-group> + <context-group purpose="location"><context context-type="linenumber">218</context></context-group> </trans-unit> - <trans-unit id="_msg671"> + <trans-unit id="_msg700"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">215</context></context-group> + <context-group purpose="location"><context context-type="linenumber">219</context></context-group> </trans-unit> - <trans-unit id="_msg672"> + <trans-unit id="_msg701"> <source xml:space="preserve"> from wallet '%1'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">305</context></context-group> + <context-group purpose="location"><context context-type="linenumber">309</context></context-group> </trans-unit> - <trans-unit id="_msg673"> + <trans-unit id="_msg702"> <source xml:space="preserve">%1 to '%2'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">316</context></context-group> + <context-group purpose="location"><context context-type="linenumber">320</context></context-group> </trans-unit> - <trans-unit id="_msg674"> + <trans-unit id="_msg703"> <source xml:space="preserve">%1 to %2</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">321</context></context-group> - </trans-unit> - <trans-unit id="_msg675"> - <source xml:space="preserve">Do you want to draft this transaction?</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">328</context></context-group> - </trans-unit> - <trans-unit id="_msg676"> - <source xml:space="preserve">Are you sure you want to send?</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">330</context></context-group> + <context-group purpose="location"><context context-type="linenumber">325</context></context-group> </trans-unit> - <trans-unit id="_msg677"> + <trans-unit id="_msg704"> <source xml:space="preserve">To review recipient list click "Show Details…"</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">382</context></context-group> - </trans-unit> - <trans-unit id="_msg678"> - <source xml:space="preserve">Create Unsigned</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">401</context></context-group> - </trans-unit> - <trans-unit id="_msg679"> - <source xml:space="preserve">Sign and send</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">401</context></context-group> + <context-group purpose="location"><context context-type="linenumber">392</context></context-group> </trans-unit> - <trans-unit id="_msg680"> + <trans-unit id="_msg705"> <source xml:space="preserve">Sign failed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">426</context></context-group> + <context-group purpose="location"><context context-type="linenumber">436</context></context-group> </trans-unit> - <trans-unit id="_msg681"> + <trans-unit id="_msg706"> <source xml:space="preserve">External signer not found</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">432</context></context-group> + <context-group purpose="location"><context context-type="linenumber">442</context></context-group> <note annotates="source" from="developer">"External signer" means using devices such as hardware wallets.</note> </trans-unit> - <trans-unit id="_msg682"> + <trans-unit id="_msg707"> <source xml:space="preserve">External signer failure</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">438</context></context-group> + <context-group purpose="location"><context context-type="linenumber">448</context></context-group> <note annotates="source" from="developer">"External signer" means using devices such as hardware wallets.</note> </trans-unit> - <trans-unit id="_msg683"> + <trans-unit id="_msg708"> <source xml:space="preserve">Save Transaction Data</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">496</context></context-group> + <context-group purpose="location"><context context-type="linenumber">506</context></context-group> </trans-unit> - <trans-unit id="_msg684"> + <trans-unit id="_msg709"> <source xml:space="preserve">Partially Signed Transaction (Binary)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">498</context></context-group> + <context-group purpose="location"><context context-type="linenumber">508</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="_msg685"> + <trans-unit id="_msg710"> <source xml:space="preserve">PSBT saved</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">505</context></context-group> + <context-group purpose="location"><context context-type="linenumber">515</context></context-group> </trans-unit> - <trans-unit id="_msg686"> + <trans-unit id="_msg711"> <source xml:space="preserve">External balance:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">680</context></context-group> + <context-group purpose="location"><context context-type="linenumber">691</context></context-group> </trans-unit> - <trans-unit id="_msg687"> + <trans-unit id="_msg712"> <source xml:space="preserve">or</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">378</context></context-group> + <context-group purpose="location"><context context-type="linenumber">388</context></context-group> </trans-unit> - <trans-unit id="_msg688"> + <trans-unit id="_msg713"> <source xml:space="preserve">You can increase the fee later (signals Replace-By-Fee, BIP-125).</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">359</context></context-group> + <context-group purpose="location"><context context-type="linenumber">369</context></context-group> </trans-unit> - <trans-unit id="_msg689"> + <trans-unit id="_msg714"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + <context-group purpose="location"><context context-type="linenumber">339</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="_msg690"> + <trans-unit id="_msg715"> + <source xml:space="preserve">Do you want to create this transaction?</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">333</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"> + <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> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">344</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"> <source xml:space="preserve">Please, review your transaction.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">337</context></context-group> + <context-group purpose="location"><context context-type="linenumber">347</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="_msg691"> + <trans-unit id="_msg718"> <source xml:space="preserve">Transaction fee</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">345</context></context-group> + <context-group purpose="location"><context context-type="linenumber">355</context></context-group> </trans-unit> - <trans-unit id="_msg692"> + <trans-unit id="_msg719"> <source xml:space="preserve">Not signalling Replace-By-Fee, BIP-125.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">361</context></context-group> + <context-group purpose="location"><context context-type="linenumber">371</context></context-group> </trans-unit> - <trans-unit id="_msg693"> + <trans-unit id="_msg720"> <source xml:space="preserve">Total Amount</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">375</context></context-group> + <context-group purpose="location"><context context-type="linenumber">385</context></context-group> </trans-unit> - <trans-unit id="_msg694"> + <trans-unit id="_msg721"> <source xml:space="preserve">Confirm send coins</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">400</context></context-group> + <context-group purpose="location"><context context-type="linenumber">410</context></context-group> </trans-unit> - <trans-unit id="_msg695"> - <source xml:space="preserve">Confirm transaction proposal</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">400</context></context-group> - </trans-unit> - <trans-unit id="_msg696"> + <trans-unit id="_msg722"> <source xml:space="preserve">Watch-only balance:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">683</context></context-group> + <context-group purpose="location"><context context-type="linenumber">694</context></context-group> </trans-unit> - <trans-unit id="_msg697"> + <trans-unit id="_msg723"> <source xml:space="preserve">The recipient address is not valid. Please recheck.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">707</context></context-group> + <context-group purpose="location"><context context-type="linenumber">718</context></context-group> </trans-unit> - <trans-unit id="_msg698"> + <trans-unit id="_msg724"> <source xml:space="preserve">The amount to pay must be larger than 0.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">710</context></context-group> + <context-group purpose="location"><context context-type="linenumber">721</context></context-group> </trans-unit> - <trans-unit id="_msg699"> + <trans-unit id="_msg725"> <source xml:space="preserve">The amount exceeds your balance.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">713</context></context-group> + <context-group purpose="location"><context context-type="linenumber">724</context></context-group> </trans-unit> - <trans-unit id="_msg700"> + <trans-unit id="_msg726"> <source xml:space="preserve">The total exceeds your balance when the %1 transaction fee is included.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">716</context></context-group> + <context-group purpose="location"><context context-type="linenumber">727</context></context-group> </trans-unit> - <trans-unit id="_msg701"> + <trans-unit id="_msg727"> <source xml:space="preserve">Duplicate address found: addresses should only be used once each.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">719</context></context-group> + <context-group purpose="location"><context context-type="linenumber">730</context></context-group> </trans-unit> - <trans-unit id="_msg702"> + <trans-unit id="_msg728"> <source xml:space="preserve">Transaction creation failed!</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">722</context></context-group> + <context-group purpose="location"><context context-type="linenumber">733</context></context-group> </trans-unit> - <trans-unit id="_msg703"> + <trans-unit id="_msg729"> <source xml:space="preserve">A fee higher than %1 is considered an absurdly high fee.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">726</context></context-group> + <context-group purpose="location"><context context-type="linenumber">737</context></context-group> </trans-unit> - <trans-unit id="_msg704"> + <trans-unit id="_msg730"> <source xml:space="preserve">Payment request expired.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">729</context></context-group> + <context-group purpose="location"><context context-type="linenumber">740</context></context-group> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">853</context></context-group> - <trans-unit id="_msg705[0]" approved="yes"> + <context-group purpose="location"><context context-type="linenumber">864</context></context-group> + <trans-unit id="_msg731[0]" approved="yes"> <source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source> <target xml:space="preserve">Estimated to begin confirmation within %n block.</target> </trans-unit> - <trans-unit id="_msg705[1]" approved="yes"> + <trans-unit id="_msg731[1]" approved="yes"> <source xml:space="preserve">Estimated to begin confirmation within %n block(s).</source> <target xml:space="preserve">Estimated to begin confirmation within %n blocks.</target> </trans-unit> </group> - <trans-unit id="_msg706"> + <trans-unit id="_msg732"> <source xml:space="preserve">Warning: Invalid Bitcoin address</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">954</context></context-group> + <context-group purpose="location"><context context-type="linenumber">965</context></context-group> </trans-unit> - <trans-unit id="_msg707"> + <trans-unit id="_msg733"> <source xml:space="preserve">Warning: Unknown change address</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">959</context></context-group> + <context-group purpose="location"><context context-type="linenumber">970</context></context-group> </trans-unit> - <trans-unit id="_msg708"> + <trans-unit id="_msg734"> <source xml:space="preserve">Confirm custom change address</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">962</context></context-group> + <context-group purpose="location"><context context-type="linenumber">973</context></context-group> </trans-unit> - <trans-unit id="_msg709"> + <trans-unit id="_msg735"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">962</context></context-group> + <context-group purpose="location"><context context-type="linenumber">973</context></context-group> </trans-unit> - <trans-unit id="_msg710"> + <trans-unit id="_msg736"> <source xml:space="preserve">(no label)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">983</context></context-group> + <context-group purpose="location"><context context-type="linenumber">994</context></context-group> </trans-unit> </group> </body></file> <file original="../forms/sendcoinsentry.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SendCoinsEntry"> - <trans-unit id="_msg711" approved="yes"> + <trans-unit id="_msg737" approved="yes"> <source xml:space="preserve">A&mount:</source> <target xml:space="preserve">A&mount:</target> <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> </trans-unit> - <trans-unit id="_msg712" approved="yes"> + <trans-unit id="_msg738" approved="yes"> <source xml:space="preserve">Pay &To:</source> <target xml:space="preserve">Pay &To:</target> <context-group purpose="location"><context context-type="linenumber">39</context></context-group> </trans-unit> - <trans-unit id="_msg713" approved="yes"> + <trans-unit id="_msg739" approved="yes"> <source xml:space="preserve">&Label:</source> <target xml:space="preserve">&Label:</target> <context-group purpose="location"><context context-type="linenumber">132</context></context-group> </trans-unit> - <trans-unit id="_msg714"> + <trans-unit id="_msg740"> <source xml:space="preserve">Choose previously used address</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">64</context></context-group> </trans-unit> - <trans-unit id="_msg715"> + <trans-unit id="_msg741"> <source xml:space="preserve">The Bitcoin address to send the payment to</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">57</context></context-group> </trans-unit> - <trans-unit id="_msg716" approved="yes"> + <trans-unit id="_msg742" approved="yes"> <source xml:space="preserve">Alt+A</source> <target xml:space="preserve">Alt+A</target> <context-group purpose="location"><context context-type="linenumber">80</context></context-group> </trans-unit> - <trans-unit id="_msg717" approved="yes"> + <trans-unit id="_msg743" approved="yes"> <source xml:space="preserve">Paste address from clipboard</source> <target xml:space="preserve">Paste address from clipboard</target> <context-group purpose="location"><context context-type="linenumber">87</context></context-group> </trans-unit> - <trans-unit id="_msg718" approved="yes"> + <trans-unit id="_msg744" approved="yes"> <source xml:space="preserve">Alt+P</source> <target xml:space="preserve">Alt+P</target> <context-group purpose="location"><context context-type="linenumber">103</context></context-group> </trans-unit> - <trans-unit id="_msg719"> + <trans-unit id="_msg745"> <source xml:space="preserve">Remove this entry</source> <target xml:space="preserve"></target> <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> </trans-unit> - <trans-unit id="_msg720"> + <trans-unit id="_msg746"> <source xml:space="preserve">The amount to send in the selected unit</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">170</context></context-group> </trans-unit> - <trans-unit id="_msg721"> + <trans-unit id="_msg747"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">177</context></context-group> </trans-unit> - <trans-unit id="_msg722"> + <trans-unit id="_msg748"> <source xml:space="preserve">S&ubtract fee from amount</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg723"> + <trans-unit id="_msg749"> <source xml:space="preserve">Use available balance</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">187</context></context-group> </trans-unit> - <trans-unit id="_msg724"> + <trans-unit id="_msg750"> <source xml:space="preserve">Message:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">196</context></context-group> </trans-unit> - <trans-unit id="_msg725"> + <trans-unit id="_msg751"> <source xml:space="preserve">This is an unauthenticated payment request.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">639</context></context-group> </trans-unit> - <trans-unit id="_msg726"> + <trans-unit id="_msg752"> <source xml:space="preserve">This is an authenticated payment request.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">1168</context></context-group> </trans-unit> - <trans-unit id="_msg727"> + <trans-unit id="_msg753"> <source xml:space="preserve">Enter a label for this address to add it to the list of used addresses</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">145</context></context-group> <context-group purpose="location"><context context-type="linenumber">148</context></context-group> </trans-unit> - <trans-unit id="_msg728"> + <trans-unit id="_msg754"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">206</context></context-group> </trans-unit> - <trans-unit id="_msg729"> + <trans-unit id="_msg755"> <source xml:space="preserve">Pay To:</source> <target xml:space="preserve"></target> <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="_msg730"> + <trans-unit id="_msg756"> <source xml:space="preserve">Memo:</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">688</context></context-group> @@ -4021,130 +4207,144 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </trans-unit> </group> </body></file> + <file original="../sendcoinsdialog.h" datatype="c" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="SendConfirmationDialog"> + <trans-unit id="_msg757"> + <source xml:space="preserve">Send</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">131</context></context-group> + </trans-unit> + <trans-unit id="_msg758"> + <source xml:space="preserve">Create Unsigned</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">133</context></context-group> + </trans-unit> + </group> + </body></file> <file original="../forms/signverifymessagedialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog"> - <trans-unit id="_msg731" approved="yes"> + <trans-unit id="_msg759" approved="yes"> <source xml:space="preserve">Signatures - Sign / Verify a Message</source> <target xml:space="preserve">Signatures - Sign / Verify a Message</target> <context-group purpose="location"><context context-type="linenumber">14</context></context-group> </trans-unit> - <trans-unit id="_msg732" approved="yes"> + <trans-unit id="_msg760" approved="yes"> <source xml:space="preserve">&Sign Message</source> <target xml:space="preserve">&Sign Message</target> <context-group purpose="location"><context context-type="linenumber">27</context></context-group> </trans-unit> - <trans-unit id="_msg733"> + <trans-unit id="_msg761"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">33</context></context-group> </trans-unit> - <trans-unit id="_msg734"> + <trans-unit id="_msg762"> <source xml:space="preserve">The Bitcoin address to sign the message with</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">51</context></context-group> </trans-unit> - <trans-unit id="_msg735"> + <trans-unit id="_msg763"> <source xml:space="preserve">Choose previously used address</source> <target xml:space="preserve"></target> <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="_msg736" approved="yes"> + <trans-unit id="_msg764" approved="yes"> <source xml:space="preserve">Alt+A</source> <target xml:space="preserve">Alt+A</target> <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="_msg737" approved="yes"> + <trans-unit id="_msg765" approved="yes"> <source xml:space="preserve">Paste address from clipboard</source> <target xml:space="preserve">Paste address from clipboard</target> <context-group purpose="location"><context context-type="linenumber">78</context></context-group> </trans-unit> - <trans-unit id="_msg738" approved="yes"> + <trans-unit id="_msg766" approved="yes"> <source xml:space="preserve">Alt+P</source> <target xml:space="preserve">Alt+P</target> <context-group purpose="location"><context context-type="linenumber">88</context></context-group> </trans-unit> - <trans-unit id="_msg739" approved="yes"> + <trans-unit id="_msg767" approved="yes"> <source xml:space="preserve">Enter the message you want to sign here</source> <target xml:space="preserve">Enter the message you want to sign here</target> <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="_msg740" approved="yes"> + <trans-unit id="_msg768" approved="yes"> <source xml:space="preserve">Signature</source> <target xml:space="preserve">Signature</target> <context-group purpose="location"><context context-type="linenumber">110</context></context-group> </trans-unit> - <trans-unit id="_msg741" approved="yes"> + <trans-unit id="_msg769" approved="yes"> <source xml:space="preserve">Copy the current signature to the system clipboard</source> <target xml:space="preserve">Copy the current signature to the system clipboard</target> <context-group purpose="location"><context context-type="linenumber">140</context></context-group> </trans-unit> - <trans-unit id="_msg742" approved="yes"> + <trans-unit id="_msg770" approved="yes"> <source xml:space="preserve">Sign the message to prove you own this Bitcoin address</source> <target xml:space="preserve">Sign the message to prove you own this Bitcoin address</target> <context-group purpose="location"><context context-type="linenumber">161</context></context-group> </trans-unit> - <trans-unit id="_msg743" approved="yes"> + <trans-unit id="_msg771" approved="yes"> <source xml:space="preserve">Sign &Message</source> <target xml:space="preserve">Sign &Message</target> <context-group purpose="location"><context context-type="linenumber">164</context></context-group> </trans-unit> - <trans-unit id="_msg744" approved="yes"> + <trans-unit id="_msg772" approved="yes"> <source xml:space="preserve">Reset all sign message fields</source> <target xml:space="preserve">Reset all sign message fields</target> <context-group purpose="location"><context context-type="linenumber">178</context></context-group> </trans-unit> - <trans-unit id="_msg745" approved="yes"> + <trans-unit id="_msg773" approved="yes"> <source xml:space="preserve">Clear &All</source> <target xml:space="preserve">Clear &All</target> <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="_msg746" approved="yes"> + <trans-unit id="_msg774" approved="yes"> <source xml:space="preserve">&Verify Message</source> <target xml:space="preserve">&Verify Message</target> <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> - <trans-unit id="_msg747"> + <trans-unit id="_msg775"> <source xml:space="preserve">Enter the receiver'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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">246</context></context-group> </trans-unit> - <trans-unit id="_msg748"> + <trans-unit id="_msg776"> <source xml:space="preserve">The Bitcoin address the message was signed with</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">267</context></context-group> </trans-unit> - <trans-unit id="_msg749"> + <trans-unit id="_msg777"> <source xml:space="preserve">The signed message to verify</source> <target xml:space="preserve"></target> <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="_msg750"> + <trans-unit id="_msg778"> <source xml:space="preserve">The signature given when the message was signed</source> <target xml:space="preserve"></target> <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="_msg751" approved="yes"> + <trans-unit id="_msg779" approved="yes"> <source xml:space="preserve">Verify the message to ensure it was signed with the specified Bitcoin address</source> <target xml:space="preserve">Verify the message to ensure it was signed with the specified Bitcoin address</target> <context-group purpose="location"><context context-type="linenumber">318</context></context-group> </trans-unit> - <trans-unit id="_msg752" approved="yes"> + <trans-unit id="_msg780" approved="yes"> <source xml:space="preserve">Verify &Message</source> <target xml:space="preserve">Verify &Message</target> <context-group purpose="location"><context context-type="linenumber">321</context></context-group> </trans-unit> - <trans-unit id="_msg753" approved="yes"> + <trans-unit id="_msg781" approved="yes"> <source xml:space="preserve">Reset all verify message fields</source> <target xml:space="preserve">Reset all verify message fields</target> <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> - <trans-unit id="_msg754"> + <trans-unit id="_msg782"> <source xml:space="preserve">Click "Sign Message" to generate signature</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">125</context></context-group> @@ -4153,13 +4353,13 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../signverifymessagedialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="SignVerifyMessageDialog"> - <trans-unit id="_msg755"> + <trans-unit id="_msg783"> <source xml:space="preserve">The entered address is invalid.</source> <target xml:space="preserve"></target> <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="_msg756"> + <trans-unit id="_msg784"> <source xml:space="preserve">Please check the address and try again.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">120</context></context-group> @@ -4167,68 +4367,82 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 <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="_msg757"> + <trans-unit id="_msg785"> <source xml:space="preserve">The entered address does not refer to a key.</source> <target xml:space="preserve"></target> <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="_msg758"> + <trans-unit id="_msg786"> <source xml:space="preserve">Wallet unlock was cancelled.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">135</context></context-group> </trans-unit> - <trans-unit id="_msg759"> + <trans-unit id="_msg787"> <source xml:space="preserve">No error</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">146</context></context-group> </trans-unit> - <trans-unit id="_msg760"> + <trans-unit id="_msg788"> <source xml:space="preserve">Private key for the entered address is not available.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">149</context></context-group> </trans-unit> - <trans-unit id="_msg761"> + <trans-unit id="_msg789"> <source xml:space="preserve">Message signing failed.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg762"> + <trans-unit id="_msg790"> <source xml:space="preserve">Message signed.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">164</context></context-group> </trans-unit> - <trans-unit id="_msg763"> + <trans-unit id="_msg791"> <source xml:space="preserve">The signature could not be decoded.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">233</context></context-group> </trans-unit> - <trans-unit id="_msg764"> + <trans-unit id="_msg792"> <source xml:space="preserve">Please check the signature and try again.</source> <target xml:space="preserve"></target> <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="_msg765"> + <trans-unit id="_msg793"> <source xml:space="preserve">The signature did not match the message digest.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> - <trans-unit id="_msg766"> + <trans-unit id="_msg794"> <source xml:space="preserve">Message verification failed.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">246</context></context-group> </trans-unit> - <trans-unit id="_msg767"> + <trans-unit id="_msg795"> <source xml:space="preserve">Message verified.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">214</context></context-group> </trans-unit> </group> </body></file> + <file original="../splashscreen.cpp" datatype="cpp" source-language="en" target-language="en"><body> + <group restype="x-trolltech-linguist-context" resname="SplashScreen"> + <trans-unit id="_msg796"> + <source xml:space="preserve">(press q to shutdown and continue later)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">187</context></context-group> + </trans-unit> + <trans-unit id="_msg797"> + <source xml:space="preserve">press q to shutdown</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">188</context></context-group> + </trans-unit> + </group> + </body></file> <file original="../trafficgraphwidget.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TrafficGraphWidget"> - <trans-unit id="_msg768"> + <trans-unit id="_msg798"> <source xml:space="preserve">kB/s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">82</context></context-group> @@ -4237,247 +4451,231 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../transactiondesc.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionDesc"> - <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">36</context></context-group> - <trans-unit id="_msg769[0]" approved="yes"> - <source xml:space="preserve">Open for %n more block(s)</source> - <target xml:space="preserve">Open for %n more block</target> - </trans-unit> - <trans-unit id="_msg769[1]" approved="yes"> - <source xml:space="preserve">Open for %n more block(s)</source> - <target xml:space="preserve">Open for %n more blocks</target> - </trans-unit> - </group> - <trans-unit id="_msg770"> - <source xml:space="preserve">Open until %1</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">38</context></context-group> - </trans-unit> - <trans-unit id="_msg771"> + <trans-unit id="_msg799"> <source xml:space="preserve">conflicted with a transaction with %1 confirmations</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">44</context></context-group> + <context-group purpose="location"><context context-type="linenumber">40</context></context-group> </trans-unit> - <trans-unit id="_msg772"> + <trans-unit id="_msg800"> <source xml:space="preserve">0/unconfirmed, %1</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">47</context></context-group> + <context-group purpose="location"><context context-type="linenumber">43</context></context-group> </trans-unit> - <trans-unit id="_msg773"> + <trans-unit id="_msg801"> <source xml:space="preserve">in memory pool</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">47</context></context-group> + <context-group purpose="location"><context context-type="linenumber">43</context></context-group> </trans-unit> - <trans-unit id="_msg774"> + <trans-unit id="_msg802"> <source xml:space="preserve">not in memory pool</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">47</context></context-group> + <context-group purpose="location"><context context-type="linenumber">43</context></context-group> </trans-unit> - <trans-unit id="_msg775"> + <trans-unit id="_msg803"> <source xml:space="preserve">abandoned</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">46</context></context-group> + <context-group purpose="location"><context context-type="linenumber">42</context></context-group> </trans-unit> - <trans-unit id="_msg776"> + <trans-unit id="_msg804"> <source xml:space="preserve">%1/unconfirmed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">49</context></context-group> + <context-group purpose="location"><context context-type="linenumber">45</context></context-group> </trans-unit> - <trans-unit id="_msg777"> + <trans-unit id="_msg805"> <source xml:space="preserve">%1 confirmations</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">51</context></context-group> + <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg778"> + <trans-unit id="_msg806"> <source xml:space="preserve">Status</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">102</context></context-group> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> </trans-unit> - <trans-unit id="_msg779"> + <trans-unit id="_msg807"> <source xml:space="preserve">Date</source> <target xml:space="preserve" state="needs-review-translation">Date</target> - <context-group purpose="location"><context context-type="linenumber">105</context></context-group> + <context-group purpose="location"><context context-type="linenumber">101</context></context-group> </trans-unit> - <trans-unit id="_msg780"> + <trans-unit id="_msg808"> <source xml:space="preserve">Source</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">112</context></context-group> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> </trans-unit> - <trans-unit id="_msg781"> + <trans-unit id="_msg809"> <source xml:space="preserve">Generated</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">112</context></context-group> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> </trans-unit> - <trans-unit id="_msg782"> + <trans-unit id="_msg810"> <source xml:space="preserve">From</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">117</context></context-group> - <context-group purpose="location"><context context-type="linenumber">131</context></context-group> - <context-group purpose="location"><context context-type="linenumber">203</context></context-group> + <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> </trans-unit> - <trans-unit id="_msg783"> + <trans-unit id="_msg811"> <source xml:space="preserve">unknown</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">131</context></context-group> + <context-group purpose="location"><context context-type="linenumber">127</context></context-group> </trans-unit> - <trans-unit id="_msg784"> + <trans-unit id="_msg812"> <source xml:space="preserve">To</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">132</context></context-group> - <context-group purpose="location"><context context-type="linenumber">152</context></context-group> - <context-group purpose="location"><context context-type="linenumber">222</context></context-group> + <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> </trans-unit> - <trans-unit id="_msg785"> + <trans-unit id="_msg813"> <source xml:space="preserve">own address</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">134</context></context-group> + <context-group purpose="location"><context context-type="linenumber">130</context></context-group> </trans-unit> - <trans-unit id="_msg786"> + <trans-unit id="_msg814"> <source xml:space="preserve">watch-only</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">134</context></context-group> - <context-group purpose="location"><context context-type="linenumber">203</context></context-group> + <context-group purpose="location"><context context-type="linenumber">130</context></context-group> + <context-group purpose="location"><context context-type="linenumber">199</context></context-group> </trans-unit> - <trans-unit id="_msg787"> + <trans-unit id="_msg815"> <source xml:space="preserve">label</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">136</context></context-group> + <context-group purpose="location"><context context-type="linenumber">132</context></context-group> </trans-unit> - <trans-unit id="_msg788"> + <trans-unit id="_msg816"> <source xml:space="preserve">Credit</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">172</context></context-group> - <context-group purpose="location"><context context-type="linenumber">184</context></context-group> - <context-group purpose="location"><context context-type="linenumber">238</context></context-group> - <context-group purpose="location"><context context-type="linenumber">268</context></context-group> - <context-group purpose="location"><context context-type="linenumber">328</context></context-group> + <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> </trans-unit> <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">174</context></context-group> - <trans-unit id="_msg789[0]" approved="yes"> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> + <trans-unit id="_msg817[0]" approved="yes"> <source xml:space="preserve">matures in %n more block(s)</source> <target xml:space="preserve">matures in %n more block</target> </trans-unit> - <trans-unit id="_msg789[1]" approved="yes"> + <trans-unit id="_msg817[1]" approved="yes"> <source xml:space="preserve">matures in %n more block(s)</source> <target xml:space="preserve">matures in %n more blocks</target> </trans-unit> </group> - <trans-unit id="_msg790"> + <trans-unit id="_msg818"> <source xml:space="preserve">not accepted</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">176</context></context-group> + <context-group purpose="location"><context context-type="linenumber">172</context></context-group> </trans-unit> - <trans-unit id="_msg791"> + <trans-unit id="_msg819"> <source xml:space="preserve">Debit</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">236</context></context-group> - <context-group purpose="location"><context context-type="linenumber">262</context></context-group> - <context-group purpose="location"><context context-type="linenumber">325</context></context-group> + <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> </trans-unit> - <trans-unit id="_msg792"> + <trans-unit id="_msg820"> <source xml:space="preserve">Total debit</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">246</context></context-group> + <context-group purpose="location"><context context-type="linenumber">242</context></context-group> </trans-unit> - <trans-unit id="_msg793"> + <trans-unit id="_msg821"> <source xml:space="preserve">Total credit</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">247</context></context-group> + <context-group purpose="location"><context context-type="linenumber">243</context></context-group> </trans-unit> - <trans-unit id="_msg794"> + <trans-unit id="_msg822"> <source xml:space="preserve">Transaction fee</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">252</context></context-group> + <context-group purpose="location"><context context-type="linenumber">248</context></context-group> </trans-unit> - <trans-unit id="_msg795"> + <trans-unit id="_msg823"> <source xml:space="preserve">Net amount</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">274</context></context-group> + <context-group purpose="location"><context context-type="linenumber">270</context></context-group> </trans-unit> - <trans-unit id="_msg796"> + <trans-unit id="_msg824"> <source xml:space="preserve">Message</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">280</context></context-group> - <context-group purpose="location"><context context-type="linenumber">292</context></context-group> + <context-group purpose="location"><context context-type="linenumber">276</context></context-group> + <context-group purpose="location"><context context-type="linenumber">288</context></context-group> </trans-unit> - <trans-unit id="_msg797"> + <trans-unit id="_msg825"> <source xml:space="preserve">Comment</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">282</context></context-group> + <context-group purpose="location"><context context-type="linenumber">278</context></context-group> </trans-unit> - <trans-unit id="_msg798"> + <trans-unit id="_msg826"> <source xml:space="preserve">Transaction ID</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">284</context></context-group> + <context-group purpose="location"><context context-type="linenumber">280</context></context-group> </trans-unit> - <trans-unit id="_msg799"> + <trans-unit id="_msg827"> <source xml:space="preserve">Transaction total size</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">285</context></context-group> + <context-group purpose="location"><context context-type="linenumber">281</context></context-group> </trans-unit> - <trans-unit id="_msg800"> + <trans-unit id="_msg828"> <source xml:space="preserve">Transaction virtual size</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">286</context></context-group> + <context-group purpose="location"><context context-type="linenumber">282</context></context-group> </trans-unit> - <trans-unit id="_msg801"> + <trans-unit id="_msg829"> <source xml:space="preserve">Output index</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">287</context></context-group> + <context-group purpose="location"><context context-type="linenumber">283</context></context-group> </trans-unit> - <trans-unit id="_msg802"> + <trans-unit id="_msg830"> <source xml:space="preserve"> (Certificate was not verified)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">303</context></context-group> + <context-group purpose="location"><context context-type="linenumber">299</context></context-group> </trans-unit> - <trans-unit id="_msg803"> + <trans-unit id="_msg831"> <source xml:space="preserve">Merchant</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">306</context></context-group> + <context-group purpose="location"><context context-type="linenumber">302</context></context-group> </trans-unit> - <trans-unit id="_msg804"> + <trans-unit id="_msg832"> <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 "not accepted" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">314</context></context-group> + <context-group purpose="location"><context context-type="linenumber">310</context></context-group> </trans-unit> - <trans-unit id="_msg805"> + <trans-unit id="_msg833"> <source xml:space="preserve">Debug information</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">322</context></context-group> + <context-group purpose="location"><context context-type="linenumber">318</context></context-group> </trans-unit> - <trans-unit id="_msg806"> + <trans-unit id="_msg834"> <source xml:space="preserve">Transaction</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">330</context></context-group> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> </trans-unit> - <trans-unit id="_msg807"> + <trans-unit id="_msg835"> <source xml:space="preserve">Inputs</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">333</context></context-group> + <context-group purpose="location"><context context-type="linenumber">329</context></context-group> </trans-unit> - <trans-unit id="_msg808"> + <trans-unit id="_msg836"> <source xml:space="preserve">Amount</source> <target xml:space="preserve" state="needs-review-translation">Amount</target> - <context-group purpose="location"><context context-type="linenumber">354</context></context-group> + <context-group purpose="location"><context context-type="linenumber">350</context></context-group> </trans-unit> - <trans-unit id="_msg809"> + <trans-unit id="_msg837"> <source xml:space="preserve">true</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">355</context></context-group> - <context-group purpose="location"><context context-type="linenumber">356</context></context-group> + <context-group purpose="location"><context context-type="linenumber">351</context></context-group> + <context-group purpose="location"><context context-type="linenumber">352</context></context-group> </trans-unit> - <trans-unit id="_msg810"> + <trans-unit id="_msg838"> <source xml:space="preserve">false</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">355</context></context-group> - <context-group purpose="location"><context context-type="linenumber">356</context></context-group> + <context-group purpose="location"><context context-type="linenumber">351</context></context-group> + <context-group purpose="location"><context context-type="linenumber">352</context></context-group> </trans-unit> </group> </body></file> <file original="../forms/transactiondescdialog.ui" datatype="x-trolltech-designer-ui" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionDescDialog"> - <trans-unit id="_msg811" approved="yes"> + <trans-unit id="_msg839" approved="yes"> <source xml:space="preserve">This pane shows a detailed description of the transaction</source> <target xml:space="preserve">This pane shows a detailed description of the transaction</target> <context-group purpose="location"><context context-type="linenumber">20</context></context-group> @@ -4486,7 +4684,7 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../transactiondescdialog.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionDescDialog"> - <trans-unit id="_msg812"> + <trans-unit id="_msg840"> <source xml:space="preserve">Details for %1</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">18</context></context-group> @@ -4495,1301 +4693,1332 @@ Note: Since the fee is calculated on a per-byte basis, a fee rate of "100 </body></file> <file original="../transactiontablemodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionTableModel"> - <trans-unit id="_msg813"> + <trans-unit id="_msg841"> <source xml:space="preserve">Date</source> <target xml:space="preserve" state="needs-review-translation">Date</target> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <trans-unit id="_msg814"> + <trans-unit id="_msg842"> <source xml:space="preserve">Type</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <trans-unit id="_msg815"> + <trans-unit id="_msg843"> <source xml:space="preserve">Label</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> - <group restype="x-gettext-plurals"> - <context-group purpose="location"><context context-type="linenumber">320</context></context-group> - <trans-unit id="_msg816[0]" approved="yes"> - <source xml:space="preserve">Open for %n more block(s)</source> - <target xml:space="preserve">Open for %n more block</target> - </trans-unit> - <trans-unit id="_msg816[1]" approved="yes"> - <source xml:space="preserve">Open for %n more block(s)</source> - <target xml:space="preserve">Open for %n more blocks</target> - </trans-unit> - </group> - <trans-unit id="_msg817"> - <source xml:space="preserve">Open until %1</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">323</context></context-group> - </trans-unit> - <trans-unit id="_msg818"> + <trans-unit id="_msg844"> <source xml:space="preserve">Unconfirmed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + <context-group purpose="location"><context context-type="linenumber">320</context></context-group> </trans-unit> - <trans-unit id="_msg819"> + <trans-unit id="_msg845"> <source xml:space="preserve">Abandoned</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + <context-group purpose="location"><context context-type="linenumber">323</context></context-group> </trans-unit> - <trans-unit id="_msg820"> + <trans-unit id="_msg846"> <source xml:space="preserve">Confirming (%1 of %2 recommended confirmations)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">332</context></context-group> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> </trans-unit> - <trans-unit id="_msg821"> + <trans-unit id="_msg847"> <source xml:space="preserve">Confirmed (%1 confirmations)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + <context-group purpose="location"><context context-type="linenumber">329</context></context-group> </trans-unit> - <trans-unit id="_msg822"> + <trans-unit id="_msg848"> <source xml:space="preserve">Conflicted</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">338</context></context-group> + <context-group purpose="location"><context context-type="linenumber">332</context></context-group> </trans-unit> - <trans-unit id="_msg823"> + <trans-unit id="_msg849"> <source xml:space="preserve">Immature (%1 confirmations, will be available after %2)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">341</context></context-group> + <context-group purpose="location"><context context-type="linenumber">335</context></context-group> </trans-unit> - <trans-unit id="_msg824"> + <trans-unit id="_msg850"> <source xml:space="preserve">Generated but not accepted</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">344</context></context-group> + <context-group purpose="location"><context context-type="linenumber">338</context></context-group> </trans-unit> - <trans-unit id="_msg825"> + <trans-unit id="_msg851"> <source xml:space="preserve">Received with</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">383</context></context-group> + <context-group purpose="location"><context context-type="linenumber">377</context></context-group> </trans-unit> - <trans-unit id="_msg826"> + <trans-unit id="_msg852"> <source xml:space="preserve">Received from</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">385</context></context-group> + <context-group purpose="location"><context context-type="linenumber">379</context></context-group> </trans-unit> - <trans-unit id="_msg827"> + <trans-unit id="_msg853"> <source xml:space="preserve">Sent to</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">388</context></context-group> + <context-group purpose="location"><context context-type="linenumber">382</context></context-group> </trans-unit> - <trans-unit id="_msg828"> + <trans-unit id="_msg854"> <source xml:space="preserve">Payment to yourself</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">390</context></context-group> + <context-group purpose="location"><context context-type="linenumber">384</context></context-group> </trans-unit> - <trans-unit id="_msg829"> + <trans-unit id="_msg855"> <source xml:space="preserve">Mined</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">392</context></context-group> + <context-group purpose="location"><context context-type="linenumber">386</context></context-group> </trans-unit> - <trans-unit id="_msg830"> + <trans-unit id="_msg856"> <source xml:space="preserve">watch-only</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">420</context></context-group> + <context-group purpose="location"><context context-type="linenumber">414</context></context-group> </trans-unit> - <trans-unit id="_msg831"> + <trans-unit id="_msg857"> <source xml:space="preserve">(n/a)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">436</context></context-group> + <context-group purpose="location"><context context-type="linenumber">430</context></context-group> </trans-unit> - <trans-unit id="_msg832"> + <trans-unit id="_msg858"> <source xml:space="preserve">(no label)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">646</context></context-group> + <context-group purpose="location"><context context-type="linenumber">637</context></context-group> </trans-unit> - <trans-unit id="_msg833"> + <trans-unit id="_msg859"> <source xml:space="preserve">Transaction status. Hover over this field to show number of confirmations.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">685</context></context-group> + <context-group purpose="location"><context context-type="linenumber">676</context></context-group> </trans-unit> - <trans-unit id="_msg834"> + <trans-unit id="_msg860"> <source xml:space="preserve">Date and time that the transaction was received.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">687</context></context-group> + <context-group purpose="location"><context context-type="linenumber">678</context></context-group> </trans-unit> - <trans-unit id="_msg835"> + <trans-unit id="_msg861"> <source xml:space="preserve">Type of transaction.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">689</context></context-group> + <context-group purpose="location"><context context-type="linenumber">680</context></context-group> </trans-unit> - <trans-unit id="_msg836"> + <trans-unit id="_msg862"> <source xml:space="preserve">Whether or not a watch-only address is involved in this transaction.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">691</context></context-group> + <context-group purpose="location"><context context-type="linenumber">682</context></context-group> </trans-unit> - <trans-unit id="_msg837"> + <trans-unit id="_msg863"> <source xml:space="preserve">User-defined intent/purpose of the transaction.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">693</context></context-group> + <context-group purpose="location"><context context-type="linenumber">684</context></context-group> </trans-unit> - <trans-unit id="_msg838"> + <trans-unit id="_msg864"> <source xml:space="preserve">Amount removed from or added to balance.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">695</context></context-group> + <context-group purpose="location"><context context-type="linenumber">686</context></context-group> </trans-unit> </group> </body></file> <file original="../transactionview.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="TransactionView"> - <trans-unit id="_msg839"> + <trans-unit id="_msg865"> <source xml:space="preserve">All</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">70</context></context-group> - <context-group purpose="location"><context context-type="linenumber">86</context></context-group> + <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="_msg840"> + <trans-unit id="_msg866"> <source xml:space="preserve">Today</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">71</context></context-group> + <context-group purpose="location"><context context-type="linenumber">74</context></context-group> </trans-unit> - <trans-unit id="_msg841"> + <trans-unit id="_msg867"> <source xml:space="preserve">This week</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">72</context></context-group> + <context-group purpose="location"><context context-type="linenumber">75</context></context-group> </trans-unit> - <trans-unit id="_msg842"> + <trans-unit id="_msg868"> <source xml:space="preserve">This month</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">73</context></context-group> + <context-group purpose="location"><context context-type="linenumber">76</context></context-group> </trans-unit> - <trans-unit id="_msg843"> + <trans-unit id="_msg869"> <source xml:space="preserve">Last month</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">74</context></context-group> + <context-group purpose="location"><context context-type="linenumber">77</context></context-group> </trans-unit> - <trans-unit id="_msg844"> + <trans-unit id="_msg870"> <source xml:space="preserve">This year</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">75</context></context-group> + <context-group purpose="location"><context context-type="linenumber">78</context></context-group> </trans-unit> - <trans-unit id="_msg845"> + <trans-unit id="_msg871"> <source xml:space="preserve">Received with</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">87</context></context-group> + <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> - <trans-unit id="_msg846"> + <trans-unit id="_msg872"> <source xml:space="preserve">Sent to</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">89</context></context-group> + <context-group purpose="location"><context context-type="linenumber">92</context></context-group> </trans-unit> - <trans-unit id="_msg847"> + <trans-unit id="_msg873"> <source xml:space="preserve">To yourself</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + <context-group purpose="location"><context context-type="linenumber">94</context></context-group> </trans-unit> - <trans-unit id="_msg848"> + <trans-unit id="_msg874"> <source xml:space="preserve">Mined</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">92</context></context-group> + <context-group purpose="location"><context context-type="linenumber">95</context></context-group> </trans-unit> - <trans-unit id="_msg849"> + <trans-unit id="_msg875"> <source xml:space="preserve">Other</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">93</context></context-group> + <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> - <trans-unit id="_msg850"> + <trans-unit id="_msg876"> <source xml:space="preserve">Enter address, transaction id, or label to search</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + <context-group purpose="location"><context context-type="linenumber">101</context></context-group> </trans-unit> - <trans-unit id="_msg851"> + <trans-unit id="_msg877"> <source xml:space="preserve">Min amount</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">102</context></context-group> + <context-group purpose="location"><context context-type="linenumber">105</context></context-group> </trans-unit> - <trans-unit id="_msg852"> + <trans-unit id="_msg878"> <source xml:space="preserve">Range…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">76</context></context-group> + <context-group purpose="location"><context context-type="linenumber">79</context></context-group> </trans-unit> - <trans-unit id="_msg853"> + <trans-unit id="_msg879"> <source xml:space="preserve">&Copy address</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">166</context></context-group> + <context-group purpose="location"><context context-type="linenumber">169</context></context-group> </trans-unit> - <trans-unit id="_msg854"> + <trans-unit id="_msg880"> <source xml:space="preserve">Copy &label</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">167</context></context-group> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> </trans-unit> - <trans-unit id="_msg855"> + <trans-unit id="_msg881"> <source xml:space="preserve">Copy &amount</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">168</context></context-group> + <context-group purpose="location"><context context-type="linenumber">171</context></context-group> </trans-unit> - <trans-unit id="_msg856"> + <trans-unit id="_msg882"> <source xml:space="preserve">Copy transaction &ID</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">169</context></context-group> + <context-group purpose="location"><context context-type="linenumber">172</context></context-group> </trans-unit> - <trans-unit id="_msg857"> + <trans-unit id="_msg883"> <source xml:space="preserve">Copy &raw transaction</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">170</context></context-group> + <context-group purpose="location"><context context-type="linenumber">173</context></context-group> </trans-unit> - <trans-unit id="_msg858"> + <trans-unit id="_msg884"> <source xml:space="preserve">Copy full transaction &details</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">171</context></context-group> + <context-group purpose="location"><context context-type="linenumber">174</context></context-group> </trans-unit> - <trans-unit id="_msg859"> + <trans-unit id="_msg885"> <source xml:space="preserve">&Show transaction details</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">172</context></context-group> + <context-group purpose="location"><context context-type="linenumber">175</context></context-group> </trans-unit> - <trans-unit id="_msg860"> + <trans-unit id="_msg886"> <source xml:space="preserve">Increase transaction &fee</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">174</context></context-group> + <context-group purpose="location"><context context-type="linenumber">177</context></context-group> </trans-unit> - <trans-unit id="_msg861"> + <trans-unit id="_msg887"> <source xml:space="preserve">A&bandon transaction</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">177</context></context-group> + <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg862"> + <trans-unit id="_msg888"> <source xml:space="preserve">&Edit address label</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">178</context></context-group> + <context-group purpose="location"><context context-type="linenumber">181</context></context-group> </trans-unit> - <trans-unit id="_msg863"> + <trans-unit id="_msg889"> + <source xml:space="preserve">Show in %1</source> + <target xml:space="preserve"></target> + <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"> <source xml:space="preserve">Export Transaction History</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">352</context></context-group> + <context-group purpose="location"><context context-type="linenumber">359</context></context-group> </trans-unit> - <trans-unit id="_msg864"> + <trans-unit id="_msg891"> <source xml:space="preserve">Comma separated file</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">355</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> + <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="_msg865"> + <trans-unit id="_msg892"> <source xml:space="preserve">Confirmed</source> <target xml:space="preserve" state="needs-review-translation">Confirmed</target> - <context-group purpose="location"><context context-type="linenumber">364</context></context-group> + <context-group purpose="location"><context context-type="linenumber">371</context></context-group> </trans-unit> - <trans-unit id="_msg866"> + <trans-unit id="_msg893"> <source xml:space="preserve">Watch-only</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">366</context></context-group> + <context-group purpose="location"><context context-type="linenumber">373</context></context-group> </trans-unit> - <trans-unit id="_msg867"> + <trans-unit id="_msg894"> <source xml:space="preserve">Date</source> <target xml:space="preserve" state="needs-review-translation">Date</target> - <context-group purpose="location"><context context-type="linenumber">367</context></context-group> + <context-group purpose="location"><context context-type="linenumber">374</context></context-group> </trans-unit> - <trans-unit id="_msg868"> + <trans-unit id="_msg895"> <source xml:space="preserve">Type</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">368</context></context-group> + <context-group purpose="location"><context context-type="linenumber">375</context></context-group> </trans-unit> - <trans-unit id="_msg869"> + <trans-unit id="_msg896"> <source xml:space="preserve">Label</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">369</context></context-group> + <context-group purpose="location"><context context-type="linenumber">376</context></context-group> </trans-unit> - <trans-unit id="_msg870"> + <trans-unit id="_msg897"> <source xml:space="preserve">Address</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">370</context></context-group> + <context-group purpose="location"><context context-type="linenumber">377</context></context-group> </trans-unit> - <trans-unit id="_msg871"> + <trans-unit id="_msg898"> <source xml:space="preserve">ID</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">372</context></context-group> + <context-group purpose="location"><context context-type="linenumber">379</context></context-group> </trans-unit> - <trans-unit id="_msg872"> + <trans-unit id="_msg899"> <source xml:space="preserve">Exporting Failed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">375</context></context-group> + <context-group purpose="location"><context context-type="linenumber">382</context></context-group> </trans-unit> - <trans-unit id="_msg873"> + <trans-unit id="_msg900"> <source xml:space="preserve">There was an error trying to save the transaction history to %1.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">375</context></context-group> + <context-group purpose="location"><context context-type="linenumber">382</context></context-group> </trans-unit> - <trans-unit id="_msg874"> + <trans-unit id="_msg901"> <source xml:space="preserve">Exporting Successful</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">379</context></context-group> + <context-group purpose="location"><context context-type="linenumber">386</context></context-group> </trans-unit> - <trans-unit id="_msg875"> + <trans-unit id="_msg902"> <source xml:space="preserve">The transaction history was successfully saved to %1.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">379</context></context-group> + <context-group purpose="location"><context context-type="linenumber">386</context></context-group> </trans-unit> - <trans-unit id="_msg876"> + <trans-unit id="_msg903"> <source xml:space="preserve">Range:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">551</context></context-group> + <context-group purpose="location"><context context-type="linenumber">558</context></context-group> </trans-unit> - <trans-unit id="_msg877"> + <trans-unit id="_msg904"> <source xml:space="preserve">to</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">559</context></context-group> + <context-group purpose="location"><context context-type="linenumber">566</context></context-group> </trans-unit> </group> </body></file> <file original="../walletframe.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="WalletFrame"> - <trans-unit id="_msg878"> + <trans-unit id="_msg905"> <source xml:space="preserve">No wallet has been loaded. Go to File > Open Wallet to load a wallet. - OR -</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">35</context></context-group> + <context-group purpose="location"><context context-type="linenumber">42</context></context-group> </trans-unit> - <trans-unit id="_msg879"> + <trans-unit id="_msg906"> <source xml:space="preserve">Create a new wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">40</context></context-group> + <context-group purpose="location"><context context-type="linenumber">47</context></context-group> + </trans-unit> + <trans-unit id="_msg907"> + <source xml:space="preserve">Error</source> + <target xml:space="preserve" state="needs-review-translation">Error</target> + <context-group purpose="location"><context context-type="linenumber">201</context></context-group> + <context-group purpose="location"><context context-type="linenumber">210</context></context-group> + <context-group purpose="location"><context context-type="linenumber">220</context></context-group> + </trans-unit> + <trans-unit id="_msg908"> + <source xml:space="preserve">Unable to decode PSBT from clipboard (invalid base64)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">201</context></context-group> + </trans-unit> + <trans-unit id="_msg909"> + <source xml:space="preserve">Load Transaction Data</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + </trans-unit> + <trans-unit id="_msg910"> + <source xml:space="preserve">Partially Signed Transaction (*.psbt)</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">207</context></context-group> + </trans-unit> + <trans-unit id="_msg911"> + <source xml:space="preserve">PSBT file must be smaller than 100 MiB</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">210</context></context-group> + </trans-unit> + <trans-unit id="_msg912"> + <source xml:space="preserve">Unable to decode PSBT</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">220</context></context-group> </trans-unit> </group> </body></file> <file original="../walletmodel.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="WalletModel"> - <trans-unit id="_msg880"> + <trans-unit id="_msg913"> <source xml:space="preserve">Send Coins</source> <target xml:space="preserve" state="needs-review-translation">Send Coins</target> - <context-group purpose="location"><context context-type="linenumber">218</context></context-group> + <context-group purpose="location"><context context-type="linenumber">221</context></context-group> </trans-unit> - <trans-unit id="_msg881"> + <trans-unit id="_msg914"> <source xml:space="preserve">Fee bump error</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">478</context></context-group> - <context-group purpose="location"><context context-type="linenumber">530</context></context-group> - <context-group purpose="location"><context context-type="linenumber">543</context></context-group> + <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> </trans-unit> - <trans-unit id="_msg882"> + <trans-unit id="_msg915"> <source xml:space="preserve">Increasing transaction fee failed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">478</context></context-group> + <context-group purpose="location"><context context-type="linenumber">481</context></context-group> </trans-unit> - <trans-unit id="_msg883"> + <trans-unit id="_msg916"> <source xml:space="preserve">Do you want to increase the fee?</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">486</context></context-group> + <context-group purpose="location"><context context-type="linenumber">488</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="_msg884"> - <source xml:space="preserve">Do you want to draft a transaction with fee increase?</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">486</context></context-group> - </trans-unit> - <trans-unit id="_msg885"> + <trans-unit id="_msg917"> <source xml:space="preserve">Current fee:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">490</context></context-group> + <context-group purpose="location"><context context-type="linenumber">492</context></context-group> </trans-unit> - <trans-unit id="_msg886"> + <trans-unit id="_msg918"> <source xml:space="preserve">Increase:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">494</context></context-group> + <context-group purpose="location"><context context-type="linenumber">496</context></context-group> </trans-unit> - <trans-unit id="_msg887"> + <trans-unit id="_msg919"> <source xml:space="preserve">New fee:</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">498</context></context-group> + <context-group purpose="location"><context context-type="linenumber">500</context></context-group> </trans-unit> - <trans-unit id="_msg888"> + <trans-unit id="_msg920"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">506</context></context-group> + <context-group purpose="location"><context context-type="linenumber">508</context></context-group> </trans-unit> - <trans-unit id="_msg889"> + <trans-unit id="_msg921"> <source xml:space="preserve">Confirm fee bump</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">509</context></context-group> + <context-group purpose="location"><context context-type="linenumber">511</context></context-group> </trans-unit> - <trans-unit id="_msg890"> + <trans-unit id="_msg922"> <source xml:space="preserve">Can't draft transaction.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">530</context></context-group> + <context-group purpose="location"><context context-type="linenumber">533</context></context-group> </trans-unit> - <trans-unit id="_msg891"> + <trans-unit id="_msg923"> <source xml:space="preserve">PSBT copied</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">537</context></context-group> + <context-group purpose="location"><context context-type="linenumber">540</context></context-group> </trans-unit> - <trans-unit id="_msg892"> + <trans-unit id="_msg924"> <source xml:space="preserve">Can't sign transaction.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">543</context></context-group> + <context-group purpose="location"><context context-type="linenumber">548</context></context-group> </trans-unit> - <trans-unit id="_msg893"> + <trans-unit id="_msg925"> <source xml:space="preserve">Could not commit transaction</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">548</context></context-group> + <context-group purpose="location"><context context-type="linenumber">553</context></context-group> </trans-unit> - <trans-unit id="_msg894"> + <trans-unit id="_msg926"> <source xml:space="preserve">Can't display address</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">562</context></context-group> + <context-group purpose="location"><context context-type="linenumber">567</context></context-group> </trans-unit> - <trans-unit id="_msg895"> + <trans-unit id="_msg927"> <source xml:space="preserve">default wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">580</context></context-group> + <context-group purpose="location"><context context-type="linenumber">585</context></context-group> </trans-unit> </group> </body></file> <file original="../walletview.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="WalletView"> - <trans-unit id="_msg896"> + <trans-unit id="_msg928"> <source xml:space="preserve">&Export</source> <target xml:space="preserve" state="needs-review-translation">&Export</target> - <context-group purpose="location"><context context-type="linenumber">51</context></context-group> + <context-group purpose="location"><context context-type="linenumber">52</context></context-group> </trans-unit> - <trans-unit id="_msg897"> + <trans-unit id="_msg929"> <source xml:space="preserve">Export the data in the current tab to a file</source> <target xml:space="preserve" state="needs-review-translation">Export the data in the current tab to a file</target> - <context-group purpose="location"><context context-type="linenumber">52</context></context-group> - </trans-unit> - <trans-unit id="_msg898"> - <source xml:space="preserve">Error</source> - <target xml:space="preserve" state="needs-review-translation">Error</target> - <context-group purpose="location"><context context-type="linenumber">217</context></context-group> - <context-group purpose="location"><context context-type="linenumber">226</context></context-group> - <context-group purpose="location"><context context-type="linenumber">236</context></context-group> - </trans-unit> - <trans-unit id="_msg899"> - <source xml:space="preserve">Unable to decode PSBT from clipboard (invalid base64)</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">217</context></context-group> - </trans-unit> - <trans-unit id="_msg900"> - <source xml:space="preserve">Load Transaction Data</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">222</context></context-group> - </trans-unit> - <trans-unit id="_msg901"> - <source xml:space="preserve">Partially Signed Transaction (*.psbt)</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">223</context></context-group> - </trans-unit> - <trans-unit id="_msg902"> - <source xml:space="preserve">PSBT file must be smaller than 100 MiB</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">226</context></context-group> - </trans-unit> - <trans-unit id="_msg903"> - <source xml:space="preserve">Unable to decode PSBT</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">236</context></context-group> + <context-group purpose="location"><context context-type="linenumber">53</context></context-group> </trans-unit> - <trans-unit id="_msg904"> + <trans-unit id="_msg930"> <source xml:space="preserve">Backup Wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">275</context></context-group> + <context-group purpose="location"><context context-type="linenumber">217</context></context-group> </trans-unit> - <trans-unit id="_msg905"> + <trans-unit id="_msg931"> <source xml:space="preserve">Wallet Data</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">277</context></context-group> + <context-group purpose="location"><context context-type="linenumber">219</context></context-group> <note annotates="source" from="developer">Name of the wallet data file format.</note> </trans-unit> - <trans-unit id="_msg906"> + <trans-unit id="_msg932"> <source xml:space="preserve">Backup Failed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">283</context></context-group> + <context-group purpose="location"><context context-type="linenumber">225</context></context-group> </trans-unit> - <trans-unit id="_msg907"> + <trans-unit id="_msg933"> <source xml:space="preserve">There was an error trying to save the wallet data to %1.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">283</context></context-group> + <context-group purpose="location"><context context-type="linenumber">225</context></context-group> </trans-unit> - <trans-unit id="_msg908"> + <trans-unit id="_msg934"> <source xml:space="preserve">Backup Successful</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">287</context></context-group> + <context-group purpose="location"><context context-type="linenumber">229</context></context-group> </trans-unit> - <trans-unit id="_msg909"> + <trans-unit id="_msg935"> <source xml:space="preserve">The wallet data was successfully saved to %1.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">287</context></context-group> + <context-group purpose="location"><context context-type="linenumber">229</context></context-group> </trans-unit> - <trans-unit id="_msg910"> + <trans-unit id="_msg936"> <source xml:space="preserve">Cancel</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">331</context></context-group> + <context-group purpose="location"><context context-type="linenumber">264</context></context-group> </trans-unit> </group> </body></file> <file original="../bitcoinstrings.cpp" datatype="cpp" source-language="en" target-language="en"><body> <group restype="x-trolltech-linguist-context" resname="bitcoin-core"> - <trans-unit id="_msg911"> + <trans-unit id="_msg937"> <source xml:space="preserve">The %s developers</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">12</context></context-group> </trans-unit> - <trans-unit id="_msg912"> + <trans-unit id="_msg938"> <source xml:space="preserve">%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">13</context></context-group> </trans-unit> - <trans-unit id="_msg913"> + <trans-unit id="_msg939"> <source xml:space="preserve">-maxtxfee is set very high! Fees this large could be paid on a single transaction.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">16</context></context-group> </trans-unit> - <trans-unit id="_msg914"> + <trans-unit id="_msg940"> <source xml:space="preserve">Cannot downgrade wallet from version %i to version %i. Wallet version unchanged.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">19</context></context-group> </trans-unit> - <trans-unit id="_msg915"> + <trans-unit id="_msg941"> <source xml:space="preserve">Cannot obtain a lock on data directory %s. %s is probably already running.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">22</context></context-group> </trans-unit> - <trans-unit id="_msg916"> + <trans-unit id="_msg942"> <source xml:space="preserve">Cannot provide specific connections and have addrman find outgoing connections at the same.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">24</context></context-group> </trans-unit> - <trans-unit id="_msg917"> + <trans-unit id="_msg943"> <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> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">27</context></context-group> </trans-unit> - <trans-unit id="_msg918"> + <trans-unit id="_msg944"> <source xml:space="preserve">Distributed under the MIT software license, see the accompanying file %s or %s</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">31</context></context-group> </trans-unit> - <trans-unit id="_msg919"> + <trans-unit id="_msg945"> <source xml:space="preserve">Error reading %s! All keys read correctly, but transaction data or address book entries might be missing or incorrect.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">34</context></context-group> </trans-unit> - <trans-unit id="_msg920"> - <source xml:space="preserve">Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> + <trans-unit id="_msg946"> + <source xml:space="preserve">Error reading %s! Transaction data may be missing or incorrect. Rescanning wallet.</source> <target xml:space="preserve"></target> <context-group purpose="location"><context context-type="linenumber">37</context></context-group> </trans-unit> - <trans-unit id="_msg921"> + <trans-unit id="_msg947"> + <source xml:space="preserve">Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">40</context></context-group> + </trans-unit> + <trans-unit id="_msg948"> <source xml:space="preserve">Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">39</context></context-group> + <context-group purpose="location"><context context-type="linenumber">42</context></context-group> </trans-unit> - <trans-unit id="_msg922"> + <trans-unit id="_msg949"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">41</context></context-group> + <context-group purpose="location"><context context-type="linenumber">44</context></context-group> </trans-unit> - <trans-unit id="_msg923"> + <trans-unit id="_msg950"> <source xml:space="preserve">Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">44</context></context-group> + <context-group purpose="location"><context context-type="linenumber">47</context></context-group> </trans-unit> - <trans-unit id="_msg924"> + <trans-unit id="_msg951"> <source xml:space="preserve">Error: Listening for incoming connections failed (listen returned error %s)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">47</context></context-group> + <context-group purpose="location"><context context-type="linenumber">50</context></context-group> </trans-unit> - <trans-unit id="_msg925"> + <trans-unit id="_msg952"> <source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">49</context></context-group> + <context-group purpose="location"><context context-type="linenumber">52</context></context-group> </trans-unit> - <trans-unit id="_msg926"> + <trans-unit id="_msg953"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">52</context></context-group> + <context-group purpose="location"><context context-type="linenumber">55</context></context-group> </trans-unit> - <trans-unit id="_msg927"> + <trans-unit id="_msg954"> <source xml:space="preserve">Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">55</context></context-group> + <context-group purpose="location"><context context-type="linenumber">58</context></context-group> </trans-unit> - <trans-unit id="_msg928"> + <trans-unit id="_msg955"> + <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> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">61</context></context-group> + </trans-unit> + <trans-unit id="_msg956"> <source xml:space="preserve">More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">58</context></context-group> + <context-group purpose="location"><context context-type="linenumber">65</context></context-group> </trans-unit> - <trans-unit id="_msg929"> + <trans-unit id="_msg957"> <source xml:space="preserve">No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">61</context></context-group> + <context-group purpose="location"><context context-type="linenumber">68</context></context-group> </trans-unit> - <trans-unit id="_msg930"> + <trans-unit id="_msg958"> <source xml:space="preserve">No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">64</context></context-group> + <context-group purpose="location"><context context-type="linenumber">71</context></context-group> </trans-unit> - <trans-unit id="_msg931"> + <trans-unit id="_msg959"> <source xml:space="preserve">No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">66</context></context-group> + <context-group purpose="location"><context context-type="linenumber">73</context></context-group> </trans-unit> - <trans-unit id="_msg932"> + <trans-unit id="_msg960"> <source xml:space="preserve">Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">69</context></context-group> + <context-group purpose="location"><context context-type="linenumber">76</context></context-group> </trans-unit> - <trans-unit id="_msg933"> + <trans-unit id="_msg961"> <source xml:space="preserve">Please contribute if you find %s useful. Visit %s for further information about the software.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">72</context></context-group> + <context-group purpose="location"><context context-type="linenumber">79</context></context-group> </trans-unit> - <trans-unit id="_msg934"> + <trans-unit id="_msg962"> <source xml:space="preserve">Prune configured below the minimum of %d MiB. Please use a higher number.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">75</context></context-group> + <context-group purpose="location"><context context-type="linenumber">82</context></context-group> </trans-unit> - <trans-unit id="_msg935"> + <trans-unit id="_msg963"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">77</context></context-group> + <context-group purpose="location"><context context-type="linenumber">84</context></context-group> </trans-unit> - <trans-unit id="_msg936"> + <trans-unit id="_msg964"> <source xml:space="preserve">SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">80</context></context-group> + <context-group purpose="location"><context context-type="linenumber">87</context></context-group> </trans-unit> - <trans-unit id="_msg937"> + <trans-unit id="_msg965"> + <source xml:space="preserve">The -txindex upgrade started by a previous version can not be completed. Restart with the previous version or run a full -reindex.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">90</context></context-group> + </trans-unit> + <trans-unit id="_msg966"> <source xml:space="preserve">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</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">83</context></context-group> + <context-group purpose="location"><context context-type="linenumber">93</context></context-group> </trans-unit> - <trans-unit id="_msg938"> + <trans-unit id="_msg967"> + <source xml:space="preserve">The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">98</context></context-group> + </trans-unit> + <trans-unit id="_msg968"> <source xml:space="preserve">The transaction amount is too small to send after the fee has been deducted</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">88</context></context-group> + <context-group purpose="location"><context context-type="linenumber">102</context></context-group> </trans-unit> - <trans-unit id="_msg939"> + <trans-unit id="_msg969"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">90</context></context-group> + <context-group purpose="location"><context context-type="linenumber">104</context></context-group> </trans-unit> - <trans-unit id="_msg940"> + <trans-unit id="_msg970"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">94</context></context-group> + <context-group purpose="location"><context context-type="linenumber">108</context></context-group> </trans-unit> - <trans-unit id="_msg941"> + <trans-unit id="_msg971"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">97</context></context-group> + <context-group purpose="location"><context context-type="linenumber">111</context></context-group> </trans-unit> - <trans-unit id="_msg942"> + <trans-unit id="_msg972"> <source xml:space="preserve">This is the transaction fee you may discard if change is smaller than dust at this level</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">100</context></context-group> + <context-group purpose="location"><context context-type="linenumber">114</context></context-group> </trans-unit> - <trans-unit id="_msg943"> + <trans-unit id="_msg973"> <source xml:space="preserve">This is the transaction fee you may pay when fee estimates are not available.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">103</context></context-group> + <context-group purpose="location"><context context-type="linenumber">117</context></context-group> </trans-unit> - <trans-unit id="_msg944"> + <trans-unit id="_msg974"> <source xml:space="preserve">Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">105</context></context-group> + <context-group purpose="location"><context context-type="linenumber">119</context></context-group> </trans-unit> - <trans-unit id="_msg945"> + <trans-unit id="_msg975"> <source xml:space="preserve">Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">108</context></context-group> + <context-group purpose="location"><context context-type="linenumber">122</context></context-group> </trans-unit> - <trans-unit id="_msg946"> + <trans-unit id="_msg976"> <source xml:space="preserve">Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">111</context></context-group> + <context-group purpose="location"><context context-type="linenumber">125</context></context-group> </trans-unit> - <trans-unit id="_msg947"> + <trans-unit id="_msg977"> <source xml:space="preserve">Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">114</context></context-group> + <context-group purpose="location"><context context-type="linenumber">128</context></context-group> </trans-unit> - <trans-unit id="_msg948"> + <trans-unit id="_msg978"> <source xml:space="preserve">Warning: Private keys detected in wallet {%s} with disabled private keys</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">117</context></context-group> + <context-group purpose="location"><context context-type="linenumber">131</context></context-group> </trans-unit> - <trans-unit id="_msg949"> + <trans-unit id="_msg979"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">119</context></context-group> + <context-group purpose="location"><context context-type="linenumber">133</context></context-group> </trans-unit> - <trans-unit id="_msg950"> + <trans-unit id="_msg980"> <source xml:space="preserve">Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">122</context></context-group> + <context-group purpose="location"><context context-type="linenumber">136</context></context-group> </trans-unit> - <trans-unit id="_msg951"> + <trans-unit id="_msg981"> <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> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">125</context></context-group> + <context-group purpose="location"><context context-type="linenumber">139</context></context-group> </trans-unit> - <trans-unit id="_msg952"> + <trans-unit id="_msg982"> <source xml:space="preserve">%s is set very high!</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">128</context></context-group> + <context-group purpose="location"><context context-type="linenumber">142</context></context-group> </trans-unit> - <trans-unit id="_msg953"> + <trans-unit id="_msg983"> <source xml:space="preserve">-maxmempool must be at least %d MB</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">129</context></context-group> + <context-group purpose="location"><context context-type="linenumber">143</context></context-group> </trans-unit> - <trans-unit id="_msg954"> + <trans-unit id="_msg984"> <source xml:space="preserve">A fatal internal error occurred, see debug.log for details</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">130</context></context-group> + <context-group purpose="location"><context context-type="linenumber">144</context></context-group> </trans-unit> - <trans-unit id="_msg955"> + <trans-unit id="_msg985"> <source xml:space="preserve">Cannot resolve -%s address: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">131</context></context-group> + <context-group purpose="location"><context context-type="linenumber">145</context></context-group> </trans-unit> - <trans-unit id="_msg956"> + <trans-unit id="_msg986"> + <source xml:space="preserve">Cannot set -forcednsseed to true when setting -dnsseed to false.</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">146</context></context-group> + </trans-unit> + <trans-unit id="_msg987"> <source xml:space="preserve">Cannot set -peerblockfilters without -blockfilterindex.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">132</context></context-group> + <context-group purpose="location"><context context-type="linenumber">147</context></context-group> </trans-unit> - <trans-unit id="_msg957"> + <trans-unit id="_msg988"> <source xml:space="preserve">Cannot write to data directory '%s'; check permissions.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">133</context></context-group> + <context-group purpose="location"><context context-type="linenumber">148</context></context-group> </trans-unit> - <trans-unit id="_msg958"> + <trans-unit id="_msg989"> <source xml:space="preserve">Change index out of range</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">134</context></context-group> + <context-group purpose="location"><context context-type="linenumber">149</context></context-group> </trans-unit> - <trans-unit id="_msg959"> + <trans-unit id="_msg990"> <source xml:space="preserve">Config setting for %s only applied on %s network when in [%s] section.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">135</context></context-group> + <context-group purpose="location"><context context-type="linenumber">150</context></context-group> </trans-unit> - <trans-unit id="_msg960"> + <trans-unit id="_msg991"> <source xml:space="preserve">Copyright (C) %i-%i</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">136</context></context-group> + <context-group purpose="location"><context context-type="linenumber">151</context></context-group> </trans-unit> - <trans-unit id="_msg961"> + <trans-unit id="_msg992"> <source xml:space="preserve">Corrupted block database detected</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">137</context></context-group> + <context-group purpose="location"><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg962"> + <trans-unit id="_msg993"> <source xml:space="preserve">Could not find asmap file %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">138</context></context-group> + <context-group purpose="location"><context context-type="linenumber">153</context></context-group> </trans-unit> - <trans-unit id="_msg963"> + <trans-unit id="_msg994"> <source xml:space="preserve">Could not parse asmap file %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">139</context></context-group> + <context-group purpose="location"><context context-type="linenumber">154</context></context-group> </trans-unit> - <trans-unit id="_msg964"> + <trans-unit id="_msg995"> <source xml:space="preserve">Disk space is too low!</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">140</context></context-group> + <context-group purpose="location"><context context-type="linenumber">155</context></context-group> </trans-unit> - <trans-unit id="_msg965"> + <trans-unit id="_msg996"> <source xml:space="preserve">Do you want to rebuild the block database now?</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">141</context></context-group> + <context-group purpose="location"><context context-type="linenumber">156</context></context-group> </trans-unit> - <trans-unit id="_msg966"> + <trans-unit id="_msg997"> <source xml:space="preserve">Done loading</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">142</context></context-group> + <context-group purpose="location"><context context-type="linenumber">157</context></context-group> </trans-unit> - <trans-unit id="_msg967"> + <trans-unit id="_msg998"> <source xml:space="preserve">Dump file %s does not exist.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">143</context></context-group> + <context-group purpose="location"><context context-type="linenumber">158</context></context-group> </trans-unit> - <trans-unit id="_msg968"> + <trans-unit id="_msg999"> <source xml:space="preserve">Error creating %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">144</context></context-group> + <context-group purpose="location"><context context-type="linenumber">159</context></context-group> </trans-unit> - <trans-unit id="_msg969"> + <trans-unit id="_msg1000"> <source xml:space="preserve">Error initializing block database</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">145</context></context-group> + <context-group purpose="location"><context context-type="linenumber">160</context></context-group> </trans-unit> - <trans-unit id="_msg970"> + <trans-unit id="_msg1001"> <source xml:space="preserve">Error initializing wallet database environment %s!</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">146</context></context-group> + <context-group purpose="location"><context context-type="linenumber">161</context></context-group> </trans-unit> - <trans-unit id="_msg971"> + <trans-unit id="_msg1002"> <source xml:space="preserve">Error loading %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">147</context></context-group> + <context-group purpose="location"><context context-type="linenumber">162</context></context-group> </trans-unit> - <trans-unit id="_msg972"> + <trans-unit id="_msg1003"> <source xml:space="preserve">Error loading %s: Private keys can only be disabled during creation</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">148</context></context-group> + <context-group purpose="location"><context context-type="linenumber">163</context></context-group> </trans-unit> - <trans-unit id="_msg973"> + <trans-unit id="_msg1004"> <source xml:space="preserve">Error loading %s: Wallet corrupted</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">149</context></context-group> + <context-group purpose="location"><context context-type="linenumber">164</context></context-group> </trans-unit> - <trans-unit id="_msg974"> + <trans-unit id="_msg1005"> <source xml:space="preserve">Error loading %s: Wallet requires newer version of %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">150</context></context-group> + <context-group purpose="location"><context context-type="linenumber">165</context></context-group> </trans-unit> - <trans-unit id="_msg975"> + <trans-unit id="_msg1006"> <source xml:space="preserve">Error loading block database</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">151</context></context-group> + <context-group purpose="location"><context context-type="linenumber">166</context></context-group> </trans-unit> - <trans-unit id="_msg976"> + <trans-unit id="_msg1007"> <source xml:space="preserve">Error opening block database</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">152</context></context-group> + <context-group purpose="location"><context context-type="linenumber">167</context></context-group> </trans-unit> - <trans-unit id="_msg977"> + <trans-unit id="_msg1008"> <source xml:space="preserve">Error reading from database, shutting down.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">153</context></context-group> + <context-group purpose="location"><context context-type="linenumber">168</context></context-group> </trans-unit> - <trans-unit id="_msg978"> + <trans-unit id="_msg1009"> <source xml:space="preserve">Error reading next record from wallet database</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">154</context></context-group> + <context-group purpose="location"><context context-type="linenumber">169</context></context-group> </trans-unit> - <trans-unit id="_msg979"> + <trans-unit id="_msg1010"> <source xml:space="preserve">Error upgrading chainstate database</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">155</context></context-group> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> </trans-unit> - <trans-unit id="_msg980"> + <trans-unit id="_msg1011"> <source xml:space="preserve">Error: Couldn't create cursor into database</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">156</context></context-group> + <context-group purpose="location"><context context-type="linenumber">171</context></context-group> </trans-unit> - <trans-unit id="_msg981"> + <trans-unit id="_msg1012"> <source xml:space="preserve">Error: Disk space is low for %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">157</context></context-group> + <context-group purpose="location"><context context-type="linenumber">172</context></context-group> </trans-unit> - <trans-unit id="_msg982"> + <trans-unit id="_msg1013"> <source xml:space="preserve">Error: Dumpfile checksum does not match. Computed %s, expected %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">158</context></context-group> + <context-group purpose="location"><context context-type="linenumber">173</context></context-group> </trans-unit> - <trans-unit id="_msg983"> + <trans-unit id="_msg1014"> <source xml:space="preserve">Error: Got key that was not hex: %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">159</context></context-group> + <context-group purpose="location"><context context-type="linenumber">174</context></context-group> </trans-unit> - <trans-unit id="_msg984"> + <trans-unit id="_msg1015"> <source xml:space="preserve">Error: Got value that was not hex: %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">160</context></context-group> + <context-group purpose="location"><context context-type="linenumber">175</context></context-group> </trans-unit> - <trans-unit id="_msg985"> + <trans-unit id="_msg1016"> <source xml:space="preserve">Error: Keypool ran out, please call keypoolrefill first</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">161</context></context-group> + <context-group purpose="location"><context context-type="linenumber">176</context></context-group> </trans-unit> - <trans-unit id="_msg986"> + <trans-unit id="_msg1017"> <source xml:space="preserve">Error: Missing checksum</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">162</context></context-group> + <context-group purpose="location"><context context-type="linenumber">177</context></context-group> </trans-unit> - <trans-unit id="_msg987"> + <trans-unit id="_msg1018"> <source xml:space="preserve">Error: No %s addresses available.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">163</context></context-group> + <context-group purpose="location"><context context-type="linenumber">178</context></context-group> </trans-unit> - <trans-unit id="_msg988"> + <trans-unit id="_msg1019"> <source xml:space="preserve">Error: Unable to parse version %u as a uint32_t</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">164</context></context-group> + <context-group purpose="location"><context context-type="linenumber">179</context></context-group> </trans-unit> - <trans-unit id="_msg989"> + <trans-unit id="_msg1020"> <source xml:space="preserve">Error: Unable to write record to new wallet</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">165</context></context-group> + <context-group purpose="location"><context context-type="linenumber">180</context></context-group> </trans-unit> - <trans-unit id="_msg990"> + <trans-unit id="_msg1021"> <source xml:space="preserve">Failed to listen on any port. Use -listen=0 if you want this.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">166</context></context-group> + <context-group purpose="location"><context context-type="linenumber">181</context></context-group> </trans-unit> - <trans-unit id="_msg991"> + <trans-unit id="_msg1022"> <source xml:space="preserve">Failed to rescan the wallet during initialization</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">167</context></context-group> + <context-group purpose="location"><context context-type="linenumber">182</context></context-group> </trans-unit> - <trans-unit id="_msg992"> + <trans-unit id="_msg1023"> <source xml:space="preserve">Failed to verify database</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">168</context></context-group> + <context-group purpose="location"><context context-type="linenumber">183</context></context-group> </trans-unit> - <trans-unit id="_msg993"> + <trans-unit id="_msg1024"> <source xml:space="preserve">Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">169</context></context-group> + <context-group purpose="location"><context context-type="linenumber">184</context></context-group> </trans-unit> - <trans-unit id="_msg994"> + <trans-unit id="_msg1025"> <source xml:space="preserve">Ignoring duplicate -wallet %s.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">170</context></context-group> + <context-group purpose="location"><context context-type="linenumber">185</context></context-group> </trans-unit> - <trans-unit id="_msg995"> + <trans-unit id="_msg1026"> <source xml:space="preserve">Importing…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">171</context></context-group> + <context-group purpose="location"><context context-type="linenumber">186</context></context-group> </trans-unit> - <trans-unit id="_msg996"> + <trans-unit id="_msg1027"> <source xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">172</context></context-group> + <context-group purpose="location"><context context-type="linenumber">187</context></context-group> </trans-unit> - <trans-unit id="_msg997"> + <trans-unit id="_msg1028"> <source xml:space="preserve">Initialization sanity check failed. %s is shutting down.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">173</context></context-group> + <context-group purpose="location"><context context-type="linenumber">188</context></context-group> </trans-unit> - <trans-unit id="_msg998"> + <trans-unit id="_msg1029"> + <source xml:space="preserve">Input not found or already spent</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">189</context></context-group> + </trans-unit> + <trans-unit id="_msg1030"> <source xml:space="preserve">Insufficient funds</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">174</context></context-group> + <context-group purpose="location"><context context-type="linenumber">190</context></context-group> </trans-unit> - <trans-unit id="_msg999"> + <trans-unit id="_msg1031"> <source xml:space="preserve">Invalid -i2psam address or hostname: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">175</context></context-group> + <context-group purpose="location"><context context-type="linenumber">191</context></context-group> </trans-unit> - <trans-unit id="_msg1000"> + <trans-unit id="_msg1032"> <source xml:space="preserve">Invalid -onion address or hostname: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">176</context></context-group> + <context-group purpose="location"><context context-type="linenumber">192</context></context-group> </trans-unit> - <trans-unit id="_msg1001"> + <trans-unit id="_msg1033"> <source xml:space="preserve">Invalid -proxy address or hostname: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">177</context></context-group> + <context-group purpose="location"><context context-type="linenumber">193</context></context-group> </trans-unit> - <trans-unit id="_msg1002"> + <trans-unit id="_msg1034"> <source xml:space="preserve">Invalid P2P permission: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">178</context></context-group> + <context-group purpose="location"><context context-type="linenumber">194</context></context-group> </trans-unit> - <trans-unit id="_msg1003"> + <trans-unit id="_msg1035"> <source xml:space="preserve">Invalid amount for -%s=<amount>: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">179</context></context-group> + <context-group purpose="location"><context context-type="linenumber">195</context></context-group> </trans-unit> - <trans-unit id="_msg1004"> + <trans-unit id="_msg1036"> <source xml:space="preserve">Invalid amount for -discardfee=<amount>: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">180</context></context-group> + <context-group purpose="location"><context context-type="linenumber">196</context></context-group> </trans-unit> - <trans-unit id="_msg1005"> + <trans-unit id="_msg1037"> <source xml:space="preserve">Invalid amount for -fallbackfee=<amount>: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">181</context></context-group> + <context-group purpose="location"><context context-type="linenumber">197</context></context-group> </trans-unit> - <trans-unit id="_msg1006"> + <trans-unit id="_msg1038"> <source xml:space="preserve">Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">182</context></context-group> + <context-group purpose="location"><context context-type="linenumber">198</context></context-group> </trans-unit> - <trans-unit id="_msg1007"> + <trans-unit id="_msg1039"> <source xml:space="preserve">Invalid netmask specified in -whitelist: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">183</context></context-group> + <context-group purpose="location"><context context-type="linenumber">199</context></context-group> </trans-unit> - <trans-unit id="_msg1008"> + <trans-unit id="_msg1040"> <source xml:space="preserve">Loading P2P addresses…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">184</context></context-group> + <context-group purpose="location"><context context-type="linenumber">200</context></context-group> </trans-unit> - <trans-unit id="_msg1009"> + <trans-unit id="_msg1041"> <source xml:space="preserve">Loading banlist…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">185</context></context-group> + <context-group purpose="location"><context context-type="linenumber">201</context></context-group> </trans-unit> - <trans-unit id="_msg1010"> + <trans-unit id="_msg1042"> <source xml:space="preserve">Loading block index…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">186</context></context-group> + <context-group purpose="location"><context context-type="linenumber">202</context></context-group> </trans-unit> - <trans-unit id="_msg1011"> + <trans-unit id="_msg1043"> <source xml:space="preserve">Loading wallet…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">187</context></context-group> + <context-group purpose="location"><context context-type="linenumber">203</context></context-group> </trans-unit> - <trans-unit id="_msg1012"> + <trans-unit id="_msg1044"> + <source xml:space="preserve">Missing amount</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">204</context></context-group> + </trans-unit> + <trans-unit id="_msg1045"> + <source xml:space="preserve">Missing solving data for estimating transaction size</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">205</context></context-group> + </trans-unit> + <trans-unit id="_msg1046"> <source xml:space="preserve">Need to specify a port with -whitebind: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">188</context></context-group> + <context-group purpose="location"><context context-type="linenumber">206</context></context-group> </trans-unit> - <trans-unit id="_msg1013"> + <trans-unit id="_msg1047"> + <source xml:space="preserve">No addresses available</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">207</context></context-group> + </trans-unit> + <trans-unit id="_msg1048"> <source xml:space="preserve">No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">189</context></context-group> + <context-group purpose="location"><context context-type="linenumber">208</context></context-group> </trans-unit> - <trans-unit id="_msg1014"> + <trans-unit id="_msg1049"> <source xml:space="preserve">Not enough file descriptors available.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">190</context></context-group> + <context-group purpose="location"><context context-type="linenumber">209</context></context-group> </trans-unit> - <trans-unit id="_msg1015"> + <trans-unit id="_msg1050"> <source xml:space="preserve">Prune cannot be configured with a negative value.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">191</context></context-group> + <context-group purpose="location"><context context-type="linenumber">210</context></context-group> </trans-unit> - <trans-unit id="_msg1016"> + <trans-unit id="_msg1051"> <source xml:space="preserve">Prune mode is incompatible with -coinstatsindex.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">192</context></context-group> + <context-group purpose="location"><context context-type="linenumber">211</context></context-group> </trans-unit> - <trans-unit id="_msg1017"> + <trans-unit id="_msg1052"> <source xml:space="preserve">Prune mode is incompatible with -txindex.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">193</context></context-group> + <context-group purpose="location"><context context-type="linenumber">212</context></context-group> </trans-unit> - <trans-unit id="_msg1018"> + <trans-unit id="_msg1053"> <source xml:space="preserve">Pruning blockstore…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">194</context></context-group> + <context-group purpose="location"><context context-type="linenumber">213</context></context-group> </trans-unit> - <trans-unit id="_msg1019"> + <trans-unit id="_msg1054"> <source xml:space="preserve">Reducing -maxconnections from %d to %d, because of system limitations.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">195</context></context-group> + <context-group purpose="location"><context context-type="linenumber">214</context></context-group> </trans-unit> - <trans-unit id="_msg1020"> + <trans-unit id="_msg1055"> <source xml:space="preserve">Replaying blocks…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">196</context></context-group> + <context-group purpose="location"><context context-type="linenumber">215</context></context-group> </trans-unit> - <trans-unit id="_msg1021"> + <trans-unit id="_msg1056"> <source xml:space="preserve">Rescanning…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">197</context></context-group> + <context-group purpose="location"><context context-type="linenumber">216</context></context-group> </trans-unit> - <trans-unit id="_msg1022"> + <trans-unit id="_msg1057"> <source xml:space="preserve">SQLiteDatabase: Failed to execute statement to verify database: %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">198</context></context-group> + <context-group purpose="location"><context context-type="linenumber">217</context></context-group> </trans-unit> - <trans-unit id="_msg1023"> + <trans-unit id="_msg1058"> <source xml:space="preserve">SQLiteDatabase: Failed to prepare statement to verify database: %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">199</context></context-group> + <context-group purpose="location"><context context-type="linenumber">218</context></context-group> </trans-unit> - <trans-unit id="_msg1024"> + <trans-unit id="_msg1059"> <source xml:space="preserve">SQLiteDatabase: Failed to read database verification error: %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">200</context></context-group> + <context-group purpose="location"><context context-type="linenumber">219</context></context-group> </trans-unit> - <trans-unit id="_msg1025"> + <trans-unit id="_msg1060"> <source xml:space="preserve">SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">201</context></context-group> + <context-group purpose="location"><context context-type="linenumber">220</context></context-group> </trans-unit> - <trans-unit id="_msg1026"> + <trans-unit id="_msg1061"> <source xml:space="preserve">Section [%s] is not recognized.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">202</context></context-group> + <context-group purpose="location"><context context-type="linenumber">221</context></context-group> </trans-unit> - <trans-unit id="_msg1027"> + <trans-unit id="_msg1062"> <source xml:space="preserve">Signing transaction failed</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">203</context></context-group> + <context-group purpose="location"><context context-type="linenumber">222</context></context-group> </trans-unit> - <trans-unit id="_msg1028"> + <trans-unit id="_msg1063"> <source xml:space="preserve">Specified -walletdir "%s" does not exist</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">204</context></context-group> + <context-group purpose="location"><context context-type="linenumber">223</context></context-group> </trans-unit> - <trans-unit id="_msg1029"> + <trans-unit id="_msg1064"> <source xml:space="preserve">Specified -walletdir "%s" is a relative path</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">205</context></context-group> + <context-group purpose="location"><context context-type="linenumber">224</context></context-group> </trans-unit> - <trans-unit id="_msg1030"> + <trans-unit id="_msg1065"> <source xml:space="preserve">Specified -walletdir "%s" is not a directory</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + <context-group purpose="location"><context context-type="linenumber">225</context></context-group> </trans-unit> - <trans-unit id="_msg1031"> + <trans-unit id="_msg1066"> <source xml:space="preserve">Specified blocks directory "%s" does not exist.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">207</context></context-group> + <context-group purpose="location"><context context-type="linenumber">226</context></context-group> </trans-unit> - <trans-unit id="_msg1032"> + <trans-unit id="_msg1067"> <source xml:space="preserve">Starting network threads…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">208</context></context-group> + <context-group purpose="location"><context context-type="linenumber">227</context></context-group> </trans-unit> - <trans-unit id="_msg1033"> + <trans-unit id="_msg1068"> <source xml:space="preserve">The source code is available from %s.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">209</context></context-group> + <context-group purpose="location"><context context-type="linenumber">228</context></context-group> </trans-unit> - <trans-unit id="_msg1034"> + <trans-unit id="_msg1069"> <source xml:space="preserve">The specified config file %s does not exist</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">210</context></context-group> + <context-group purpose="location"><context context-type="linenumber">229</context></context-group> </trans-unit> - <trans-unit id="_msg1035"> + <trans-unit id="_msg1070"> <source xml:space="preserve">The transaction amount is too small to pay the fee</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">211</context></context-group> + <context-group purpose="location"><context context-type="linenumber">230</context></context-group> </trans-unit> - <trans-unit id="_msg1036"> + <trans-unit id="_msg1071"> <source xml:space="preserve">The wallet will avoid paying less than the minimum relay fee.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">212</context></context-group> + <context-group purpose="location"><context context-type="linenumber">231</context></context-group> </trans-unit> - <trans-unit id="_msg1037"> + <trans-unit id="_msg1072"> <source xml:space="preserve">This is experimental software.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">213</context></context-group> + <context-group purpose="location"><context context-type="linenumber">232</context></context-group> </trans-unit> - <trans-unit id="_msg1038"> + <trans-unit id="_msg1073"> <source xml:space="preserve">This is the minimum transaction fee you pay on every transaction.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">214</context></context-group> + <context-group purpose="location"><context context-type="linenumber">233</context></context-group> </trans-unit> - <trans-unit id="_msg1039"> + <trans-unit id="_msg1074"> <source xml:space="preserve">This is the transaction fee you will pay if you send a transaction.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">215</context></context-group> + <context-group purpose="location"><context context-type="linenumber">234</context></context-group> </trans-unit> - <trans-unit id="_msg1040"> + <trans-unit id="_msg1075"> <source xml:space="preserve">Transaction amount too small</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">216</context></context-group> + <context-group purpose="location"><context context-type="linenumber">235</context></context-group> </trans-unit> - <trans-unit id="_msg1041"> + <trans-unit id="_msg1076"> <source xml:space="preserve">Transaction amounts must not be negative</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">217</context></context-group> + <context-group purpose="location"><context context-type="linenumber">236</context></context-group> </trans-unit> - <trans-unit id="_msg1042"> + <trans-unit id="_msg1077"> <source xml:space="preserve">Transaction has too long of a mempool chain</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">218</context></context-group> + <context-group purpose="location"><context context-type="linenumber">237</context></context-group> </trans-unit> - <trans-unit id="_msg1043"> + <trans-unit id="_msg1078"> <source xml:space="preserve">Transaction must have at least one recipient</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">219</context></context-group> + <context-group purpose="location"><context context-type="linenumber">238</context></context-group> </trans-unit> - <trans-unit id="_msg1044"> - <source xml:space="preserve">Transaction needs a change address, but we can't generate it. %s</source> + <trans-unit id="_msg1079"> + <source xml:space="preserve">Transaction needs a change address, but we can't generate it.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">220</context></context-group> + <context-group purpose="location"><context context-type="linenumber">239</context></context-group> </trans-unit> - <trans-unit id="_msg1045"> + <trans-unit id="_msg1080"> <source xml:space="preserve">Transaction too large</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">221</context></context-group> + <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> - <trans-unit id="_msg1046"> + <trans-unit id="_msg1081"> <source xml:space="preserve">Unable to bind to %s on this computer (bind returned error %s)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">222</context></context-group> + <context-group purpose="location"><context context-type="linenumber">241</context></context-group> </trans-unit> - <trans-unit id="_msg1047"> + <trans-unit id="_msg1082"> <source xml:space="preserve">Unable to bind to %s on this computer. %s is probably already running.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">223</context></context-group> + <context-group purpose="location"><context context-type="linenumber">242</context></context-group> </trans-unit> - <trans-unit id="_msg1048"> + <trans-unit id="_msg1083"> <source xml:space="preserve">Unable to create the PID file '%s': %s</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">224</context></context-group> + <context-group purpose="location"><context context-type="linenumber">243</context></context-group> </trans-unit> - <trans-unit id="_msg1049"> + <trans-unit id="_msg1084"> <source xml:space="preserve">Unable to generate initial keys</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">225</context></context-group> + <context-group purpose="location"><context context-type="linenumber">244</context></context-group> </trans-unit> - <trans-unit id="_msg1050"> + <trans-unit id="_msg1085"> <source xml:space="preserve">Unable to generate keys</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">226</context></context-group> + <context-group purpose="location"><context context-type="linenumber">245</context></context-group> </trans-unit> - <trans-unit id="_msg1051"> + <trans-unit id="_msg1086"> <source xml:space="preserve">Unable to open %s for writing</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">227</context></context-group> + <context-group purpose="location"><context context-type="linenumber">246</context></context-group> </trans-unit> - <trans-unit id="_msg1052"> + <trans-unit id="_msg1087"> + <source xml:space="preserve">Unable to parse -maxuploadtarget: '%s'</source> + <target xml:space="preserve"></target> + <context-group purpose="location"><context context-type="linenumber">247</context></context-group> + </trans-unit> + <trans-unit id="_msg1088"> <source xml:space="preserve">Unable to start HTTP server. See debug log for details.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">228</context></context-group> + <context-group purpose="location"><context context-type="linenumber">248</context></context-group> </trans-unit> - <trans-unit id="_msg1053"> + <trans-unit id="_msg1089"> <source xml:space="preserve">Unknown -blockfilterindex value %s.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">229</context></context-group> + <context-group purpose="location"><context context-type="linenumber">249</context></context-group> </trans-unit> - <trans-unit id="_msg1054"> + <trans-unit id="_msg1090"> <source xml:space="preserve">Unknown address type '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">230</context></context-group> + <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> - <trans-unit id="_msg1055"> + <trans-unit id="_msg1091"> <source xml:space="preserve">Unknown change type '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">231</context></context-group> + <context-group purpose="location"><context context-type="linenumber">251</context></context-group> </trans-unit> - <trans-unit id="_msg1056"> + <trans-unit id="_msg1092"> <source xml:space="preserve">Unknown network specified in -onlynet: '%s'</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">232</context></context-group> + <context-group purpose="location"><context context-type="linenumber">252</context></context-group> </trans-unit> - <trans-unit id="_msg1057"> + <trans-unit id="_msg1093"> <source xml:space="preserve">Unknown new rules activated (versionbit %i)</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">233</context></context-group> + <context-group purpose="location"><context context-type="linenumber">253</context></context-group> </trans-unit> - <trans-unit id="_msg1058"> + <trans-unit id="_msg1094"> <source xml:space="preserve">Unsupported logging category %s=%s.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">234</context></context-group> + <context-group purpose="location"><context context-type="linenumber">254</context></context-group> </trans-unit> - <trans-unit id="_msg1059"> + <trans-unit id="_msg1095"> <source xml:space="preserve">Upgrading UTXO database</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">235</context></context-group> - </trans-unit> - <trans-unit id="_msg1060"> - <source xml:space="preserve">Upgrading txindex database</source> - <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">236</context></context-group> + <context-group purpose="location"><context context-type="linenumber">255</context></context-group> </trans-unit> - <trans-unit id="_msg1061"> + <trans-unit id="_msg1096"> <source xml:space="preserve">User Agent comment (%s) contains unsafe characters.</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">237</context></context-group> + <context-group purpose="location"><context context-type="linenumber">256</context></context-group> </trans-unit> - <trans-unit id="_msg1062"> + <trans-unit id="_msg1097"> <source xml:space="preserve">Verifying blocks…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">238</context></context-group> + <context-group purpose="location"><context context-type="linenumber">257</context></context-group> </trans-unit> - <trans-unit id="_msg1063"> + <trans-unit id="_msg1098"> <source xml:space="preserve">Verifying wallet(s)…</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">239</context></context-group> + <context-group purpose="location"><context context-type="linenumber">258</context></context-group> </trans-unit> - <trans-unit id="_msg1064"> + <trans-unit id="_msg1099"> <source xml:space="preserve">Wallet needed to be rewritten: restart %s to complete</source> <target xml:space="preserve"></target> - <context-group purpose="location"><context context-type="linenumber">240</context></context-group> + <context-group purpose="location"><context context-type="linenumber">259</context></context-group> </trans-unit> </group> </body></file> diff --git a/src/qt/modaloverlay.cpp b/src/qt/modaloverlay.cpp index cca77881e1..97ee75a31f 100644 --- a/src/qt/modaloverlay.cpp +++ b/src/qt/modaloverlay.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp index ee70c1bc30..b2dc7fd65a 100644 --- a/src/qt/networkstyle.cpp +++ b/src/qt/networkstyle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 The Bitcoin Core developers +// Copyright (c) 2014-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp index a68eee718e..fd22f21f9b 100644 --- a/src/qt/openuridialog.cpp +++ b/src/qt/openuridialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h index f3a8b0ba22..2c8f7f8bab 100644 --- a/src/qt/openuridialog.h +++ b/src/qt/openuridialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 0cc2d61df6..c05571677c 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -19,6 +19,8 @@ #include <netbase.h> #include <txdb.h> // for -dbcache defaults +#include <chrono> + #include <QDataWidgetMapper> #include <QDir> #include <QIntValidator> @@ -242,6 +244,7 @@ void OptionsDialog::setMapper() mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures); mapper->addMapping(ui->subFeeFromAmount, OptionsModel::SubFeeFromAmount); mapper->addMapping(ui->externalSignerPath, OptionsModel::ExternalSignerPath); + mapper->addMapping(ui->m_enable_psbt_controls, OptionsModel::EnablePSBTControls); /* Network */ mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP); @@ -361,7 +364,7 @@ void OptionsDialog::showRestartWarning(bool fPersistent) ui->statusLabel->setText(tr("This change would require a client restart.")); // clear non-persistent status label after 10 seconds // Todo: should perhaps be a class attribute, if we extend the use of statusLabel - QTimer::singleShot(10000, this, &OptionsDialog::clearStatusLabel); + QTimer::singleShot(10s, this, &OptionsDialog::clearStatusLabel); } } diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index f14aec3449..0b7802536c 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 9e2f38f7ec..5d9ed5bf23 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -83,6 +83,11 @@ void OptionsModel::Init(bool resetSettings) settings.setValue("fCoinControlFeatures", false); fCoinControlFeatures = settings.value("fCoinControlFeatures", false).toBool(); + if (!settings.contains("enable_psbt_controls")) { + settings.setValue("enable_psbt_controls", false); + } + m_enable_psbt_controls = settings.value("enable_psbt_controls", false).toBool(); + // These are shared with the core or have a command-line parameter // and we want command-line parameters to overwrite the GUI settings. // @@ -204,8 +209,8 @@ static void CopySettings(QSettings& dst, const QSettings& src) /** Back up a QSettings to an ini-formatted file. */ static void BackupSettings(const fs::path& filename, const QSettings& src) { - qInfo() << "Backing up GUI settings to" << GUIUtil::boostPathToQString(filename); - QSettings dst(GUIUtil::boostPathToQString(filename), QSettings::IniFormat); + qInfo() << "Backing up GUI settings to" << GUIUtil::PathToQString(filename); + QSettings dst(GUIUtil::PathToQString(filename), QSettings::IniFormat); dst.clear(); CopySettings(dst, src); } @@ -360,6 +365,8 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const return m_use_embedded_monospaced_font; case CoinControlFeatures: return fCoinControlFeatures; + case EnablePSBTControls: + return settings.value("enable_psbt_controls"); case Prune: return settings.value("bPrune"); case PruneSize: @@ -507,6 +514,10 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in settings.setValue("fCoinControlFeatures", fCoinControlFeatures); Q_EMIT coinControlFeaturesChanged(fCoinControlFeatures); break; + case EnablePSBTControls: + m_enable_psbt_controls = value.toBool(); + settings.setValue("enable_psbt_controls", m_enable_psbt_controls); + break; case Prune: if (settings.value("bPrune") != value) { settings.setValue("bPrune", value); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 8f1513e48d..bb9a8c1f8c 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -69,6 +69,7 @@ public: SpendZeroConfChange, // bool Listen, // bool Server, // bool + EnablePSBTControls, // bool OptionIDRowCount, }; @@ -90,6 +91,7 @@ public: bool getUseEmbeddedMonospacedFont() const { return m_use_embedded_monospaced_font; } bool getCoinControlFeatures() const { return fCoinControlFeatures; } bool getSubFeeFromAmount() const { return m_sub_fee_from_amount; } + bool getEnablePSBTControls() const { return m_enable_psbt_controls; } const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; } /* Explicit setters */ @@ -115,6 +117,7 @@ private: bool m_use_embedded_monospaced_font; bool fCoinControlFeatures; bool m_sub_fee_from_amount; + bool m_enable_psbt_controls; /* settings that were overridden by command-line */ QString strOverriddenByCommandLine; diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 864a62edc8..7127706463 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index 5270741c0d..058df1a8c5 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 098fe5ac61..cb09035b45 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -51,7 +51,7 @@ static QString ipcServerName() // Append a simple hash of the datadir // Note that gArgs.GetDataDirNet() returns a different path // for -testnet versus main net - QString ddir(GUIUtil::boostPathToQString(gArgs.GetDataDirNet())); + QString ddir(GUIUtil::PathToQString(gArgs.GetDataDirNet())); name.append(QString::number(qHash(ddir))); return name; diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index 433a1ea934..cd3193a1d2 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index 40265ee266..11064cdbfe 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/peertablesortproxy.cpp b/src/qt/peertablesortproxy.cpp index 419133bc32..26fedb4127 100644 --- a/src/qt/peertablesortproxy.cpp +++ b/src/qt/peertablesortproxy.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/qt/peertablesortproxy.h b/src/qt/peertablesortproxy.h index 1879f6b400..29e532001e 100644 --- a/src/qt/peertablesortproxy.h +++ b/src/qt/peertablesortproxy.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp index 2257c2ad4f..89e022a067 100644 --- a/src/qt/platformstyle.cpp +++ b/src/qt/platformstyle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-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. diff --git a/src/qt/platformstyle.h b/src/qt/platformstyle.h index 9df0a1f985..98797d6a3c 100644 --- a/src/qt/platformstyle.h +++ b/src/qt/platformstyle.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2019 The Bitcoin Core developers +// Copyright (c) 2015-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. diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp index 3e598bfab9..6880c157c0 100644 --- a/src/qt/psbtoperationsdialog.cpp +++ b/src/qt/psbtoperationsdialog.cpp @@ -1,10 +1,11 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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 <qt/psbtoperationsdialog.h> #include <core_io.h> +#include <fs.h> #include <interfaces/node.h> #include <key_io.h> #include <node/psbt.h> @@ -15,8 +16,13 @@ #include <qt/optionsmodel.h> #include <util/strencodings.h> +#include <fstream> #include <iostream> +#include <string> +using node::AnalyzePSBT; +using node::DEFAULT_MAX_RAW_TX_FEE_RATE; +using node::PSBTAnalysis; PSBTOperationsDialog::PSBTOperationsDialog( QWidget* parent, WalletModel* wallet_model, ClientModel* client_model) : QDialog(parent, GUIUtil::dialog_flags), @@ -155,7 +161,7 @@ void PSBTOperationsDialog::saveTransaction() { if (filename.isEmpty()) { return; } - std::ofstream out(filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary); + std::ofstream out{filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary}; out << ssTx.str(); out.close(); showStatus(tr("PSBT saved to disk."), StatusLevel::INFO); diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp index 0799e01aac..05a67117b6 100644 --- a/src/qt/qrimagewidget.cpp +++ b/src/qt/qrimagewidget.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp index aa936d6b7c..bd4df75d23 100644 --- a/src/qt/qvalidatedlineedit.cpp +++ b/src/qt/qvalidatedlineedit.cpp @@ -15,6 +15,12 @@ QValidatedLineEdit::QValidatedLineEdit(QWidget *parent) : connect(this, &QValidatedLineEdit::textChanged, this, &QValidatedLineEdit::markValid); } +void QValidatedLineEdit::setText(const QString& text) +{ + QLineEdit::setText(text); + checkValidity(); +} + void QValidatedLineEdit::setValid(bool _valid) { if(_valid == this->valid) @@ -28,7 +34,7 @@ void QValidatedLineEdit::setValid(bool _valid) } else { - setStyleSheet(STYLE_INVALID); + setStyleSheet("QValidatedLineEdit { " STYLE_INVALID "}"); } this->valid = _valid; } @@ -106,6 +112,7 @@ void QValidatedLineEdit::checkValidity() void QValidatedLineEdit::setCheckValidator(const QValidator *v) { checkValidator = v; + checkValidity(); } bool QValidatedLineEdit::isValid() diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h index b32305f5e1..12d35aa264 100644 --- a/src/qt/qvalidatedlineedit.h +++ b/src/qt/qvalidatedlineedit.h @@ -29,6 +29,7 @@ private: const QValidator *checkValidator; public Q_SLOTS: + void setText(const QString&); void setValid(bool valid); void setEnabled(bool enabled); diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp index 5672396819..f94486a2f3 100644 --- a/src/qt/qvaluecombobox.cpp +++ b/src/qt/qvaluecombobox.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp index d47ee95826..3c80c01160 100644 --- a/src/qt/receivecoinsdialog.cpp +++ b/src/qt/receivecoinsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -38,7 +38,7 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWid } else { ui->clearButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove")); ui->receiveButton->setIcon(_platformStyle->SingleColorIcon(":/icons/receiving_addresses")); - ui->showRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/edit")); + ui->showRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/eye")); ui->removeRequestButton->setIcon(_platformStyle->SingleColorIcon(":/icons/remove")); } @@ -87,10 +87,18 @@ void ReceiveCoinsDialog::setModel(WalletModel *_model) &QItemSelectionModel::selectionChanged, this, &ReceiveCoinsDialog::recentRequestsView_selectionChanged); - if (model->wallet().getDefaultAddressType() == OutputType::BECH32) { - ui->useBech32->setCheckState(Qt::Checked); - } else { - ui->useBech32->setCheckState(Qt::Unchecked); + // Populate address type dropdown and select default + auto add_address_type = [&](OutputType type, const QString& text, const QString& tooltip) { + const auto index = ui->addressType->count(); + ui->addressType->addItem(text, (int) type); + ui->addressType->setItemData(index, tooltip, Qt::ToolTipRole); + if (model->wallet().getDefaultAddressType() == type) ui->addressType->setCurrentIndex(index); + }; + add_address_type(OutputType::LEGACY, "Base58 (Legacy)", "Not recommended due to higher fees and less protection against typos."); + add_address_type(OutputType::P2SH_SEGWIT, "Base58 (P2SH-SegWit)", "Generates an address compatible with older wallets."); + add_address_type(OutputType::BECH32, "Bech32 (SegWit)", "Generates a native segwit address (BIP-173). Some old wallets don't support it."); + if (model->wallet().taprootEnabled()) { + add_address_type(OutputType::BECH32M, "Bech32m (Taproot)", "Bech32m (BIP-350) is an upgrade to Bech32, wallet support is still limited."); } // Set the button to be enabled or disabled based on whether the wallet can give out new addresses. @@ -144,15 +152,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked() QString address; QString label = ui->reqLabel->text(); /* Generate new receiving address */ - OutputType address_type; - if (ui->useBech32->isChecked()) { - address_type = OutputType::BECH32; - } else { - address_type = model->wallet().getDefaultAddressType(); - if (address_type == OutputType::BECH32) { - address_type = OutputType::P2SH_SEGWIT; - } - } + const OutputType address_type = (OutputType)ui->addressType->currentData().toInt(); address = model->getAddressTableModel()->addRow(AddressTableModel::Receive, label, "", address_type); switch(model->getAddressTableModel()->getEditStatus()) diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index fbbccc5a33..a089b8aa6a 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp index 41f22e9c34..c0135283b1 100644 --- a/src/qt/receiverequestdialog.cpp +++ b/src/qt/receiverequestdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp index ab8225e19f..03ca9ad7dc 100644 --- a/src/qt/recentrequeststablemodel.cpp +++ b/src/qt/recentrequeststablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h index c489c0eaf4..cf7cd24ce2 100644 --- a/src/qt/recentrequeststablemodel.h +++ b/src/qt/recentrequeststablemodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/res/animation/makespinner.sh b/src/qt/res/animation/makespinner.sh index 647ee1aed8..92e34a84a3 100755 --- a/src/qt/res/animation/makespinner.sh +++ b/src/qt/res/animation/makespinner.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2014-2020 The Bitcoin Core developers +# Copyright (c) 2014-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. diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 9f06d225c0..c5e5e69df6 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -54,6 +54,8 @@ #include <QTimer> #include <QVariant> +#include <chrono> + const int CONSOLE_HISTORY = 50; const int INITIAL_TRAFFIC_GRAPH_MINS = 30; const QSize FONT_RANGE(4, 40); @@ -1140,7 +1142,7 @@ void RPCConsole::on_sldGraphRange_valueChanged(int value) void RPCConsole::setTrafficGraphRange(int mins) { - ui->trafficGraph->setGraphRangeMins(mins); + ui->trafficGraph->setGraphRange(std::chrono::minutes{mins}); ui->lblGraphRange->setText(GUIUtil::formatDurationStr(std::chrono::minutes{mins})); } @@ -1215,6 +1217,9 @@ void RPCConsole::updateDetailWidget() } ui->peerHeight->setText(QString::number(stats->nodeStateStats.m_starting_height)); ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStateStats.m_ping_wait)); + ui->peerAddrRelayEnabled->setText(stats->nodeStateStats.m_addr_relay_enabled ? ts.yes : ts.no); + ui->peerAddrProcessed->setText(QString::number(stats->nodeStateStats.m_addr_processed)); + ui->peerAddrRateLimited->setText(QString::number(stats->nodeStateStats.m_addr_rate_limited)); } ui->peersTabRightPanel->show(); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index fc6e85b41a..528e2bef7d 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 2718392940..579ef0c3fd 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -24,17 +24,24 @@ #include <node/ui_interface.h> #include <policy/fees.h> #include <txmempool.h> +#include <validation.h> #include <wallet/coincontrol.h> #include <wallet/fees.h> #include <wallet/wallet.h> -#include <validation.h> +#include <array> +#include <chrono> +#include <fstream> +#include <memory> #include <QFontMetrics> #include <QScrollBar> #include <QSettings> #include <QTextDocument> +using wallet::CCoinControl; +using wallet::DEFAULT_PAY_TX_FEE; + static constexpr std::array confTargets{2, 4, 6, 12, 24, 48, 144, 504, 1008}; int getConfTargetForIndex(int index) { if (index+1 > static_cast<int>(confTargets.size())) { @@ -324,16 +331,22 @@ bool SendCoinsDialog::PrepareSendText(QString& question_string, QString& informa formatted.append(recipientElement); } - if (model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner()) { - question_string.append(tr("Do you want to draft this transaction?")); - } else { - question_string.append(tr("Are you sure you want to send?")); - } - + /*: 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. */ + question_string.append(tr("Do you want to create this transaction?")); question_string.append("<br /><span style='font-size:10pt;'>"); if (model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner()) { + /*: 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. */ question_string.append(tr("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.").arg(PACKAGE_NAME)); + } else if (model->getOptionsModel()->getEnablePSBTControls()) { + /*: 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. */ + question_string.append(tr("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.").arg(PACKAGE_NAME)); } else { + /*: Text to prompt a user to review the details of the transaction they are attempting to send. */ question_string.append(tr("Please, review your transaction.")); } question_string.append("</span>%1"); @@ -397,21 +410,20 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) if (!PrepareSendText(question_string, informative_text, detailed_text)) return; assert(m_current_transaction); - const QString confirmation = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner() ? tr("Confirm transaction proposal") : tr("Confirm send coins"); - const QString confirmButtonText = model->wallet().privateKeysDisabled() && !model->wallet().hasExternalSigner() ? tr("Create Unsigned") : tr("Sign and send"); - auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, confirmButtonText, this); + const QString confirmation = tr("Confirm send coins"); + auto confirmationDialog = new SendConfirmationDialog(confirmation, question_string, informative_text, detailed_text, SEND_CONFIRM_DELAY, !model->wallet().privateKeysDisabled(), model->getOptionsModel()->getEnablePSBTControls(), this); confirmationDialog->setAttribute(Qt::WA_DeleteOnClose); // TODO: Replace QDialog::exec() with safer QDialog::show(). const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec()); - if(retval != QMessageBox::Yes) + if(retval != QMessageBox::Yes && retval != QMessageBox::Save) { fNewRecipientAllowed = true; return; } bool send_failure = false; - if (model->wallet().privateKeysDisabled()) { + if (retval == QMessageBox::Save) { CMutableTransaction mtx = CMutableTransaction{*(m_current_transaction->getWtx())}; PartiallySignedTransaction psbtx(mtx); bool complete = false; @@ -500,7 +512,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) if (filename.isEmpty()) { return; } - std::ofstream out(filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary); + std::ofstream out{filename.toLocal8Bit().data(), std::ofstream::out | std::ofstream::binary}; out << ssTx.str(); out.close(); Q_EMIT message(tr("PSBT saved"), "PSBT saved to disk", CClientUIInterface::MSG_INFORMATION); @@ -512,6 +524,7 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked) assert(false); } // msgBox.exec() } else { + assert(!model->wallet().privateKeysDisabled()); // now send the prepared transaction WalletModel::SendCoinsReturn sendStatus = model->sendCoins(*m_current_transaction); // process sendStatus and on error generate message shown to user @@ -917,7 +930,7 @@ void SendCoinsDialog::coinControlButtonClicked() { auto dlg = new CoinControlDialog(*m_coin_control, model, platformStyle); connect(dlg, &QDialog::finished, this, &SendCoinsDialog::coinControlUpdateLabels); - GUIUtil::ShowModalDialogAndDeleteOnClose(dlg); + GUIUtil::ShowModalDialogAsynchronously(dlg); } // Coin Control: checkbox custom change address @@ -1031,8 +1044,8 @@ void SendCoinsDialog::coinControlUpdateLabels() } } -SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text, const QString& detailed_text, int _secDelay, const QString& _confirmButtonText, QWidget* parent) - : QMessageBox(parent), secDelay(_secDelay), confirmButtonText(_confirmButtonText) +SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text, const QString& detailed_text, int _secDelay, bool enable_send, bool always_show_unsigned, QWidget* parent) + : QMessageBox(parent), secDelay(_secDelay), m_enable_send(enable_send) { setIcon(QMessageBox::Question); setWindowTitle(title); // On macOS, the window title is ignored (as required by the macOS Guidelines). @@ -1040,26 +1053,28 @@ SendConfirmationDialog::SendConfirmationDialog(const QString& title, const QStri setInformativeText(informative_text); setDetailedText(detailed_text); setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); + if (always_show_unsigned || !enable_send) addButton(QMessageBox::Save); setDefaultButton(QMessageBox::Cancel); yesButton = button(QMessageBox::Yes); if (confirmButtonText.isEmpty()) { confirmButtonText = yesButton->text(); } - updateYesButton(); + m_psbt_button = button(QMessageBox::Save); + updateButtons(); connect(&countDownTimer, &QTimer::timeout, this, &SendConfirmationDialog::countDown); } int SendConfirmationDialog::exec() { - updateYesButton(); - countDownTimer.start(1000); + updateButtons(); + countDownTimer.start(1s); return QMessageBox::exec(); } void SendConfirmationDialog::countDown() { secDelay--; - updateYesButton(); + updateButtons(); if(secDelay <= 0) { @@ -1067,16 +1082,24 @@ void SendConfirmationDialog::countDown() } } -void SendConfirmationDialog::updateYesButton() +void SendConfirmationDialog::updateButtons() { if(secDelay > 0) { yesButton->setEnabled(false); - yesButton->setText(confirmButtonText + " (" + QString::number(secDelay) + ")"); + yesButton->setText(confirmButtonText + (m_enable_send ? (" (" + QString::number(secDelay) + ")") : QString(""))); + if (m_psbt_button) { + m_psbt_button->setEnabled(false); + m_psbt_button->setText(m_psbt_button_text + " (" + QString::number(secDelay) + ")"); + } } else { - yesButton->setEnabled(true); + yesButton->setEnabled(m_enable_send); yesButton->setText(confirmButtonText); + if (m_psbt_button) { + m_psbt_button->setEnabled(true); + m_psbt_button->setText(m_psbt_button_text); + } } } diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 33736f8095..4a16702756 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -12,12 +12,14 @@ #include <QString> #include <QTimer> -class CCoinControl; class ClientModel; class PlatformStyle; class SendCoinsEntry; class SendCoinsRecipient; enum class SynchronizationState; +namespace wallet { +class CCoinControl; +} // namespace wallet namespace Ui { class SendCoinsDialog; @@ -62,7 +64,7 @@ private: Ui::SendCoinsDialog *ui; ClientModel *clientModel; WalletModel *model; - std::unique_ptr<CCoinControl> m_coin_control; + std::unique_ptr<wallet::CCoinControl> m_coin_control; std::unique_ptr<WalletModelTransaction> m_current_transaction; bool fNewRecipientAllowed; bool fFeeMinimized; @@ -114,18 +116,21 @@ class SendConfirmationDialog : public QMessageBox Q_OBJECT public: - SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, const QString& confirmText = "", QWidget* parent = nullptr); + SendConfirmationDialog(const QString& title, const QString& text, const QString& informative_text = "", const QString& detailed_text = "", int secDelay = SEND_CONFIRM_DELAY, bool enable_send = true, bool always_show_unsigned = true, QWidget* parent = nullptr); int exec() override; private Q_SLOTS: void countDown(); - void updateYesButton(); + void updateButtons(); private: QAbstractButton *yesButton; + QAbstractButton *m_psbt_button; QTimer countDownTimer; int secDelay; - QString confirmButtonText; + QString confirmButtonText{tr("Send")}; + bool m_enable_send; + QString m_psbt_button_text{tr("Create Unsigned")}; }; #endif // BITCOIN_QT_SENDCOINSDIALOG_H diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 5fa5165615..339ac580d8 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h index e682e6423a..e8db1e3a5c 100644 --- a/src/qt/sendcoinsentry.h +++ b/src/qt/sendcoinsentry.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/sendcoinsrecipient.h b/src/qt/sendcoinsrecipient.h index c23afcab24..787a52b8b3 100644 --- a/src/qt/sendcoinsrecipient.h +++ b/src/qt/sendcoinsrecipient.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 33589f09bf..74bedbf020 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h index 3d2d5f281e..1a3708bf8f 100644 --- a/src/qt/signverifymessagedialog.h +++ b/src/qt/signverifymessagedialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 85703b3350..a4dfffa387 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -201,7 +201,7 @@ void SplashScreen::handleLoadWallet() { #ifdef ENABLE_WALLET if (!WalletModel::isWalletEnabled()) return; - m_handler_load_wallet = m_node->walletClient().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { + m_handler_load_wallet = m_node->walletLoader().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { m_connected_wallet_handlers.emplace_back(wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, false))); m_connected_wallets.emplace_back(std::move(wallet)); }); diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h index 8a5875d2a6..c14fc521a7 100644 --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index 39cc1c1e1d..66637a5dcf 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -20,10 +20,19 @@ #include <wallet/wallet.h> #include <walletinitinterface.h> +#include <chrono> + #include <QApplication> #include <QTimer> #include <QMessageBox> +using wallet::AddWallet; +using wallet::CWallet; +using wallet::CreateMockWalletDatabase; +using wallet::RemoveWallet; +using wallet::WALLET_FLAG_DESCRIPTORS; +using wallet::WalletContext; + namespace { @@ -40,7 +49,7 @@ void EditAddressAndSubmit( dialog->findChild<QLineEdit*>("labelEdit")->setText(label); dialog->findChild<QValidatedLineEdit*>("addressEdit")->setText(address); - ConfirmMessage(&warning_text, 5); + ConfirmMessage(&warning_text, 5ms); dialog->accept(); QCOMPARE(warning_text, expected_msg); } @@ -60,8 +69,8 @@ void EditAddressAndSubmit( void TestAddAddressesToSendBook(interfaces::Node& node) { TestChain100Setup test; - auto wallet_client = interfaces::MakeWalletClient(*test.m_node.chain, *Assert(test.m_node.args)); - test.m_node.wallet_client = wallet_client.get(); + auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args)); + test.m_node.wallet_loader = wallet_loader.get(); node.setContext(&test.m_node); const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", gArgs, CreateMockWalletDatabase()); wallet->LoadWallet(); @@ -115,7 +124,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node) std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other")); OptionsModel optionsModel; ClientModel clientModel(node, &optionsModel); - WalletContext& context = *node.walletClient().context(); + WalletContext& context = *node.walletLoader().context(); AddWallet(context, wallet); WalletModel walletModel(interfaces::MakeWallet(context, wallet), clientModel, platformStyle.get()); RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt); diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp index 8489b33144..099ac5fcae 100644 --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index df3b85ea71..669a05fe0f 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index f6ab26d1d2..10b7e2ffe7 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -22,6 +22,7 @@ #include <QApplication> #include <QObject> #include <QTest> +#include <functional> #if defined(QT_STATICPLUGIN) #include <QtPlugin> @@ -39,8 +40,12 @@ 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{}; + // This is all you need to run all the tests int main(int argc, char* argv[]) { diff --git a/src/qt/test/util.cpp b/src/qt/test/util.cpp index 987d921f03..635dbcd1c5 100644 --- a/src/qt/test/util.cpp +++ b/src/qt/test/util.cpp @@ -2,6 +2,8 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <chrono> + #include <QApplication> #include <QMessageBox> #include <QPushButton> @@ -9,7 +11,7 @@ #include <QTimer> #include <QWidget> -void ConfirmMessage(QString* text, int msec) +void ConfirmMessage(QString* text, std::chrono::milliseconds msec) { QTimer::singleShot(msec, [text]() { for (QWidget* widget : QApplication::topLevelWidgets()) { diff --git a/src/qt/test/util.h b/src/qt/test/util.h index df5931a032..f50a6b6c61 100644 --- a/src/qt/test/util.h +++ b/src/qt/test/util.h @@ -5,7 +5,11 @@ #ifndef BITCOIN_QT_TEST_UTIL_H #define BITCOIN_QT_TEST_UTIL_H -#include <QString> +#include <chrono> + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE /** * Press "Ok" button in message box dialog. @@ -13,6 +17,6 @@ * @param text - Optionally store dialog text. * @param msec - Number of milliseconds to pause before triggering the callback. */ -void ConfirmMessage(QString* text = nullptr, int msec = 0); +void ConfirmMessage(QString* text, std::chrono::milliseconds msec); #endif // BITCOIN_QT_TEST_UTIL_H diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 93d6aa805f..6ab534764b 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. @@ -26,6 +26,7 @@ #include <qt/recentrequeststablemodel.h> #include <qt/receiverequestdialog.h> +#include <chrono> #include <memory> #include <QAbstractButton> @@ -39,6 +40,15 @@ #include <QListView> #include <QDialogButtonBox> +using wallet::AddWallet; +using wallet::CWallet; +using wallet::CreateMockWalletDatabase; +using wallet::RemoveWallet; +using wallet::WALLET_FLAG_DESCRIPTORS; +using wallet::WalletContext; +using wallet::WalletDescriptor; +using wallet::WalletRescanReserver; + namespace { //! Press "Yes" or "Cancel" buttons in modal send confirmation dialog. @@ -112,7 +122,7 @@ void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, st if (expectError.empty()) { ConfirmSend(&text, cancel); } else { - ConfirmMessage(&text); + ConfirmMessage(&text, 0ms); } action->trigger(); QVERIFY(text.indexOf(QString::fromStdString(expectError)) != -1); @@ -138,8 +148,8 @@ void TestGUI(interfaces::Node& node) for (int i = 0; i < 5; ++i) { test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); } - auto wallet_client = interfaces::MakeWalletClient(*test.m_node.chain, *Assert(test.m_node.args)); - test.m_node.wallet_client = wallet_client.get(); + auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args)); + test.m_node.wallet_loader = wallet_loader.get(); node.setContext(&test.m_node); const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", gArgs, CreateMockWalletDatabase()); wallet->LoadWallet(); @@ -175,7 +185,7 @@ void TestGUI(interfaces::Node& node) TransactionView transactionView(platformStyle.get()); OptionsModel optionsModel; ClientModel clientModel(node, &optionsModel); - WalletContext& context = *node.walletClient().context(); + WalletContext& context = *node.walletLoader().context(); AddWallet(context, wallet); WalletModel walletModel(interfaces::MakeWallet(context, wallet), clientModel, platformStyle.get()); RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt); diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp index 7e12410c80..aebd44d5f7 100644 --- a/src/qt/trafficgraphwidget.cpp +++ b/src/qt/trafficgraphwidget.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -11,6 +11,7 @@ #include <QColor> #include <QTimer> +#include <chrono> #include <cmath> #define DESIRED_SAMPLES 800 @@ -22,7 +23,6 @@ TrafficGraphWidget::TrafficGraphWidget(QWidget *parent) : QWidget(parent), timer(nullptr), fMax(0.0f), - nMins(0), vSamplesIn(), vSamplesOut(), nLastBytesIn(0), @@ -42,10 +42,7 @@ void TrafficGraphWidget::setClientModel(ClientModel *model) } } -int TrafficGraphWidget::getGraphRangeMins() const -{ - return nMins; -} +std::chrono::minutes TrafficGraphWidget::getGraphRange() const { return m_range; } void TrafficGraphWidget::paintPath(QPainterPath &path, QQueue<float> &samples) { @@ -153,12 +150,12 @@ void TrafficGraphWidget::updateRates() update(); } -void TrafficGraphWidget::setGraphRangeMins(int mins) +void TrafficGraphWidget::setGraphRange(std::chrono::minutes new_range) { - nMins = mins; - int msecsPerSample = nMins * 60 * 1000 / DESIRED_SAMPLES; + m_range = new_range; + const auto msecs_per_sample{std::chrono::duration_cast<std::chrono::milliseconds>(m_range) / DESIRED_SAMPLES}; timer->stop(); - timer->setInterval(msecsPerSample); + timer->setInterval(msecs_per_sample); clear(); } diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h index 2d8c825815..a40b734540 100644 --- a/src/qt/trafficgraphwidget.h +++ b/src/qt/trafficgraphwidget.h @@ -8,6 +8,8 @@ #include <QWidget> #include <QQueue> +#include <chrono> + class ClientModel; QT_BEGIN_NAMESPACE @@ -22,14 +24,14 @@ class TrafficGraphWidget : public QWidget public: explicit TrafficGraphWidget(QWidget *parent = nullptr); void setClientModel(ClientModel *model); - int getGraphRangeMins() const; + std::chrono::minutes getGraphRange() const; protected: void paintEvent(QPaintEvent *) override; public Q_SLOTS: void updateRates(); - void setGraphRangeMins(int mins); + void setGraphRange(std::chrono::minutes new_range); void clear(); private: @@ -37,7 +39,7 @@ private: QTimer *timer; float fMax; - int nMins; + std::chrono::minutes m_range{0}; QQueue<float> vSamplesIn; QQueue<float> vSamplesOut; quint64 nLastBytesIn; diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 02d220db20..be5851d627 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -18,7 +18,6 @@ #include <interfaces/wallet.h> #include <key_io.h> #include <policy/policy.h> -#include <script/script.h> #include <util/system.h> #include <validation.h> #include <wallet/ismine.h> @@ -28,16 +27,13 @@ #include <QLatin1String> +using wallet::ISMINE_ALL; +using wallet::ISMINE_SPENDABLE; +using wallet::ISMINE_WATCH_ONLY; +using wallet::isminetype; + QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks) { - if (!status.is_final) - { - if (wtx.tx->nLockTime < LOCKTIME_THRESHOLD) - return tr("Open for %n more block(s)", "", wtx.tx->nLockTime - numBlocks); - else - return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.tx->nLockTime)); - } - else { int nDepth = status.depth_in_main_chain; if (nDepth < 0) { diff --git a/src/qt/transactiondescdialog.cpp b/src/qt/transactiondescdialog.cpp index 6f31d8463f..893752b227 100644 --- a/src/qt/transactiondescdialog.cpp +++ b/src/qt/transactiondescdialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 57c05a647e..3be7e1a969 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2018 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 270b8ef78c..fd9be52842 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 77fec93f0f..26144ba197 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -13,6 +13,10 @@ #include <QDateTime> +using wallet::ISMINE_SPENDABLE; +using wallet::ISMINE_WATCH_ONLY; +using wallet::isminetype; + /* Return positive answer if transaction should be shown in list. */ bool TransactionRecord::showTransaction() @@ -175,21 +179,8 @@ void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, cons status.depth = wtx.depth_in_main_chain; status.m_cur_block_hash = block_hash; - const bool up_to_date = ((int64_t)QDateTime::currentMSecsSinceEpoch() / 1000 - block_time < MAX_BLOCK_TIME_GAP); - if (up_to_date && !wtx.is_final) { - if (wtx.lock_time < LOCKTIME_THRESHOLD) { - status.status = TransactionStatus::OpenUntilBlock; - status.open_for = wtx.lock_time - numBlocks; - } - else - { - status.status = TransactionStatus::OpenUntilDate; - status.open_for = wtx.lock_time; - } - } // For generated transactions, determine maturity - else if(type == TransactionRecord::Generated) - { + if (type == TransactionRecord::Generated) { if (wtx.blocks_to_maturity > 0) { status.status = TransactionStatus::Immature; diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index fb88ca424f..dd34656d5f 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -30,8 +30,6 @@ public: enum Status { Confirmed, /**< Have 6 or more confirmations (normal tx) or fully mature (mined tx) **/ /// Normal (sent/received) transactions - OpenUntilDate, /**< Transaction not yet final, waiting for date */ - OpenUntilBlock, /**< Transaction not yet final, waiting for block */ Unconfirmed, /**< Not yet mined into a block **/ Confirming, /**< Confirmed, but waiting for the recommended number of confirmations **/ Conflicted, /**< Conflicts with other transaction or mempool **/ diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 23590ea4d2..44b4fee2e7 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -316,12 +316,6 @@ QString TransactionTableModel::formatTxStatus(const TransactionRecord *wtx) cons switch(wtx->status.status) { - case TransactionStatus::OpenUntilBlock: - status = tr("Open for %n more block(s)","",wtx->status.open_for); - break; - case TransactionStatus::OpenUntilDate: - status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for)); - break; case TransactionStatus::Unconfirmed: status = tr("Unconfirmed"); break; @@ -475,9 +469,6 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) { switch(wtx->status.status) { - case TransactionStatus::OpenUntilBlock: - case TransactionStatus::OpenUntilDate: - return COLOR_TX_STATUS_OPENUNTILDATE; case TransactionStatus::Unconfirmed: return QIcon(":/icons/transaction_0"); case TransactionStatus::Abandoned: diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 653f3dda6d..778ef04b77 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -19,6 +19,7 @@ #include <node/ui_interface.h> +#include <chrono> #include <optional> #include <QApplication> @@ -114,8 +115,8 @@ TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *pa amountWidget->setValidator(amountValidator); hlayout->addWidget(amountWidget); - // Delay before filtering transactions in ms - static const int input_filter_delay = 200; + // Delay before filtering transactions + static constexpr auto input_filter_delay{200ms}; QTimer* amount_typing_delay = new QTimer(this); amount_typing_delay->setSingleShot(true); @@ -510,7 +511,7 @@ void TransactionView::editLabel() : EditAddressDialog::EditSendingAddress, this); dlg->setModel(addressBook); dlg->loadRow(idx); - GUIUtil::ShowModalDialogAndDeleteOnClose(dlg); + GUIUtil::ShowModalDialogAsynchronously(dlg); } else { @@ -519,7 +520,7 @@ void TransactionView::editLabel() this); dlg->setModel(addressBook); dlg->setAddress(address); - GUIUtil::ShowModalDialogAndDeleteOnClose(dlg); + GUIUtil::ShowModalDialogAsynchronously(dlg); } } } diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 3e2321d91b..fe6e3ac7c0 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 4d246bc8dc..e68095f8e5 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index b9a9fcf3d1..b025bb367c 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -20,6 +20,7 @@ #include <wallet/wallet.h> #include <algorithm> +#include <chrono> #include <QApplication> #include <QMessageBox> @@ -28,6 +29,11 @@ #include <QTimer> #include <QWindow> +using wallet::WALLET_FLAG_BLANK_WALLET; +using wallet::WALLET_FLAG_DESCRIPTORS; +using wallet::WALLET_FLAG_DISABLE_PRIVATE_KEYS; +using wallet::WALLET_FLAG_EXTERNAL_SIGNER; + WalletController::WalletController(ClientModel& client_model, const PlatformStyle* platform_style, QObject* parent) : QObject(parent) , m_activity_thread(new QThread(this)) @@ -37,7 +43,7 @@ WalletController::WalletController(ClientModel& client_model, const PlatformStyl , m_platform_style(platform_style) , m_options_model(client_model.getOptionsModel()) { - m_handler_load_wallet = m_node.walletClient().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { + m_handler_load_wallet = m_node.walletLoader().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { getOrCreateWallet(std::move(wallet)); }); @@ -61,7 +67,7 @@ std::map<std::string, bool> WalletController::listWalletDir() const { QMutexLocker locker(&m_mutex); std::map<std::string, bool> wallets; - for (const std::string& name : m_node.walletClient().listWalletDir()) { + for (const std::string& name : m_node.walletLoader().listWalletDir()) { wallets[name] = false; } for (WalletModel* wallet_model : m_wallets) { @@ -254,12 +260,12 @@ void CreateWalletActivity::createWallet() flags |= WALLET_FLAG_EXTERNAL_SIGNER; } - QTimer::singleShot(500, worker(), [this, name, flags] { - std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().createWallet(name, m_passphrase, flags, m_error_message, m_warning_message); + 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); if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet)); - QTimer::singleShot(500, this, &CreateWalletActivity::finish); + QTimer::singleShot(500ms, this, &CreateWalletActivity::finish); }); } @@ -336,7 +342,7 @@ 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().walletClient().loadWallet(path, m_error_message, m_warning_message); + std::unique_ptr<interfaces::Wallet> wallet = node().walletLoader().loadWallet(path, m_error_message, m_warning_message); if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet)); @@ -359,7 +365,7 @@ void LoadWalletsActivity::load() tr("Loading wallets…")); QTimer::singleShot(0, worker(), [this] { - for (auto& wallet : node().walletClient().getWallets()) { + for (auto& wallet : node().walletLoader().getWallets()) { m_wallet_controller->getOrCreateWallet(std::move(wallet)); } diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h index bbd990228f..24f85c258c 100644 --- a/src/qt/walletcontroller.h +++ b/src/qt/walletcontroller.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 4ff92bf82c..91ce420a33 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -1,9 +1,10 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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 <qt/walletframe.h> +#include <fs.h> #include <node/ui_interface.h> #include <psbt.h> #include <qt/guiutil.h> @@ -14,6 +15,8 @@ #include <util/system.h> #include <cassert> +#include <fstream> +#include <string> #include <QApplication> #include <QClipboard> @@ -210,7 +213,7 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard) Q_EMIT message(tr("Error"), tr("PSBT file must be smaller than 100 MiB"), CClientUIInterface::MSG_ERROR); return; } - std::ifstream in(filename.toLocal8Bit().data(), std::ios::binary); + std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary}; data = std::string(std::istreambuf_iterator<char>{in}, {}); } @@ -223,7 +226,7 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard) auto dlg = new PSBTOperationsDialog(this, currentWalletModel(), clientModel); dlg->openWithPSBT(psbtx); - GUIUtil::ShowModalDialogAndDeleteOnClose(dlg); + GUIUtil::ShowModalDialogAsynchronously(dlg); } void WalletFrame::encryptWallet() diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index cfca5c4c5c..60c97ff76a 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 052453cf65..5ee32e79d5 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -36,6 +36,9 @@ #include <QSet> #include <QTimer> +using wallet::CCoinControl; +using wallet::CRecipient; +using wallet::DEFAULT_DISABLE_WALLET; WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel& client_model, const PlatformStyle *platformStyle, QObject *parent) : QObject(parent), @@ -480,10 +483,9 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) return false; } - const bool create_psbt = m_wallet->privateKeysDisabled(); - // allow a user based fee verification - QString questionString = create_psbt ? tr("Do you want to draft a transaction with fee increase?") : tr("Do you want to increase the fee?"); + /*: Asks a user if they would like to manually increase the fee of a transaction that has already been created. */ + QString questionString = tr("Do you want to increase the fee?"); questionString.append("<br />"); questionString.append("<table style=\"text-align: left;\">"); questionString.append("<tr><td>"); @@ -506,13 +508,13 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) questionString.append(tr("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.")); } - auto confirmationDialog = new SendConfirmationDialog(tr("Confirm fee bump"), questionString); + auto confirmationDialog = new SendConfirmationDialog(tr("Confirm fee bump"), questionString, "", "", SEND_CONFIRM_DELAY, !m_wallet->privateKeysDisabled(), getOptionsModel()->getEnablePSBTControls(), nullptr); confirmationDialog->setAttribute(Qt::WA_DeleteOnClose); // TODO: Replace QDialog::exec() with safer QDialog::show(). const auto retval = static_cast<QMessageBox::StandardButton>(confirmationDialog->exec()); // cancel sign&broadcast if user doesn't want to bump the fee - if (retval != QMessageBox::Yes) { + if (retval != QMessageBox::Yes && retval != QMessageBox::Save) { return false; } @@ -523,7 +525,7 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) } // Short-circuit if we are returning a bumped transaction PSBT to clipboard - if (create_psbt) { + if (retval == QMessageBox::Save) { PartiallySignedTransaction psbtx(mtx); bool complete = false; const TransactionError err = wallet().fillPSBT(SIGHASH_ALL, false /* sign */, true /* bip32derivs */, nullptr, psbtx, complete); @@ -539,6 +541,8 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash) return true; } + assert(!m_wallet->privateKeysDisabled()); + // sign bumped transaction if (!m_wallet->signBumpTransaction(mtx)) { QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't sign transaction.")); @@ -583,7 +587,7 @@ QString WalletModel::getDisplayName() const bool WalletModel::isMultiwallet() { - return m_node.walletClient().getWallets().size() > 1; + return m_node.walletLoader().getWallets().size() > 1; } void WalletModel::refresh(bool pk_hash_only) diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 47a21bcfcf..ad1239ccdc 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -32,16 +32,17 @@ class SendCoinsRecipient; class TransactionTableModel; class WalletModelTransaction; -class CCoinControl; class CKeyID; class COutPoint; -class COutput; class CPubKey; class uint256; namespace interfaces { class Node; } // namespace interfaces +namespace wallet { +class CCoinControl; +} // namespace wallet QT_BEGIN_NAMESPACE class QTimer; @@ -99,7 +100,7 @@ public: }; // prepare transaction for getting txfee before sending coins - SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const CCoinControl& coinControl); + SendCoinsReturn prepareTransaction(WalletModelTransaction &transaction, const wallet::CCoinControl& coinControl); // Send coins to a list of recipients SendCoinsReturn sendCoins(WalletModelTransaction &transaction); diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index d185ddb7e8..b5538b644f 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h index 0bae4bade3..28fb551364 100644 --- a/src/qt/walletmodeltransaction.h +++ b/src/qt/walletmodeltransaction.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index 7813b89e41..e7ec54721a 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -208,7 +208,7 @@ void WalletView::encryptWallet() auto dlg = new AskPassphraseDialog(AskPassphraseDialog::Encrypt, this); dlg->setModel(walletModel); connect(dlg, &QDialog::finished, this, &WalletView::encryptionStatusChanged); - GUIUtil::ShowModalDialogAndDeleteOnClose(dlg); + GUIUtil::ShowModalDialogAsynchronously(dlg); } void WalletView::backupWallet() @@ -235,16 +235,18 @@ void WalletView::changePassphrase() { auto dlg = new AskPassphraseDialog(AskPassphraseDialog::ChangePass, this); dlg->setModel(walletModel); - GUIUtil::ShowModalDialogAndDeleteOnClose(dlg); + GUIUtil::ShowModalDialogAsynchronously(dlg); } void WalletView::unlockWallet() { // Unlock wallet when requested by wallet model if (walletModel->getEncryptionStatus() == WalletModel::Locked) { - auto dlg = new AskPassphraseDialog(AskPassphraseDialog::Unlock, this); - dlg->setModel(walletModel); - GUIUtil::ShowModalDialogAndDeleteOnClose(dlg); + AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, this); + dlg.setModel(walletModel); + // A modal dialog must be synchronous here as expected + // in the WalletModel::requestUnlock() function. + dlg.exec(); } } diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 86a835c484..2f9d344bc8 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/qt/winshutdownmonitor.h b/src/qt/winshutdownmonitor.h index bf399edcf3..72655da3da 100644 --- a/src/qt/winshutdownmonitor.h +++ b/src/qt/winshutdownmonitor.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-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. diff --git a/src/random.cpp b/src/random.cpp index 174f4cef31..b862510524 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -19,6 +19,7 @@ #include <sync.h> // for Mutex #include <util/time.h> // for GetTimeMicros() +#include <cmath> #include <stdlib.h> #include <thread> @@ -31,10 +32,8 @@ #include <sys/syscall.h> #include <linux/random.h> #endif -#if defined(HAVE_GETENTROPY) || (defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)) -#include <unistd.h> -#endif #if defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX) +#include <unistd.h> #include <sys/random.h> #endif #ifdef HAVE_SYSCTL_ARND @@ -304,16 +303,14 @@ void GetOSRand(unsigned char *ent32) RandFailure(); } } -#elif defined(HAVE_GETENTROPY) && defined(__OpenBSD__) - /* On OpenBSD this can return up to 256 bytes of entropy, will return an - * error if more are requested. - * The call cannot return less than the requested number of bytes. - getentropy is explicitly limited to openbsd here, as a similar (but not - the same) function may exist on other platforms via glibc. +#elif defined(__OpenBSD__) + /* OpenBSD. From the arc4random(3) man page: + "Use of these functions is encouraged for almost all random number + consumption because the other interfaces are deficient in either + quality, portability, standardization, or availability." + The function call is always successful. */ - if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) { - RandFailure(); - } + arc4random_buf(ent32, NUM_OS_RANDOM_BYTES); // Silence a compiler warning about unused function. (void)GetDevURandom; #elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX) @@ -714,3 +711,9 @@ void RandomInit() ReportHardwareRand(); } + +std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval) +{ + double unscaled = -std::log1p(GetRand(uint64_t{1} << 48) * -0.0000000000000035527136788 /* -1/2^48 */); + return now + std::chrono::duration_cast<std::chrono::microseconds>(unscaled * average_interval + 0.5us); +} diff --git a/src/random.h b/src/random.h index 0c6dc24983..97302d61ab 100644 --- a/src/random.h +++ b/src/random.h @@ -10,7 +10,7 @@ #include <crypto/common.h> #include <uint256.h> -#include <chrono> // For std::chrono::microseconds +#include <chrono> #include <cstdint> #include <limits> @@ -82,6 +82,18 @@ D GetRandomDuration(typename std::common_type<D>::type max) noexcept }; constexpr auto GetRandMicros = GetRandomDuration<std::chrono::microseconds>; constexpr auto GetRandMillis = GetRandomDuration<std::chrono::milliseconds>; + +/** + * Return a timestamp in the future sampled from an exponential distribution + * (https://en.wikipedia.org/wiki/Exponential_distribution). This distribution + * is memoryless and should be used for repeated network events (e.g. sending a + * certain type of message) to minimize leaking information to observers. + * + * The probability of an event occurring before time x is 1 - e^-(x/a) where a + * is the average interval between events. + * */ +std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval); + int GetRandInt(int nMax) noexcept; uint256 GetRandHash() noexcept; diff --git a/src/randomenv.cpp b/src/randomenv.cpp index bf23ea4a12..388841289a 100644 --- a/src/randomenv.cpp +++ b/src/randomenv.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/randomenv.h b/src/randomenv.h index 746516b79b..b192ff40e0 100644 --- a/src/randomenv.h +++ b/src/randomenv.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/rest.cpp b/src/rest.cpp index 2c0ead26c7..063872b47a 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -1,12 +1,14 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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 <blockfilter.h> #include <chain.h> #include <chainparams.h> #include <core_io.h> #include <httpserver.h> +#include <index/blockfilterindex.h> #include <index/txindex.h> #include <node/blockstorage.h> #include <node/context.h> @@ -30,7 +32,13 @@ #include <univalue.h> +using node::GetTransaction; +using node::IsBlockPruned; +using node::NodeContext; +using node::ReadBlockFromDisk; + static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once +static constexpr unsigned int MAX_REST_HEADERS_RESULTS = 2000; enum class RetFormat { UNDEF, @@ -191,8 +199,8 @@ static bool rest_headers(const std::any& context, return RESTERR(req, HTTP_BAD_REQUEST, "No header count specified. Use /rest/headers/<count>/<hash>.<ext>."); const auto parsed_count{ToIntegral<size_t>(path[0])}; - if (!parsed_count.has_value() || *parsed_count < 1 || *parsed_count > 2000) { - return RESTERR(req, HTTP_BAD_REQUEST, "Header count out of range: " + path[0]); + if (!parsed_count.has_value() || *parsed_count < 1 || *parsed_count > MAX_REST_HEADERS_RESULTS) { + return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Header count is invalid or out of acceptable range (1-%u): %s", MAX_REST_HEADERS_RESULTS, path[0])); } std::string hashStr = path[1]; @@ -255,7 +263,7 @@ static bool rest_headers(const std::any& context, return true; } default: { - return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: .bin, .hex, .json)"); + return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")"); } } } @@ -338,6 +346,209 @@ static bool rest_block_notxdetails(const std::any& context, HTTPRequest* req, co return rest_block(context, req, strURIPart, TxVerbosity::SHOW_TXID); } +static bool rest_filter_header(const std::any& context, HTTPRequest* req, const std::string& strURIPart) +{ + if (!CheckWarmup(req)) return false; + + std::string param; + const RetFormat rf = ParseDataFormat(param, strURIPart); + + std::vector<std::string> uri_parts; + boost::split(uri_parts, param, boost::is_any_of("/")); + if (uri_parts.size() != 3) { + return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/blockfilterheaders/<filtertype>/<count>/<blockhash>"); + } + + uint256 block_hash; + if (!ParseHashStr(uri_parts[2], block_hash)) { + return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + uri_parts[2]); + } + + BlockFilterType filtertype; + if (!BlockFilterTypeByName(uri_parts[0], filtertype)) { + return RESTERR(req, HTTP_BAD_REQUEST, "Unknown filtertype " + uri_parts[0]); + } + + BlockFilterIndex* index = GetBlockFilterIndex(filtertype); + if (!index) { + return RESTERR(req, HTTP_BAD_REQUEST, "Index is not enabled for filtertype " + uri_parts[0]); + } + + const auto parsed_count{ToIntegral<size_t>(uri_parts[1])}; + if (!parsed_count.has_value() || *parsed_count < 1 || *parsed_count > MAX_REST_HEADERS_RESULTS) { + return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Header count is invalid or out of acceptable range (1-%u): %s", MAX_REST_HEADERS_RESULTS, uri_parts[1])); + } + + std::vector<const CBlockIndex*> headers; + headers.reserve(*parsed_count); + { + ChainstateManager* maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) return false; + ChainstateManager& chainman = *maybe_chainman; + LOCK(cs_main); + CChain& active_chain = chainman.ActiveChain(); + const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block_hash); + while (pindex != nullptr && active_chain.Contains(pindex)) { + headers.push_back(pindex); + if (headers.size() == *parsed_count) + break; + pindex = active_chain.Next(pindex); + } + } + + bool index_ready = index->BlockUntilSyncedToCurrentChain(); + + std::vector<uint256> filter_headers; + filter_headers.reserve(*parsed_count); + for (const CBlockIndex* pindex : headers) { + uint256 filter_header; + if (!index->LookupFilterHeader(pindex, filter_header)) { + std::string errmsg = "Filter not found."; + + if (!index_ready) { + errmsg += " Block filters are still in the process of being indexed."; + } else { + errmsg += " This error is unexpected and indicates index corruption."; + } + + return RESTERR(req, HTTP_NOT_FOUND, errmsg); + } + filter_headers.push_back(filter_header); + } + + switch (rf) { + case RetFormat::BINARY: { + CDataStream ssHeader{SER_NETWORK, PROTOCOL_VERSION}; + for (const uint256& header : filter_headers) { + ssHeader << header; + } + + std::string binaryHeader = ssHeader.str(); + req->WriteHeader("Content-Type", "application/octet-stream"); + req->WriteReply(HTTP_OK, binaryHeader); + return true; + } + case RetFormat::HEX: { + CDataStream ssHeader{SER_NETWORK, PROTOCOL_VERSION}; + for (const uint256& header : filter_headers) { + ssHeader << header; + } + + std::string strHex = HexStr(ssHeader) + "\n"; + req->WriteHeader("Content-Type", "text/plain"); + req->WriteReply(HTTP_OK, strHex); + return true; + } + case RetFormat::JSON: { + UniValue jsonHeaders(UniValue::VARR); + for (const uint256& header : filter_headers) { + jsonHeaders.push_back(header.GetHex()); + } + + std::string strJSON = jsonHeaders.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: " + AvailableDataFormatsString() + ")"); + } + } +} + +static bool rest_block_filter(const std::any& context, HTTPRequest* req, const std::string& strURIPart) +{ + if (!CheckWarmup(req)) return false; + + std::string param; + const RetFormat rf = ParseDataFormat(param, strURIPart); + + // request is sent over URI scheme /rest/blockfilter/filtertype/blockhash + std::vector<std::string> uri_parts; + boost::split(uri_parts, param, boost::is_any_of("/")); + if (uri_parts.size() != 2) { + return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/blockfilter/<filtertype>/<blockhash>"); + } + + uint256 block_hash; + if (!ParseHashStr(uri_parts[1], block_hash)) { + return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + uri_parts[1]); + } + + BlockFilterType filtertype; + if (!BlockFilterTypeByName(uri_parts[0], filtertype)) { + return RESTERR(req, HTTP_BAD_REQUEST, "Unknown filtertype " + uri_parts[0]); + } + + BlockFilterIndex* index = GetBlockFilterIndex(filtertype); + if (!index) { + return RESTERR(req, HTTP_BAD_REQUEST, "Index is not enabled for filtertype " + uri_parts[0]); + } + + const CBlockIndex* block_index; + bool block_was_connected; + { + ChainstateManager* maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) return false; + ChainstateManager& chainman = *maybe_chainman; + LOCK(cs_main); + block_index = chainman.m_blockman.LookupBlockIndex(block_hash); + if (!block_index) { + return RESTERR(req, HTTP_NOT_FOUND, uri_parts[1] + " not found"); + } + block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS); + } + + bool index_ready = index->BlockUntilSyncedToCurrentChain(); + + BlockFilter filter; + if (!index->LookupFilter(block_index, filter)) { + std::string errmsg = "Filter not found."; + + if (!block_was_connected) { + errmsg += " Block was not connected to active chain."; + } else if (!index_ready) { + errmsg += " Block filters are still in the process of being indexed."; + } else { + errmsg += " This error is unexpected and indicates index corruption."; + } + + return RESTERR(req, HTTP_NOT_FOUND, errmsg); + } + + switch (rf) { + case RetFormat::BINARY: { + CDataStream ssResp{SER_NETWORK, PROTOCOL_VERSION}; + ssResp << filter; + + std::string binaryResp = ssResp.str(); + req->WriteHeader("Content-Type", "application/octet-stream"); + req->WriteReply(HTTP_OK, binaryResp); + return true; + } + case RetFormat::HEX: { + CDataStream ssResp{SER_NETWORK, PROTOCOL_VERSION}; + ssResp << filter; + + std::string strHex = HexStr(ssResp) + "\n"; + req->WriteHeader("Content-Type", "text/plain"); + req->WriteReply(HTTP_OK, strHex); + return true; + } + case RetFormat::JSON: { + UniValue ret(UniValue::VOBJ); + ret.pushKV("filter", HexStr(filter.GetEncodedFilter())); + std::string strJSON = ret.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: " + AvailableDataFormatsString() + ")"); + } + } +} + // A bit of a hack - dependency on a function defined in rpc/blockchain.cpp RPCHelpMan getblockchaininfo(); @@ -718,6 +929,8 @@ static const struct { {"/rest/tx/", rest_tx}, {"/rest/block/notxdetails/", rest_block_notxdetails}, {"/rest/block/", rest_block_extended}, + {"/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}, diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 050d9dd980..69204e346a 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -19,10 +19,10 @@ #include <hash.h> #include <index/blockfilterindex.h> #include <index/coinstatsindex.h> +#include <logging/timer.h> #include <net.h> #include <net_processing.h> #include <node/blockstorage.h> -#include <logging/timer.h> #include <node/coinstats.h> #include <node/context.h> #include <node/utxo_snapshot.h> @@ -56,6 +56,16 @@ #include <memory> #include <mutex> +using node::BlockManager; +using node::CCoinsStats; +using node::CoinStatsHashType; +using node::GetUTXOStats; +using node::IsBlockPruned; +using node::NodeContext; +using node::ReadBlockFromDisk; +using node::SnapshotMetadata; +using node::UndoReadFromDisk; + struct CUpdatedBlock { uint256 hash; @@ -175,7 +185,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn case TxVerbosity::SHOW_DETAILS: case TxVerbosity::SHOW_DETAILS_AND_PREVOUT: CBlockUndo blockUndo; - const bool have_undo = !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex); + const bool have_undo{WITH_LOCK(::cs_main, return !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))}; for (size_t i = 0; i < block.vtx.size(); ++i) { const CTransactionRef& tx = block.vtx.at(i); @@ -185,6 +195,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags(), txundo, verbosity); txs.push_back(objTx); } + break; } result.pushKV("tx", txs); @@ -779,17 +790,15 @@ static RPCHelpMan getblockfrompeer() { return RPCHelpMan{ "getblockfrompeer", - "\nAttempt to fetch block from a given peer.\n" - "\nWe must have the header for this block, e.g. using submitheader.\n" - "\nReturns {} if a block-request was successfully scheduled\n", + "Attempt to fetch block from a given peer.\n\n" + "We must have the header for this block, e.g. using submitheader.\n" + "Subsequent calls for the same block and a new peer will cause the response from the previous peer to be ignored.\n\n" + "Returns an empty JSON object if the request was successfully scheduled.", { - {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, - {"nodeid", RPCArg::Type::NUM, RPCArg::Optional::NO, "The node ID (see getpeerinfo for node IDs)"}, + {"block_hash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"}, + {"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to fetch it from (see getpeerinfo for peer IDs)"}, }, - RPCResult{RPCResult::Type::OBJ, "", "", - { - {RPCResult::Type::STR, "warnings", /*optional=*/true, "any warnings"}, - }}, + RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}}, RPCExamples{ HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0") + HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0") @@ -799,31 +808,25 @@ static RPCHelpMan getblockfrompeer() const NodeContext& node = EnsureAnyNodeContext(request.context); ChainstateManager& chainman = EnsureChainman(node); PeerManager& peerman = EnsurePeerman(node); - CConnman& connman = EnsureConnman(node); - uint256 hash(ParseHashV(request.params[0], "hash")); - - const NodeId nodeid = static_cast<NodeId>(request.params[1].get_int64()); + const uint256& block_hash{ParseHashV(request.params[0], "block_hash")}; + const NodeId peer_id{request.params[1].get_int64()}; - // Check that the peer with nodeid exists - if (!connman.ForNode(nodeid, [](CNode* node) {return true;})) { - throw JSONRPCError(RPC_MISC_ERROR, strprintf("Peer nodeid %d does not exist", nodeid)); - } - - const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(hash);); + const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(block_hash);); if (!index) { throw JSONRPCError(RPC_MISC_ERROR, "Block header missing"); } - UniValue result = UniValue::VOBJ; + const bool block_has_data = WITH_LOCK(::cs_main, return index->nStatus & BLOCK_HAVE_DATA); + if (block_has_data) { + throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded"); + } - if (index->nStatus & BLOCK_HAVE_DATA) { - result.pushKV("warnings", "Block already downloaded"); - } else if (!peerman.FetchBlock(nodeid, hash, *index)) { - throw JSONRPCError(RPC_MISC_ERROR, "Failed to fetch block from peer"); + if (const auto err{peerman.FetchBlock(peer_id, *index)}) { + throw JSONRPCError(RPC_MISC_ERROR, err.value()); } - return result; + return UniValue::VOBJ; }, }; } @@ -927,8 +930,9 @@ static RPCHelpMan getblockheader() }; } -static CBlock GetBlockChecked(const CBlockIndex* pblockindex) +static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); CBlock block; if (IsBlockPruned(pblockindex)) { throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); @@ -944,8 +948,9 @@ static CBlock GetBlockChecked(const CBlockIndex* pblockindex) return block; } -static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) +static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { + AssertLockHeld(::cs_main); CBlockUndo blockUndo; if (IsBlockPruned(pblockindex)) { throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)"); @@ -967,7 +972,7 @@ static RPCHelpMan getblock() "If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).\n", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, - {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"}, + {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs"}, }, { RPCResult{"for verbosity = 0", @@ -1009,6 +1014,37 @@ static RPCHelpMan getblock() }}, }}, }}, + RPCResult{"for verbosity = 3", + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::ELISION, "", "Same output as verbosity = 2"}, + {RPCResult::Type::ARR, "tx", "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::ARR, "vin", "", + { + {RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::ELISION, "", "The same output as verbosity = 2"}, + {RPCResult::Type::OBJ, "prevout", "(Only if undo information is available)", + { + {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::OBJ, "scriptPubKey", "", + { + {RPCResult::Type::STR, "asm", "The asm"}, + {RPCResult::Type::STR, "hex", "The hex"}, + {RPCResult::Type::STR, "address", /* optional */ true, "The Bitcoin address (only if a well-defined address exists)"}, + {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, + }}, + }}, + }}, + }}, + }}, + }}, + }}, }, RPCExamples{ HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") @@ -1080,7 +1116,7 @@ static RPCHelpMan pruneblockchain() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - if (!fPruneMode) + if (!node::fPruneMode) throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode."); ChainstateManager& chainman = EnsureAnyChainman(request.context); @@ -1242,9 +1278,10 @@ static RPCHelpMan gettxoutsetinfo() ret.pushKV("hash_serialized_2", stats.hashSerialized.GetHex()); } if (hash_type == CoinStatsHashType::MUHASH) { - ret.pushKV("muhash", stats.hashSerialized.GetHex()); + ret.pushKV("muhash", stats.hashSerialized.GetHex()); } - ret.pushKV("total_amount", ValueFromAmount(stats.nTotalAmount)); + CHECK_NONFATAL(stats.total_amount.has_value()); + ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value())); if (!stats.index_used) { ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions)); ret.pushKV("disk_size", stats.nDiskSize); @@ -1297,6 +1334,7 @@ static RPCHelpMan gettxout() {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT}, {RPCResult::Type::OBJ, "scriptPubKey", "", { {RPCResult::Type::STR, "asm", ""}, + {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, {RPCResult::Type::STR_HEX, "hex", ""}, {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, @@ -1392,7 +1430,7 @@ static RPCHelpMan verifychain() }; } -static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue& softforks, const Consensus::Params& params, Consensus::BuriedDeployment dep) +static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const Consensus::Params& params, Consensus::BuriedDeployment dep) { // For buried deployments. @@ -1400,63 +1438,94 @@ static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue& UniValue rv(UniValue::VOBJ); rv.pushKV("type", "buried"); - // getblockchaininfo reports the softfork as active from when the chain height is + // getdeploymentinfo reports the softfork as active from when the chain height is // one below the activation height - rv.pushKV("active", DeploymentActiveAfter(active_chain_tip, params, dep)); + rv.pushKV("active", DeploymentActiveAfter(blockindex, params, dep)); rv.pushKV("height", params.DeploymentHeight(dep)); softforks.pushKV(DeploymentName(dep), rv); } -static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue& softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) +static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) { // For BIP9 deployments. if (!DeploymentEnabled(consensusParams, id)) return; + if (blockindex == nullptr) return; + + auto get_state_name = [](const ThresholdState state) -> std::string { + switch (state) { + case ThresholdState::DEFINED: return "defined"; + case ThresholdState::STARTED: return "started"; + case ThresholdState::LOCKED_IN: return "locked_in"; + case ThresholdState::ACTIVE: return "active"; + case ThresholdState::FAILED: return "failed"; + } + return "invalid"; + }; UniValue bip9(UniValue::VOBJ); - const ThresholdState thresholdState = g_versionbitscache.State(active_chain_tip, consensusParams, id); - switch (thresholdState) { - case ThresholdState::DEFINED: bip9.pushKV("status", "defined"); break; - case ThresholdState::STARTED: bip9.pushKV("status", "started"); break; - case ThresholdState::LOCKED_IN: bip9.pushKV("status", "locked_in"); break; - case ThresholdState::ACTIVE: bip9.pushKV("status", "active"); break; - case ThresholdState::FAILED: bip9.pushKV("status", "failed"); break; - } - const bool has_signal = (ThresholdState::STARTED == thresholdState || ThresholdState::LOCKED_IN == thresholdState); + + const ThresholdState next_state = g_versionbitscache.State(blockindex, consensusParams, id); + const ThresholdState current_state = g_versionbitscache.State(blockindex->pprev, consensusParams, id); + + const bool has_signal = (ThresholdState::STARTED == current_state || ThresholdState::LOCKED_IN == current_state); + + // BIP9 parameters if (has_signal) { bip9.pushKV("bit", consensusParams.vDeployments[id].bit); } bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime); bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout); - int64_t since_height = g_versionbitscache.StateSinceHeight(active_chain_tip, consensusParams, id); - bip9.pushKV("since", since_height); + bip9.pushKV("min_activation_height", consensusParams.vDeployments[id].min_activation_height); + + // BIP9 status + bip9.pushKV("status", get_state_name(current_state)); + bip9.pushKV("since", g_versionbitscache.StateSinceHeight(blockindex->pprev, consensusParams, id)); + bip9.pushKV("status-next", get_state_name(next_state)); + + // BIP9 signalling status, if applicable if (has_signal) { UniValue statsUV(UniValue::VOBJ); - BIP9Stats statsStruct = g_versionbitscache.Statistics(active_chain_tip, consensusParams, id); + std::vector<bool> signals; + BIP9Stats statsStruct = g_versionbitscache.Statistics(blockindex, consensusParams, id, &signals); statsUV.pushKV("period", statsStruct.period); statsUV.pushKV("elapsed", statsStruct.elapsed); statsUV.pushKV("count", statsStruct.count); - if (ThresholdState::LOCKED_IN != thresholdState) { + if (ThresholdState::LOCKED_IN != current_state) { statsUV.pushKV("threshold", statsStruct.threshold); statsUV.pushKV("possible", statsStruct.possible); } bip9.pushKV("statistics", statsUV); + + std::string sig; + sig.reserve(signals.size()); + for (const bool s : signals) { + sig.push_back(s ? '#' : '-'); + } + bip9.pushKV("signalling", sig); } - bip9.pushKV("min_activation_height", consensusParams.vDeployments[id].min_activation_height); UniValue rv(UniValue::VOBJ); rv.pushKV("type", "bip9"); - rv.pushKV("bip9", bip9); - if (ThresholdState::ACTIVE == thresholdState) { - rv.pushKV("height", since_height); + if (ThresholdState::ACTIVE == next_state) { + rv.pushKV("height", g_versionbitscache.StateSinceHeight(blockindex, consensusParams, id)); } - rv.pushKV("active", ThresholdState::ACTIVE == thresholdState); + rv.pushKV("active", ThresholdState::ACTIVE == next_state); + rv.pushKV("bip9", bip9); softforks.pushKV(DeploymentName(id), rv); } +namespace { +/* TODO: when -deprecatedrpc=softforks is removed, drop these */ +UniValue DeploymentInfo(const CBlockIndex* tip, const Consensus::Params& consensusParams); +extern const std::vector<RPCResult> RPCHelpForDeployment; +} + +// used by rest.cpp:rest_chaininfo, so cannot be static RPCHelpMan getblockchaininfo() { + /* TODO: from v24, remove -deprecatedrpc=softforks */ return RPCHelpMan{"getblockchaininfo", "Returns an object containing various state info regarding blockchain processing.\n", {}, @@ -1478,31 +1547,11 @@ RPCHelpMan getblockchaininfo() {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "lowest-height complete block stored (only present if pruning is enabled)"}, {RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"}, {RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"}, - {RPCResult::Type::OBJ_DYN, "softforks", "status of softforks", + {RPCResult::Type::OBJ_DYN, "softforks", "(DEPRECATED, returned only if config option -deprecatedrpc=softforks is passed) status of softforks", { {RPCResult::Type::OBJ, "xxxx", "name of the softfork", - { - {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""}, - {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)", - { - {RPCResult::Type::STR, "status", "one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\""}, - {RPCResult::Type::NUM, "bit", /*optional=*/true, "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" and \"locked_in\" status)"}, - {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"}, - {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"}, - {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"}, - {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"}, - {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)", - { - {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"}, - {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"}, - {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"}, - {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"}, - {RPCResult::Type::BOOL, "possible", /*optional=*/true, "returns false if there are not enough blocks left in this period to pass activation threshold (only for \"started\" status)"}, - }}, - }}, - {RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"}, - {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"}, - }}, + RPCHelpForDeployment + }, }}, {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"}, }}, @@ -1512,6 +1561,7 @@ RPCHelpMan getblockchaininfo() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + const ArgsManager& args{EnsureAnyArgsman(request.context)}; ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); CChainState& active_chainstate = chainman.ActiveChainstate(); @@ -1530,9 +1580,9 @@ RPCHelpMan getblockchaininfo() obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip)); obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload()); obj.pushKV("chainwork", tip->nChainWork.GetHex()); - obj.pushKV("size_on_disk", CalculateCurrentUsage()); - obj.pushKV("pruned", fPruneMode); - if (fPruneMode) { + obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage()); + obj.pushKV("pruned", node::fPruneMode); + if (node::fPruneMode) { const CBlockIndex* block = tip; CHECK_NONFATAL(block); while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) { @@ -1542,23 +1592,17 @@ RPCHelpMan getblockchaininfo() obj.pushKV("pruneheight", block->nHeight); // if 0, execution bypasses the whole if block. - bool automatic_pruning = (gArgs.GetIntArg("-prune", 0) != 1); + bool automatic_pruning{args.GetIntArg("-prune", 0) != 1}; obj.pushKV("automatic_pruning", automatic_pruning); if (automatic_pruning) { - obj.pushKV("prune_target_size", nPruneTarget); + obj.pushKV("prune_target_size", node::nPruneTarget); } } - const Consensus::Params& consensusParams = Params().GetConsensus(); - UniValue softforks(UniValue::VOBJ); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_DERSIG); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_CLTV); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_CSV); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_SEGWIT); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_TAPROOT); - obj.pushKV("softforks", softforks); + if (IsDeprecatedRPCEnabled("softforks")) { + const Consensus::Params& consensusParams = Params().GetConsensus(); + obj.pushKV("softforks", DeploymentInfo(tip, consensusParams)); + } obj.pushKV("warnings", GetWarnings(false).original); return obj; @@ -1566,6 +1610,92 @@ RPCHelpMan getblockchaininfo() }; } +namespace { +const std::vector<RPCResult> RPCHelpForDeployment{ + {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""}, + {RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"}, + {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"}, + {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)", + { + {RPCResult::Type::NUM, "bit", /*optional=*/true, "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" and \"locked_in\" status)"}, + {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"}, + {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"}, + {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"}, + {RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"}, + {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"}, + {RPCResult::Type::STR, "status-next", "status of deployment at the next block"}, + {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)", + { + {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"}, + {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"}, + {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"}, + {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"}, + {RPCResult::Type::BOOL, "possible", /*optional=*/true, "returns false if there are not enough blocks left in this period to pass activation threshold (only for \"started\" status)"}, + }}, + {RPCResult::Type::STR, "signalling", "indicates blocks that signalled with a # and blocks that did not with a -"}, + }}, +}; + +UniValue DeploymentInfo(const CBlockIndex* blockindex, const Consensus::Params& consensusParams) +{ + UniValue softforks(UniValue::VOBJ); + SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB); + SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_DERSIG); + SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_CLTV); + SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_CSV); + SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_SEGWIT); + SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); + SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_TAPROOT); + return softforks; +} +} // anon namespace + +static RPCHelpMan getdeploymentinfo() +{ + return RPCHelpMan{"getdeploymentinfo", + "Returns an object containing various state info regarding deployments of consensus changes.", + { + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Default{"hash of current chain tip"}, "The block hash at which to query deployment state"}, + }, + RPCResult{ + RPCResult::Type::OBJ, "", "", { + {RPCResult::Type::STR, "hash", "requested block hash (or tip)"}, + {RPCResult::Type::NUM, "height", "requested block height (or tip)"}, + {RPCResult::Type::OBJ, "deployments", "", { + {RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment} + }}, + } + }, + RPCExamples{ HelpExampleCli("getdeploymentinfo", "") + HelpExampleRpc("getdeploymentinfo", "") }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue + { + const ChainstateManager& chainman = EnsureAnyChainman(request.context); + LOCK(cs_main); + const CChainState& active_chainstate = chainman.ActiveChainstate(); + + const CBlockIndex* blockindex; + if (request.params[0].isNull()) { + blockindex = active_chainstate.m_chain.Tip(); + CHECK_NONFATAL(blockindex); + } else { + const uint256 hash(ParseHashV(request.params[0], "blockhash")); + blockindex = chainman.m_blockman.LookupBlockIndex(hash); + if (!blockindex) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + } + } + + const Consensus::Params& consensusParams = Params().GetConsensus(); + + UniValue deploymentinfo(UniValue::VOBJ); + deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString()); + deploymentinfo.pushKV("height", blockindex->nHeight); + deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, consensusParams)); + return deploymentinfo; + }, + }; +} + /** Comparison function for sorting the getchaintips heads. */ struct CompareBlocksByHeight { @@ -1709,7 +1839,7 @@ static RPCHelpMan getmempoolinfo() {RPCResult::Type::NUM, "size", "Current tx count"}, {RPCResult::Type::NUM, "bytes", "Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted"}, {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"}, - {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritizetransaction"}, + {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritisetransaction"}, {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"}, {RPCResult::Type::STR_AMOUNT, "mempoolminfee", "Minimum fee rate in " + CURRENCY_UNIT + "/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee"}, {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"}, @@ -2238,10 +2368,9 @@ static RPCHelpMan savemempool() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + const ArgsManager& args{EnsureAnyArgsman(request.context)}; const CTxMemPool& mempool = EnsureAnyMemPool(request.context); - const NodeContext& node = EnsureAnyNodeContext(request.context); - if (!mempool.IsLoaded()) { throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet"); } @@ -2251,7 +2380,7 @@ static RPCHelpMan savemempool() } UniValue ret(UniValue::VOBJ); - ret.pushKV("filename", fs::path((node.args->GetDataDirNet() / "mempool.dat")).u8string()); + ret.pushKV("filename", fs::path((args.GetDataDirNet() / "mempool.dat")).u8string()); return ret; }, @@ -2576,13 +2705,9 @@ static RPCHelpMan dumptxoutset() { return RPCHelpMan{ "dumptxoutset", - "\nWrite the serialized UTXO set to disk.\n", + "Write the serialized UTXO set to disk.", { - {"path", - RPCArg::Type::STR, - RPCArg::Optional::NO, - /* default_val */ "", - "path to the output file. If relative, will be prefixed by datadir."}, + {"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."}, }, RPCResult{ RPCResult::Type::OBJ, "", "", @@ -2600,10 +2725,11 @@ static RPCHelpMan dumptxoutset() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const fs::path path = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), fs::u8path(request.params[0].get_str())); + const ArgsManager& args{EnsureAnyArgsman(request.context)}; + const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str())); // Write to a temporary path and then move into `path` on completion // to avoid confusion due to an interruption. - const fs::path temppath = fsbridge::AbsPathJoin(gArgs.GetDataDirNet(), fs::u8path(request.params[0].get_str() + ".incomplete")); + const fs::path temppath = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str() + ".incomplete")); if (fs::exists(path)) { throw JSONRPCError( @@ -2716,6 +2842,7 @@ static const CRPCCommand commands[] = { "blockchain", &getblockheader, }, { "blockchain", &getchaintips, }, { "blockchain", &getdifficulty, }, + { "blockchain", &getdeploymentinfo, }, { "blockchain", &getmempoolancestors, }, { "blockchain", &getmempooldescendants, }, { "blockchain", &getmempoolentry, }, diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 99e744fdb3..1f51d7c1ad 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -21,9 +21,10 @@ class CBlock; class CBlockIndex; class CChainState; class CTxMemPool; -class ChainstateManager; class UniValue; +namespace node { struct NodeContext; +} // namespace node static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5; @@ -58,7 +59,7 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], * @return a UniValue map containing metadata about the snapshot. */ UniValue CreateUTXOSnapshot( - NodeContext& node, + node::NodeContext& node, CChainState& chainstate, CAutoFile& afile, const fs::path& path, diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index a171972da3..c480a093a4 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -60,7 +60,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getbalance", 1, "minconf" }, { "getbalance", 2, "include_watchonly" }, { "getbalance", 3, "avoid_reuse" }, - { "getblockfrompeer", 1, "nodeid" }, + { "getblockfrompeer", 1, "peer_id" }, { "getblockhash", 0, "height" }, { "waitforblockheight", 0, "height" }, { "waitforblockheight", 1, "timeout" }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 6e67832b31..0554367672 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -41,6 +41,13 @@ #include <memory> #include <stdint.h> +using node::BlockAssembler; +using node::CBlockTemplate; +using node::IncrementExtraNonce; +using node::NodeContext; +using node::RegenerateCommitments; +using node::UpdateTime; + /** * Return average network hashes per second based on the last 'lookup' blocks, * or from the last difficulty change if 'lookup' is nonpositive. diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 7705051df9..8d574e0359 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -35,6 +35,8 @@ #include <univalue.h> +using node::NodeContext; + static RPCHelpMan validateaddress() { return RPCHelpMan{ diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 557b1296a6..3d7c00edfc 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -32,6 +32,8 @@ #include <univalue.h> +using node::NodeContext; + const std::vector<std::string> CONNECTION_TYPE_DOC{ "outbound-full-relay (default automatic connections)", "block-relay-only (does not relay transactions or addresses)", @@ -646,7 +648,7 @@ static RPCHelpMan getnetworkinfo() obj.pushKV("incrementalfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK())); UniValue localAddresses(UniValue::VARR); { - LOCK(cs_mapLocalHost); + LOCK(g_maplocalhost_mutex); for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost) { UniValue rec(UniValue::VOBJ); diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h index 2fc9f55eba..75e42e4c88 100644 --- a/src/rpc/protocol.h +++ b/src/rpc/protocol.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 9be5c82311..ff0d8a4e0f 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -45,6 +45,15 @@ #include <univalue.h> +using node::AnalyzePSBT; +using node::BroadcastTransaction; +using node::DEFAULT_MAX_RAW_TX_FEE_RATE; +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) { // Call into TxToUniv() in bitcoin-common to decode the transaction hex. @@ -170,6 +179,7 @@ static RPCHelpMan getrawtransaction() {RPCResult::Type::OBJ, "scriptPubKey", "", { {RPCResult::Type::STR, "asm", "the asm"}, + {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, {RPCResult::Type::STR, "hex", "the hex"}, {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, @@ -231,7 +241,8 @@ static RPCHelpMan getrawtransaction() if (!tx) { std::string errmsg; if (blockindex) { - if (!(blockindex->nStatus & BLOCK_HAVE_DATA)) { + const bool block_has_data = WITH_LOCK(::cs_main, return blockindex->nStatus & BLOCK_HAVE_DATA); + if (!block_has_data) { throw JSONRPCError(RPC_MISC_ERROR, "Block not available"); } errmsg = "No such transaction found in the provided block"; @@ -497,6 +508,7 @@ static RPCHelpMan decoderawtransaction() {RPCResult::Type::OBJ, "scriptPubKey", "", { {RPCResult::Type::STR, "asm", "the asm"}, + {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, {RPCResult::Type::STR_HEX, "hex", "the hex"}, {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, @@ -552,6 +564,7 @@ static RPCHelpMan decodescript() RPCResult::Type::OBJ, "", "", { {RPCResult::Type::STR, "asm", "Script public key"}, + {RPCResult::Type::STR, "desc", "Inferred descriptor for the script"}, {RPCResult::Type::STR, "type", "The output type (e.g. " + GetAllOutputTypes() + ")"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, {RPCResult::Type::STR, "p2sh", /*optional=*/true, @@ -563,6 +576,7 @@ static RPCHelpMan decodescript() {RPCResult::Type::STR_HEX, "hex", "Hex string of the script public key"}, {RPCResult::Type::STR, "type", "The type of the script public key (e.g. witness_v0_keyhash or witness_v0_scripthash)"}, {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, + {RPCResult::Type::STR, "desc", "Inferred descriptor for the script"}, {RPCResult::Type::STR, "p2sh-segwit", "address of the P2SH script wrapping this witness redeem script"}, }}, }, @@ -1066,8 +1080,9 @@ static RPCHelpMan testmempoolaccept() static RPCHelpMan decodepsbt() { - return RPCHelpMan{"decodepsbt", - "\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n", + return RPCHelpMan{ + "decodepsbt", + "Return a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.", { {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The PSBT base64 string"}, }, @@ -1176,7 +1191,7 @@ static RPCHelpMan decodepsbt() { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, }}, - {RPCResult::Type::ARR, "proprietary", "The input proprietary map", + {RPCResult::Type::ARR, "proprietary", /*optional=*/true, "The input proprietary map", { {RPCResult::Type::OBJ, "", "", { @@ -1217,7 +1232,7 @@ static RPCHelpMan decodepsbt() { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, }}, - {RPCResult::Type::ARR, "proprietary", "The output proprietary map", + {RPCResult::Type::ARR, "proprietary", /*optional=*/true, "The output proprietary map", { {RPCResult::Type::OBJ, "", "", { diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index d550160260..e23fe34480 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -63,7 +63,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal if (rbf) { nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */ } else if (rawTx.nLockTime) { - nSequence = CTxIn::SEQUENCE_FINAL - 1; + nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; /* CTxIn::SEQUENCE_FINAL - 1 */ } else { nSequence = CTxIn::SEQUENCE_FINAL; } diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h index d2e116f7ee..c3eb1417f8 100644 --- a/src/rpc/rawtransaction_util.h +++ b/src/rpc/rawtransaction_util.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. diff --git a/src/rpc/register.h b/src/rpc/register.h index 6724203ffe..c5055cc9d7 100644 --- a/src/rpc/register.h +++ b/src/rpc/register.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/rpc/request.cpp b/src/rpc/request.cpp index 3245e04cdf..95a7c25b93 100644 --- a/src/rpc/request.cpp +++ b/src/rpc/request.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -12,6 +12,11 @@ #include <util/system.h> #include <util/strencodings.h> +#include <fstream> +#include <stdexcept> +#include <string> +#include <vector> + /** * JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility, * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were @@ -83,7 +88,7 @@ bool GenerateAuthCookie(std::string *cookie_out) /** the umask determines what permissions are used to create this file - * these are set to 077 in init.cpp unless overridden with -sysperms. */ - fsbridge::ofstream file; + std::ofstream file; fs::path filepath_tmp = GetAuthCookieFile(true); file.open(filepath_tmp); if (!file.is_open()) { @@ -107,7 +112,7 @@ bool GenerateAuthCookie(std::string *cookie_out) bool GetAuthCookie(std::string *cookie_out) { - fsbridge::ifstream file; + std::ifstream file; std::string cookie; fs::path filepath = GetAuthCookieFile(); file.open(filepath); diff --git a/src/rpc/request.h b/src/rpc/request.h index bb091efea8..a682c58d96 100644 --- a/src/rpc/request.h +++ b/src/rpc/request.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 9bcfba3507..c70236cc1c 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/rpc/server.h b/src/rpc/server.h index e6bb35fc33..01e8556050 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/rpc/server_util.cpp b/src/rpc/server_util.cpp index 3fc35222e1..6a1b41f066 100644 --- a/src/rpc/server_util.cpp +++ b/src/rpc/server_util.cpp @@ -15,6 +15,8 @@ #include <any> +using node::NodeContext; + NodeContext& EnsureAnyNodeContext(const std::any& context) { auto node_context = util::AnyPtr<NodeContext>(context); @@ -37,6 +39,19 @@ CTxMemPool& EnsureAnyMemPool(const std::any& context) return EnsureMemPool(EnsureAnyNodeContext(context)); } +ArgsManager& EnsureArgsman(const NodeContext& node) +{ + if (!node.args) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Node args not found"); + } + return *node.args; +} + +ArgsManager& EnsureAnyArgsman(const std::any& context) +{ + return EnsureArgsman(EnsureAnyNodeContext(context)); +} + ChainstateManager& EnsureChainman(const NodeContext& node) { if (!node.chainman) { diff --git a/src/rpc/server_util.h b/src/rpc/server_util.h index ad3c149c90..2cc710a803 100644 --- a/src/rpc/server_util.h +++ b/src/rpc/server_util.h @@ -7,21 +7,26 @@ #include <any> +class ArgsManager; class CBlockPolicyEstimator; class CConnman; -class ChainstateManager; class CTxMemPool; -struct NodeContext; +class ChainstateManager; class PeerManager; +namespace node { +struct NodeContext; +} // namespace node -NodeContext& EnsureAnyNodeContext(const std::any& context); -CTxMemPool& EnsureMemPool(const NodeContext& node); +node::NodeContext& EnsureAnyNodeContext(const std::any& context); +CTxMemPool& EnsureMemPool(const node::NodeContext& node); CTxMemPool& EnsureAnyMemPool(const std::any& context); -ChainstateManager& EnsureChainman(const NodeContext& node); +ArgsManager& EnsureArgsman(const node::NodeContext& node); +ArgsManager& EnsureAnyArgsman(const std::any& context); +ChainstateManager& EnsureChainman(const node::NodeContext& node); ChainstateManager& EnsureAnyChainman(const std::any& context); -CBlockPolicyEstimator& EnsureFeeEstimator(const NodeContext& node); +CBlockPolicyEstimator& EnsureFeeEstimator(const node::NodeContext& node); CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context); -CConnman& EnsureConnman(const NodeContext& node); -PeerManager& EnsurePeerman(const NodeContext& node); +CConnman& EnsureConnman(const node::NodeContext& node); +PeerManager& EnsurePeerman(const node::NodeContext& node); #endif // BITCOIN_RPC_SERVER_UTIL_H diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 57e3da0351..5ef7e26ce8 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -831,11 +831,14 @@ void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const } case Type::OBJ_DYN: case Type::OBJ: { + if (m_inner.empty()) { + sections.PushSection({indent + maybe_key + "{}", Description("empty JSON object")}); + return; + } sections.PushSection({indent + maybe_key + "{", Description("json object")}); for (const auto& i : m_inner) { i.ToSections(sections, OuterType::OBJ, current_indent + 2); } - CHECK_NONFATAL(!m_inner.empty()); if (m_type == Type::OBJ_DYN && m_inner.back().m_type != Type::ELISION) { // If the dictionary keys are dynamic, use three dots for continuation sections.PushSection({indent_next + "...", ""}); @@ -886,6 +889,17 @@ bool RPCResult::MatchesType(const UniValue& result) const CHECK_NONFATAL(false); } +void RPCResult::CheckInnerDoc() const +{ + if (m_type == Type::OBJ) { + // May or may not be empty + return; + } + // Everything else must either be empty or not + const bool inner_needed{m_type == Type::ARR || m_type == Type::ARR_FIXED || m_type == Type::OBJ_DYN}; + CHECK_NONFATAL(inner_needed != m_inner.empty()); +} + std::string RPCArg::ToStringObj(const bool oneline) const { std::string res; diff --git a/src/rpc/util.h b/src/rpc/util.h index d43ee33b0f..25ebf78fa1 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -267,8 +267,7 @@ struct RPCResult { m_cond{std::move(cond)} { CHECK_NONFATAL(!m_cond.empty()); - const bool inner_needed{type == Type::ARR || type == Type::ARR_FIXED || type == Type::OBJ || type == Type::OBJ_DYN}; - CHECK_NONFATAL(inner_needed != inner.empty()); + CheckInnerDoc(); } RPCResult( @@ -292,8 +291,7 @@ struct RPCResult { m_description{std::move(description)}, m_cond{} { - const bool inner_needed{type == Type::ARR || type == Type::ARR_FIXED || type == Type::OBJ || type == Type::OBJ_DYN}; - CHECK_NONFATAL(inner_needed != inner.empty()); + CheckInnerDoc(); } RPCResult( @@ -311,6 +309,9 @@ struct RPCResult { std::string ToDescriptionString() const; /** Check whether the result JSON type matches. */ bool MatchesType(const UniValue& result) const; + +private: + void CheckInnerDoc() const; }; struct RPCResults { diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 162cced6c7..0b2ad3c553 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. @@ -136,7 +136,7 @@ bool CScheduler::AreThreadsServicingQueue() const void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue() { { - LOCK(m_cs_callbacks_pending); + LOCK(m_callbacks_mutex); // Try to avoid scheduling too many copies here, but if we // accidentally have two ProcessQueue's scheduled at once its // not a big deal. @@ -150,7 +150,7 @@ void SingleThreadedSchedulerClient::ProcessQueue() { std::function<void()> callback; { - LOCK(m_cs_callbacks_pending); + LOCK(m_callbacks_mutex); if (m_are_callbacks_running) return; if (m_callbacks_pending.empty()) return; m_are_callbacks_running = true; @@ -167,7 +167,7 @@ void SingleThreadedSchedulerClient::ProcessQueue() ~RAIICallbacksRunning() { { - LOCK(instance->m_cs_callbacks_pending); + LOCK(instance->m_callbacks_mutex); instance->m_are_callbacks_running = false; } instance->MaybeScheduleProcessQueue(); @@ -182,7 +182,7 @@ void SingleThreadedSchedulerClient::AddToProcessQueue(std::function<void()> func assert(m_pscheduler); { - LOCK(m_cs_callbacks_pending); + LOCK(m_callbacks_mutex); m_callbacks_pending.emplace_back(std::move(func)); } MaybeScheduleProcessQueue(); @@ -194,13 +194,13 @@ void SingleThreadedSchedulerClient::EmptyQueue() bool should_continue = true; while (should_continue) { ProcessQueue(); - LOCK(m_cs_callbacks_pending); + LOCK(m_callbacks_mutex); should_continue = !m_callbacks_pending.empty(); } } size_t SingleThreadedSchedulerClient::CallbacksPending() { - LOCK(m_cs_callbacks_pending); + LOCK(m_callbacks_mutex); return m_callbacks_pending.size(); } diff --git a/src/scheduler.h b/src/scheduler.h index be878661db..bb0abfbf7a 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. @@ -119,9 +119,9 @@ class SingleThreadedSchedulerClient private: CScheduler* m_pscheduler; - RecursiveMutex m_cs_callbacks_pending; - std::list<std::function<void()>> m_callbacks_pending GUARDED_BY(m_cs_callbacks_pending); - bool m_are_callbacks_running GUARDED_BY(m_cs_callbacks_pending) = false; + Mutex m_callbacks_mutex; + std::list<std::function<void()>> m_callbacks_pending GUARDED_BY(m_callbacks_mutex); + bool m_are_callbacks_running GUARDED_BY(m_callbacks_mutex) = false; void MaybeScheduleProcessQueue(); void ProcessQueue(); diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index a9aa6a0060..f7f9dfc262 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -22,20 +22,23 @@ public: m_remaining(txToLen) {} - void read(char* pch, size_t nSize) + void read(Span<std::byte> dst) { - if (nSize > m_remaining) + if (dst.size() > m_remaining) { throw std::ios_base::failure(std::string(__func__) + ": end of data"); + } - if (pch == nullptr) + if (dst.data() == nullptr) { throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer"); + } - if (m_data == nullptr) + if (m_data == nullptr) { throw std::ios_base::failure(std::string(__func__) + ": bad source buffer"); + } - memcpy(pch, m_data, nSize); - m_remaining -= nSize; - m_data += nSize; + memcpy(dst.data(), m_data, dst.size()); + m_remaining -= dst.size(); + m_data += dst.size(); } template<typename T> diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h index b6939127e1..8fea42e4b9 100644 --- a/src/script/bitcoinconsensus.h +++ b/src/script/bitcoinconsensus.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 30f929664f..84040bf847 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -1222,7 +1222,7 @@ std::unique_ptr<DescriptorImpl> ParseScript(uint32_t& key_exp_index, Span<const error = "A function is needed within P2WSH"; return nullptr; } - error = strprintf("%s is not a valid descriptor function", std::string(expr.begin(), expr.end())); + error = strprintf("'%s' is not a valid descriptor function", std::string(expr.begin(), expr.end())); return nullptr; } diff --git a/src/script/descriptor.h b/src/script/descriptor.h index ecd7c4eea5..16ee2f6d97 100644 --- a/src/script/descriptor.h +++ b/src/script/descriptor.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 6433ba1b58..11b1a1c887 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -1303,12 +1303,12 @@ public: it = itBegin; while (scriptCode.GetOp(it, opcode)) { if (opcode == OP_CODESEPARATOR) { - s.write((char*)&itBegin[0], it-itBegin-1); + s.write(AsBytes(Span{&itBegin[0], size_t(it - itBegin - 1)})); itBegin = it; } } if (itBegin != scriptCode.end()) - s.write((char*)&itBegin[0], it-itBegin); + s.write(AsBytes(Span{&itBegin[0], size_t(it - itBegin)})); } /** Serialize an input of txTo */ @@ -1500,7 +1500,7 @@ static bool HandleMissingData(MissingDataBehavior mdb) } template<typename T> -bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb) +bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb) { uint8_t ext_flag, key_version; switch (sigversion) { @@ -1568,9 +1568,12 @@ bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata // Data about the output (if only one). if (output_type == SIGHASH_SINGLE) { if (in_pos >= tx_to.vout.size()) return false; - CHashWriter sha_single_output(SER_GETHASH, 0); - sha_single_output << tx_to.vout[in_pos]; - ss << sha_single_output.GetSHA256(); + if (!execdata.m_output_hash) { + CHashWriter sha_single_output(SER_GETHASH, 0); + sha_single_output << tx_to.vout[in_pos]; + execdata.m_output_hash = sha_single_output.GetSHA256(); + } + ss << execdata.m_output_hash.value(); } // Additional data for BIP 342 signatures @@ -1692,7 +1695,7 @@ bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vecto } template <class T> -bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey_in, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror) const +bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey_in, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const { assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT); // Schnorr signatures have 32-byte public keys. The caller is responsible for enforcing this. diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 513eaaf94c..cf1953ad22 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -11,6 +11,7 @@ #include <span.h> #include <primitives/transaction.h> +#include <optional> #include <vector> #include <stdint.h> @@ -215,6 +216,9 @@ struct ScriptExecutionData bool m_validation_weight_left_init = false; //! How much validation weight is left (decremented for every successful non-empty signature check). int64_t m_validation_weight_left; + + //! The hash of the corresponding output + std::optional<uint256> m_output_hash; }; /** Signature hash sizes */ @@ -244,7 +248,7 @@ public: return false; } - virtual bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const + virtual bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const { return false; } @@ -272,7 +276,7 @@ enum class MissingDataBehavior }; template<typename T> -bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb); +bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb); template <class T> class GenericTransactionSignatureChecker : public BaseSignatureChecker @@ -292,7 +296,7 @@ public: GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, MissingDataBehavior mdb) : txTo(txToIn), m_mdb(mdb), nIn(nInIn), amount(amountIn), txdata(nullptr) {} GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn, MissingDataBehavior mdb) : txTo(txToIn), m_mdb(mdb), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; - bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override; + bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override; bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; }; @@ -313,7 +317,7 @@ public: return m_checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion); } - bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override + bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override { return m_checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata, serror); } diff --git a/src/script/script.h b/src/script/script.h index 8cd1cc3855..8b7a7bb7b3 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -51,10 +51,10 @@ static const uint32_t LOCKTIME_MAX = 0xFFFFFFFFU; static constexpr unsigned int ANNEX_TAG = 0x50; // Validation weight per passing signature (Tapscript only, see BIP 342). -static constexpr uint64_t VALIDATION_WEIGHT_PER_SIGOP_PASSED = 50; +static constexpr int64_t VALIDATION_WEIGHT_PER_SIGOP_PASSED{50}; // How much weight budget is added to the witness size (Tapscript only, see BIP 342). -static constexpr uint64_t VALIDATION_WEIGHT_OFFSET = 50; +static constexpr int64_t VALIDATION_WEIGHT_OFFSET{50}; template <typename T> std::vector<unsigned char> ToByteVector(const T& in) diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index 6f911f4fe7..4e2acc463a 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/script/sigcache.h b/src/script/sigcache.h index 7b6b91c963..1e21d6f340 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/script/sign.cpp b/src/script/sign.cpp index d33c847d98..371a937bc8 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -542,7 +542,7 @@ class DummySignatureChecker final : public BaseSignatureChecker public: DummySignatureChecker() {} bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; } - bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror) const override { return true; } + bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const override { return true; } }; const DummySignatureChecker DUMMY_CHECKER; diff --git a/src/script/sign.h b/src/script/sign.h index 7e3d5e80e4..7301826ba5 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp index 17f97fa30c..552934e0eb 100644 --- a/src/script/signingprovider.cpp +++ b/src/script/signingprovider.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h index b8b3e03dd3..f1bded1a8c 100644 --- a/src/script/signingprovider.h +++ b/src/script/signingprovider.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/script/standard.cpp b/src/script/standard.cpp index d9656c781d..5fb98cc307 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/script/standard.h b/src/script/standard.h index a8e57231bf..eb50421768 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/serialize.h b/src/serialize.h index 873361fe9e..44bb471f25 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -47,79 +47,72 @@ static const unsigned int MAX_VECTOR_ALLOCATE = 5000000; struct deserialize_type {}; constexpr deserialize_type deserialize {}; -//! Safely convert odd char pointer types to standard ones. -inline char* CharCast(char* c) { return c; } -inline char* CharCast(unsigned char* c) { return (char*)c; } -inline const char* CharCast(const char* c) { return c; } -inline const char* CharCast(const unsigned char* c) { return (const char*)c; } - /* * Lowest-level serialization and conversion. - * @note Sizes of these types are verified in the tests */ template<typename Stream> inline void ser_writedata8(Stream &s, uint8_t obj) { - s.write((char*)&obj, 1); + s.write(AsBytes(Span{&obj, 1})); } template<typename Stream> inline void ser_writedata16(Stream &s, uint16_t obj) { obj = htole16(obj); - s.write((char*)&obj, 2); + s.write(AsBytes(Span{&obj, 1})); } template<typename Stream> inline void ser_writedata16be(Stream &s, uint16_t obj) { obj = htobe16(obj); - s.write((char*)&obj, 2); + s.write(AsBytes(Span{&obj, 1})); } template<typename Stream> inline void ser_writedata32(Stream &s, uint32_t obj) { obj = htole32(obj); - s.write((char*)&obj, 4); + s.write(AsBytes(Span{&obj, 1})); } template<typename Stream> inline void ser_writedata32be(Stream &s, uint32_t obj) { obj = htobe32(obj); - s.write((char*)&obj, 4); + s.write(AsBytes(Span{&obj, 1})); } template<typename Stream> inline void ser_writedata64(Stream &s, uint64_t obj) { obj = htole64(obj); - s.write((char*)&obj, 8); + s.write(AsBytes(Span{&obj, 1})); } template<typename Stream> inline uint8_t ser_readdata8(Stream &s) { uint8_t obj; - s.read((char*)&obj, 1); + s.read(AsWritableBytes(Span{&obj, 1})); return obj; } template<typename Stream> inline uint16_t ser_readdata16(Stream &s) { uint16_t obj; - s.read((char*)&obj, 2); + s.read(AsWritableBytes(Span{&obj, 1})); return le16toh(obj); } template<typename Stream> inline uint16_t ser_readdata16be(Stream &s) { uint16_t obj; - s.read((char*)&obj, 2); + s.read(AsWritableBytes(Span{&obj, 1})); return be16toh(obj); } template<typename Stream> inline uint32_t ser_readdata32(Stream &s) { uint32_t obj; - s.read((char*)&obj, 4); + s.read(AsWritableBytes(Span{&obj, 1})); return le32toh(obj); } template<typename Stream> inline uint32_t ser_readdata32be(Stream &s) { uint32_t obj; - s.read((char*)&obj, 4); + s.read(AsWritableBytes(Span{&obj, 1})); return be32toh(obj); } template<typename Stream> inline uint64_t ser_readdata64(Stream &s) { uint64_t obj; - s.read((char*)&obj, 8); + s.read(AsWritableBytes(Span{&obj, 1})); return le64toh(obj); } @@ -127,7 +120,7 @@ template<typename Stream> inline uint64_t ser_readdata64(Stream &s) ///////////////////////////////////////////////////////////////// // // Templates for serializing to anything that looks like a stream, -// i.e. anything that supports .read(char*, size_t) and .write(char*, size_t) +// i.e. anything that supports .read(Span<std::byte>) and .write(Span<const std::byte>) // class CSizeComputer; @@ -196,7 +189,7 @@ template<typename X> const X& ReadWriteAsHelper(const X& x) { return x; } FORMATTER_METHODS(cls, obj) #ifndef CHAR_EQUALS_INT8 -template<typename Stream> inline void Serialize(Stream& s, char a ) { ser_writedata8(s, a); } // TODO Get rid of bare char +template <typename Stream> void Serialize(Stream&, char) = delete; // char serialization forbidden. Use uint8_t or int8_t #endif template<typename Stream> inline void Serialize(Stream& s, int8_t a ) { ser_writedata8(s, a); } template<typename Stream> inline void Serialize(Stream& s, uint8_t a ) { ser_writedata8(s, a); } @@ -206,13 +199,13 @@ template<typename Stream> inline void Serialize(Stream& s, int32_t a ) { ser_wri template<typename Stream> inline void Serialize(Stream& s, uint32_t a) { ser_writedata32(s, a); } template<typename Stream> inline void Serialize(Stream& s, int64_t a ) { ser_writedata64(s, a); } template<typename Stream> inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); } -template<typename Stream, int N> inline void Serialize(Stream& s, const char (&a)[N]) { s.write(a, N); } -template<typename Stream, int N> inline void Serialize(Stream& s, const unsigned char (&a)[N]) { s.write(CharCast(a), N); } -template<typename Stream> inline void Serialize(Stream& s, const Span<const unsigned char>& span) { s.write(CharCast(span.data()), span.size()); } -template<typename Stream> inline void Serialize(Stream& s, const Span<unsigned char>& span) { s.write(CharCast(span.data()), span.size()); } +template<typename Stream, int N> inline void Serialize(Stream& s, const char (&a)[N]) { s.write(MakeByteSpan(a)); } +template<typename Stream, int N> inline void Serialize(Stream& s, const unsigned char (&a)[N]) { s.write(MakeByteSpan(a)); } +template<typename Stream> inline void Serialize(Stream& s, const Span<const unsigned char>& span) { s.write(AsBytes(span)); } +template<typename Stream> inline void Serialize(Stream& s, const Span<unsigned char>& span) { s.write(AsBytes(span)); } #ifndef CHAR_EQUALS_INT8 -template<typename Stream> inline void Unserialize(Stream& s, char& a ) { a = ser_readdata8(s); } // TODO Get rid of bare char +template <typename Stream> void Unserialize(Stream&, char) = delete; // char serialization forbidden. Use uint8_t or int8_t #endif template<typename Stream> inline void Unserialize(Stream& s, int8_t& a ) { a = ser_readdata8(s); } template<typename Stream> inline void Unserialize(Stream& s, uint8_t& a ) { a = ser_readdata8(s); } @@ -222,9 +215,9 @@ template<typename Stream> inline void Unserialize(Stream& s, int32_t& a ) { a = template<typename Stream> inline void Unserialize(Stream& s, uint32_t& a) { a = ser_readdata32(s); } template<typename Stream> inline void Unserialize(Stream& s, int64_t& a ) { a = ser_readdata64(s); } template<typename Stream> inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); } -template<typename Stream, int N> inline void Unserialize(Stream& s, char (&a)[N]) { s.read(a, N); } -template<typename Stream, int N> inline void Unserialize(Stream& s, unsigned char (&a)[N]) { s.read(CharCast(a), N); } -template<typename Stream> inline void Unserialize(Stream& s, Span<unsigned char>& span) { s.read(CharCast(span.data()), span.size()); } +template<typename Stream, int N> inline void Unserialize(Stream& s, char (&a)[N]) { s.read(MakeWritableByteSpan(a)); } +template<typename Stream, int N> inline void Unserialize(Stream& s, unsigned char (&a)[N]) { s.read(MakeWritableByteSpan(a)); } +template<typename Stream> inline void Unserialize(Stream& s, Span<unsigned char>& span) { s.read(AsWritableBytes(span)); } template <typename Stream> inline void Serialize(Stream& s, bool a) { uint8_t f = a; ser_writedata8(s, f); } template <typename Stream> inline void Unserialize(Stream& s, bool& a) { uint8_t f = ser_readdata8(s); a = f; } @@ -479,10 +472,10 @@ struct CustomUintFormatter if (v < 0 || v > MAX) throw std::ios_base::failure("CustomUintFormatter value out of range"); if (BigEndian) { uint64_t raw = htobe64(v); - s.write(((const char*)&raw) + 8 - Bytes, Bytes); + s.write({BytePtr(&raw) + 8 - Bytes, Bytes}); } else { uint64_t raw = htole64(v); - s.write((const char*)&raw, Bytes); + s.write({BytePtr(&raw), Bytes}); } } @@ -492,10 +485,10 @@ struct CustomUintFormatter static_assert(std::numeric_limits<U>::max() >= MAX && std::numeric_limits<U>::min() <= 0, "Assigned type too small"); uint64_t raw = 0; if (BigEndian) { - s.read(((char*)&raw) + 8 - Bytes, Bytes); + s.read({BytePtr(&raw) + 8 - Bytes, Bytes}); v = static_cast<I>(be64toh(raw)); } else { - s.read((char*)&raw, Bytes); + s.read({BytePtr(&raw), Bytes}); v = static_cast<I>(le64toh(raw)); } } @@ -551,7 +544,7 @@ struct LimitedStringFormatter throw std::ios_base::failure("String length limit exceeded"); } v.resize(size); - if (size != 0) s.read((char*)v.data(), size); + if (size != 0) s.read(MakeWritableByteSpan(v)); } template<typename Stream> @@ -715,7 +708,7 @@ void Serialize(Stream& os, const std::basic_string<C>& str) { WriteCompactSize(os, str.size()); if (!str.empty()) - os.write((char*)str.data(), str.size() * sizeof(C)); + os.write(MakeByteSpan(str)); } template<typename Stream, typename C> @@ -724,7 +717,7 @@ void Unserialize(Stream& is, std::basic_string<C>& str) unsigned int nSize = ReadCompactSize(is); str.resize(nSize); if (nSize != 0) - is.read((char*)str.data(), nSize * sizeof(C)); + is.read(MakeWritableByteSpan(str)); } @@ -737,7 +730,7 @@ void Serialize_impl(Stream& os, const prevector<N, T>& v, const unsigned char&) { WriteCompactSize(os, v.size()); if (!v.empty()) - os.write((char*)v.data(), v.size() * sizeof(T)); + os.write(MakeByteSpan(v)); } template<typename Stream, unsigned int N, typename T, typename V> @@ -764,7 +757,7 @@ void Unserialize_impl(Stream& is, prevector<N, T>& v, const unsigned char&) { unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); v.resize_uninitialized(i + blk); - is.read((char*)&v[i], blk * sizeof(T)); + is.read(AsWritableBytes(Span{&v[i], blk})); i += blk; } } @@ -791,7 +784,7 @@ void Serialize_impl(Stream& os, const std::vector<T, A>& v, const unsigned char& { WriteCompactSize(os, v.size()); if (!v.empty()) - os.write((char*)v.data(), v.size() * sizeof(T)); + os.write(MakeByteSpan(v)); } template<typename Stream, typename T, typename A> @@ -830,7 +823,7 @@ void Unserialize_impl(Stream& is, std::vector<T, A>& v, const unsigned char&) { unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); v.resize(i + blk); - is.read((char*)&v[i], blk * sizeof(T)); + is.read(AsWritableBytes(Span{&v[i], blk})); i += blk; } } @@ -995,9 +988,9 @@ protected: public: explicit CSizeComputer(int nVersionIn) : nSize(0), nVersion(nVersionIn) {} - void write(const char *psz, size_t _nSize) + void write(Span<const std::byte> src) { - this->nSize += _nSize; + this->nSize += src.size(); } /** Pretend _nSize bytes are written, without specifying them. */ diff --git a/src/shutdown.cpp b/src/shutdown.cpp index 35faf3c412..93f04e9021 100644 --- a/src/shutdown.cpp +++ b/src/shutdown.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/shutdown.h b/src/shutdown.h index 9df601d478..07a8315788 100644 --- a/src/shutdown.h +++ b/src/shutdown.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/signet.cpp b/src/signet.cpp index 6366851790..747bd1b0a8 100644 --- a/src/signet.cpp +++ b/src/signet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/signet.h b/src/signet.h index f876488c0a..6912fc7f4b 100644 --- a/src/signet.h +++ b/src/signet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/span.h b/src/span.h index 6703e889c5..b627b993c2 100644 --- a/src/span.h +++ b/src/span.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -243,16 +243,21 @@ T& SpanPopBack(Span<T>& span) return back; } +//! Convert a data pointer to a std::byte data pointer. +//! Where possible, please use the safer AsBytes helpers. +inline const std::byte* BytePtr(const void* data) { return reinterpret_cast<const std::byte*>(data); } +inline std::byte* BytePtr(void* data) { return reinterpret_cast<std::byte*>(data); } + // From C++20 as_bytes and as_writeable_bytes template <typename T> Span<const std::byte> AsBytes(Span<T> s) noexcept { - return {reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()}; + return {BytePtr(s.data()), s.size_bytes()}; } template <typename T> Span<std::byte> AsWritableBytes(Span<T> s) noexcept { - return {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()}; + return {BytePtr(s.data()), s.size_bytes()}; } template <typename V> diff --git a/src/streams.h b/src/streams.h index 98b99b1a62..cf8b4eb96f 100644 --- a/src/streams.h +++ b/src/streams.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -49,14 +49,14 @@ public: return (*this); } - void write(const char* pch, size_t nSize) + void write(Span<const std::byte> src) { - stream->write(pch, nSize); + stream->write(src); } - void read(char* pch, size_t nSize) + void read(Span<std::byte> dst) { - stream->read(pch, nSize); + stream->read(dst); } int GetVersion() const { return nVersion; } @@ -94,17 +94,17 @@ class CVectorWriter { ::SerializeMany(*this, std::forward<Args>(args)...); } - void write(const char* pch, size_t nSize) + void write(Span<const std::byte> src) { assert(nPos <= vchData.size()); - size_t nOverwrite = std::min(nSize, vchData.size() - nPos); + size_t nOverwrite = std::min(src.size(), vchData.size() - nPos); if (nOverwrite) { - memcpy(vchData.data() + nPos, reinterpret_cast<const unsigned char*>(pch), nOverwrite); + memcpy(vchData.data() + nPos, src.data(), nOverwrite); } - if (nOverwrite < nSize) { - vchData.insert(vchData.end(), reinterpret_cast<const unsigned char*>(pch) + nOverwrite, reinterpret_cast<const unsigned char*>(pch) + nSize); + if (nOverwrite < src.size()) { + vchData.insert(vchData.end(), UCharCast(src.data()) + nOverwrite, UCharCast(src.end())); } - nPos += nSize; + nPos += src.size(); } template<typename T> CVectorWriter& operator<<(const T& obj) @@ -161,18 +161,18 @@ public: size_t size() const { return m_data.size(); } bool empty() const { return m_data.empty(); } - void read(char* dst, size_t n) + void read(Span<std::byte> dst) { - if (n == 0) { + if (dst.size() == 0) { return; } // Read from the beginning of the buffer - if (n > m_data.size()) { + if (dst.size() > m_data.size()) { throw std::ios_base::failure("SpanReader::read(): end of data"); } - memcpy(dst, m_data.data(), n); - m_data = m_data.subspan(n); + memcpy(dst.data(), m_data.data(), dst.size()); + m_data = m_data.subspan(dst.size()); } }; @@ -206,6 +206,7 @@ public: : nType{nTypeIn}, nVersion{nVersionIn} {} + explicit CDataStream(Span<const uint8_t> sp, int type, int version) : CDataStream{AsBytes(sp), type, version} {} explicit CDataStream(Span<const value_type> sp, int nTypeIn, int nVersionIn) : vch(sp.data(), sp.data() + sp.size()), nType{nTypeIn}, @@ -221,7 +222,7 @@ public: std::string str() const { - return (std::string(begin(), end())); + return std::string{UCharCast(data()), UCharCast(data() + size())}; } @@ -239,76 +240,9 @@ public: const_reference operator[](size_type pos) const { return vch[pos + nReadPos]; } reference operator[](size_type pos) { return vch[pos + nReadPos]; } void clear() { vch.clear(); nReadPos = 0; } - iterator insert(iterator it, const value_type x) { return vch.insert(it, x); } - void insert(iterator it, size_type n, const value_type x) { vch.insert(it, n, x); } value_type* data() { return vch.data() + nReadPos; } const value_type* data() const { return vch.data() + nReadPos; } - void insert(iterator it, std::vector<value_type>::const_iterator first, std::vector<value_type>::const_iterator last) - { - if (last == first) return; - assert(last - first > 0); - if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) - { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } - - void insert(iterator it, const value_type* first, const value_type* last) - { - if (last == first) return; - assert(last - first > 0); - if (it == vch.begin() + nReadPos && (unsigned int)(last - first) <= nReadPos) - { - // special case for inserting at the front when there's room - nReadPos -= (last - first); - memcpy(&vch[nReadPos], &first[0], last - first); - } - else - vch.insert(it, first, last); - } - - iterator erase(iterator it) - { - if (it == vch.begin() + nReadPos) - { - // special case for erasing from the front - if (++nReadPos >= vch.size()) - { - // whenever we reach the end, we take the opportunity to clear the buffer - nReadPos = 0; - return vch.erase(vch.begin(), vch.end()); - } - return vch.begin() + nReadPos; - } - else - return vch.erase(it); - } - - iterator erase(iterator first, iterator last) - { - if (first == vch.begin() + nReadPos) - { - // special case for erasing from the front - if (last == vch.end()) - { - nReadPos = 0; - return vch.erase(vch.begin(), vch.end()); - } - else - { - nReadPos = (last - vch.begin()); - return last; - } - } - else - return vch.erase(first, last); - } - inline void Compact() { vch.erase(vch.begin(), vch.begin() + nReadPos); @@ -342,16 +276,16 @@ public: void SetVersion(int n) { nVersion = n; } int GetVersion() const { return nVersion; } - void read(char* pch, size_t nSize) + void read(Span<value_type> dst) { - if (nSize == 0) return; + if (dst.size() == 0) return; // Read from the beginning of the buffer - unsigned int nReadPosNext = nReadPos + nSize; + unsigned int nReadPosNext = nReadPos + dst.size(); if (nReadPosNext > vch.size()) { throw std::ios_base::failure("CDataStream::read(): end of data"); } - memcpy(pch, &vch[nReadPos], nSize); + memcpy(dst.data(), &vch[nReadPos], dst.size()); if (nReadPosNext == vch.size()) { nReadPos = 0; @@ -379,10 +313,10 @@ public: nReadPos = nReadPosNext; } - void write(const char* pch, size_t nSize) + void write(Span<const value_type> src) { // Write to the end of the buffer - vch.insert(vch.end(), pch, pch + nSize); + vch.insert(vch.end(), src.begin(), src.end()); } template<typename Stream> @@ -390,7 +324,7 @@ public: { // Special case: stream << stream concatenates like stream += stream if (!vch.empty()) - s.write((char*)vch.data(), vch.size() * sizeof(value_type)); + s.write(MakeByteSpan(vch)); } template<typename T> @@ -421,7 +355,7 @@ public: } for (size_type i = 0, j = 0; i != size(); i++) { - vch[i] ^= key[j++]; + vch[i] ^= std::byte{key[j++]}; // This potentially acts on very many bytes of data, so it's // important that we calculate `j`, i.e. the `key` index in this @@ -594,12 +528,13 @@ public: int GetType() const { return nType; } int GetVersion() const { return nVersion; } - void read(char* pch, size_t nSize) + void read(Span<std::byte> dst) { if (!file) throw std::ios_base::failure("CAutoFile::read: file handle is nullptr"); - if (fread(pch, 1, nSize, file) != nSize) + 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"); + } } void ignore(size_t nSize) @@ -615,12 +550,13 @@ public: } } - void write(const char* pch, size_t nSize) + void write(Span<const std::byte> src) { if (!file) throw std::ios_base::failure("CAutoFile::write: file handle is nullptr"); - if (fwrite(pch, 1, nSize, file) != nSize) + if (fwrite(src.data(), 1, src.size(), file) != src.size()) { throw std::ios_base::failure("CAutoFile::write: write failed"); + } } template<typename T> @@ -661,7 +597,7 @@ private: uint64_t nReadPos; //!< how many bytes have been read from this uint64_t nReadLimit; //!< up to which position we're allowed to read uint64_t nRewind; //!< how many bytes we guarantee to rewind - std::vector<char> vchBuf; //!< the buffer + std::vector<std::byte> vchBuf; //!< the buffer protected: //! read data from the source to fill the buffer @@ -682,8 +618,8 @@ protected: } public: - CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) : - nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, 0) + CBufferedFile(FILE* fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) + : nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit(std::numeric_limits<uint64_t>::max()), nRewind(nRewindIn), vchBuf(nBufSize, std::byte{0}) { if (nRewindIn >= nBufSize) throw std::ios_base::failure("Rewind limit must be less than buffer size"); @@ -716,22 +652,23 @@ public: } //! read a number of bytes - void read(char *pch, size_t nSize) { - if (nSize + nReadPos > nReadLimit) + void read(Span<std::byte> dst) + { + if (dst.size() + nReadPos > nReadLimit) { throw std::ios_base::failure("Read attempted past buffer limit"); - while (nSize > 0) { + } + while (dst.size() > 0) { if (nReadPos == nSrcPos) Fill(); unsigned int pos = nReadPos % vchBuf.size(); - size_t nNow = nSize; + size_t nNow = dst.size(); if (nNow + pos > vchBuf.size()) nNow = vchBuf.size() - pos; if (nNow + nReadPos > nSrcPos) nNow = nSrcPos - nReadPos; - memcpy(pch, &vchBuf[pos], nNow); + memcpy(dst.data(), &vchBuf[pos], nNow); nReadPos += nNow; - pch += nNow; - nSize -= nNow; + dst = dst.subspan(nNow); } } @@ -774,12 +711,14 @@ public: } //! search for a given byte in the stream, and remain positioned on it - void FindByte(char ch) { + void FindByte(uint8_t ch) + { while (true) { if (nReadPos == nSrcPos) Fill(); - if (vchBuf[nReadPos % vchBuf.size()] == ch) + if (vchBuf[nReadPos % vchBuf.size()] == std::byte{ch}) { break; + } nReadPos++; } } diff --git a/src/support/allocators/secure.h b/src/support/allocators/secure.h index c4923dc56f..a9aa928082 100644 --- a/src/support/allocators/secure.h +++ b/src/support/allocators/secure.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/support/allocators/zeroafterfree.h b/src/support/allocators/zeroafterfree.h index 77de4b1e69..0befe0ffcd 100644 --- a/src/support/allocators/zeroafterfree.h +++ b/src/support/allocators/zeroafterfree.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -41,6 +41,6 @@ struct zero_after_free_allocator : public std::allocator<T> { }; /** Byte-vector that clears its contents before deletion. */ -using SerializeData = std::vector<uint8_t, zero_after_free_allocator<uint8_t>>; +using SerializeData = std::vector<std::byte, zero_after_free_allocator<std::byte>>; #endif // BITCOIN_SUPPORT_ALLOCATORS_ZEROAFTERFREE_H diff --git a/src/sync.cpp b/src/sync.cpp index c9fd8e347e..4621805653 100644 --- a/src/sync.cpp +++ b/src/sync.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/sync.h b/src/sync.h index 6ba63d5e4d..85000a9151 100644 --- a/src/sync.h +++ b/src/sync.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/test/README.md b/src/test/README.md index d03411c3ed..90d0e7102d 100644 --- a/src/test/README.md +++ b/src/test/README.md @@ -33,19 +33,31 @@ the `src/qt/test/test_main.cpp` file. ### Running individual tests -`test_bitcoin` has some built-in command-line arguments; for -example, to run just the `getarg_tests` verbosely: +`test_bitcoin` accepts the command line arguments from the boost framework. +For example, to run just the `getarg_tests` suite of tests: - test_bitcoin --log_level=all --run_test=getarg_tests -- DEBUG_LOG_OUT +```bash +test_bitcoin --log_level=all --run_test=getarg_tests +``` `log_level` controls the verbosity of the test framework, which logs when a -test case is entered, for example. The `DEBUG_LOG_OUT` after the two dashes -redirects the debug log, which would normally go to a file in the test datadir +test case is entered, for example. `test_bitcoin` also accepts the command +line arguments accepted by `bitcoind`. Use `--` to separate both types of +arguments: + +```bash +test_bitcoin --log_level=all --run_test=getarg_tests -- -printtoconsole=1 +``` + +The `-printtoconsole=1` after the two dashes redirects the debug log, which +would normally go to a file in the test datadir (`BasicTestingSetup::m_path_root`), to the standard terminal output. ... or to run just the doubledash test: - test_bitcoin --run_test=getarg_tests/doubledash +```bash +test_bitcoin --run_test=getarg_tests/doubledash +``` Run `test_bitcoin --help` for the full list. @@ -68,7 +80,7 @@ on failure. For running individual tests verbosely, refer to the section To write to logs from unit tests you need to use specific message methods provided by Boost. The simplest is `BOOST_TEST_MESSAGE`. -For debugging you can launch the `test_bitcoin` executable with `gdb`or `lldb` and +For debugging you can launch the `test_bitcoin` executable with `gdb` or `lldb` and start debugging, just like you would with any other program: ```bash @@ -95,7 +107,7 @@ Running the tests and hitting a segmentation fault should now produce a file cal `/proc/sys/kernel/core_pattern`). You can then explore the core dump using -``` bash +```bash gdb src/test/test_bitcoin core (gbd) bt # produce a backtrace for where a segfault occurred diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index b700c3ae22..efc30b6822 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -21,59 +21,15 @@ #include <string> using namespace std::literals; +using node::NodeContext; -class AddrManTest : public AddrMan -{ -public: - explicit AddrManTest(std::vector<bool> asmap = std::vector<bool>()) - : AddrMan(asmap, /*deterministic=*/true, /*consistency_check_ratio=*/100) - {} - - AddrInfo* Find(const CService& addr) - { - LOCK(m_impl->cs); - return m_impl->Find(addr); - } - - AddrInfo* Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId) - { - LOCK(m_impl->cs); - return m_impl->Create(addr, addrSource, pnId); - } - - void Delete(int nId) - { - LOCK(m_impl->cs); - m_impl->Delete(nId); - } +static const std::vector<bool> EMPTY_ASMAP; +static const bool DETERMINISTIC{true}; - // Used to test deserialization - std::pair<int, int> GetBucketAndEntry(const CAddress& addr) - { - LOCK(m_impl->cs); - int nId = m_impl->mapAddr[addr]; - for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; ++bucket) { - for (int entry = 0; entry < ADDRMAN_BUCKET_SIZE; ++entry) { - if (nId == m_impl->vvNew[bucket][entry]) { - return std::pair<int, int>(bucket, entry); - } - } - } - return std::pair<int, int>(-1, -1); - } - - // Simulates connection failure so that we can test eviction of offline nodes - void SimConnFail(const CService& addr) - { - int64_t nLastSuccess = 1; - // Set last good connection in the deep past. - Good(addr, nLastSuccess); - - bool count_failure = false; - int64_t nLastTry = GetAdjustedTime() - 61; - Attempt(addr, count_failure, nLastTry); - } -}; +static int32_t GetCheckRatio(const NodeContext& node_ctx) +{ + return std::clamp<int32_t>(node_ctx.args->GetIntArg("-checkaddrman", 100), 0, 1000000); +} static CNetAddr ResolveIP(const std::string& ip) { @@ -102,12 +58,11 @@ static std::vector<bool> FromBytes(const unsigned char* source, int vector_size) return result; } - BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(addrman_simple) { - auto addrman = std::make_unique<AddrManTest>(); + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); CNetAddr source = ResolveIP("252.2.2.2"); @@ -141,7 +96,7 @@ BOOST_AUTO_TEST_CASE(addrman_simple) BOOST_CHECK(addrman->size() >= 1); // Test: reset addrman and test AddrMan::Add multiple addresses works as expected - addrman = std::make_unique<AddrManTest>(); + addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); std::vector<CAddress> vAddr; vAddr.push_back(CAddress(ResolveService("250.1.1.3", 8333), NODE_NONE)); vAddr.push_back(CAddress(ResolveService("250.1.1.4", 8333), NODE_NONE)); @@ -151,58 +106,58 @@ BOOST_AUTO_TEST_CASE(addrman_simple) BOOST_AUTO_TEST_CASE(addrman_ports) { - AddrManTest addrman; + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); CNetAddr source = ResolveIP("252.2.2.2"); - BOOST_CHECK_EQUAL(addrman.size(), 0U); + BOOST_CHECK_EQUAL(addrman->size(), 0U); // Test 7; Addr with same IP but diff port does not replace existing addr. CService addr1 = ResolveService("250.1.1.1", 8333); - BOOST_CHECK(addrman.Add({CAddress(addr1, NODE_NONE)}, source)); - BOOST_CHECK_EQUAL(addrman.size(), 1U); + BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source)); + BOOST_CHECK_EQUAL(addrman->size(), 1U); CService addr1_port = ResolveService("250.1.1.1", 8334); - BOOST_CHECK(addrman.Add({CAddress(addr1_port, NODE_NONE)}, source)); - BOOST_CHECK_EQUAL(addrman.size(), 2U); - auto addr_ret2 = addrman.Select().first; + BOOST_CHECK(addrman->Add({CAddress(addr1_port, NODE_NONE)}, source)); + BOOST_CHECK_EQUAL(addrman->size(), 2U); + auto addr_ret2 = addrman->Select().first; BOOST_CHECK(addr_ret2.ToString() == "250.1.1.1:8333" || addr_ret2.ToString() == "250.1.1.1:8334"); // Test: Add same IP but diff port to tried table; this converts the entry with // the specified port to tried, but not the other. - addrman.Good(CAddress(addr1_port, NODE_NONE)); - BOOST_CHECK_EQUAL(addrman.size(), 2U); + addrman->Good(CAddress(addr1_port, NODE_NONE)); + BOOST_CHECK_EQUAL(addrman->size(), 2U); bool newOnly = true; - auto addr_ret3 = addrman.Select(newOnly).first; + auto addr_ret3 = addrman->Select(newOnly).first; BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333"); } BOOST_AUTO_TEST_CASE(addrman_select) { - AddrManTest addrman; + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); CNetAddr source = ResolveIP("252.2.2.2"); // Test: Select from new with 1 addr in new. CService addr1 = ResolveService("250.1.1.1", 8333); - BOOST_CHECK(addrman.Add({CAddress(addr1, NODE_NONE)}, source)); - BOOST_CHECK_EQUAL(addrman.size(), 1U); + BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source)); + BOOST_CHECK_EQUAL(addrman->size(), 1U); bool newOnly = true; - auto addr_ret1 = addrman.Select(newOnly).first; + auto addr_ret1 = addrman->Select(newOnly).first; BOOST_CHECK_EQUAL(addr_ret1.ToString(), "250.1.1.1:8333"); // Test: move addr to tried, select from new expected nothing returned. - addrman.Good(CAddress(addr1, NODE_NONE)); - BOOST_CHECK_EQUAL(addrman.size(), 1U); - auto addr_ret2 = addrman.Select(newOnly).first; + BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE))); + BOOST_CHECK_EQUAL(addrman->size(), 1U); + auto addr_ret2 = addrman->Select(newOnly).first; BOOST_CHECK_EQUAL(addr_ret2.ToString(), "[::]:0"); - auto addr_ret3 = addrman.Select().first; + auto addr_ret3 = addrman->Select().first; BOOST_CHECK_EQUAL(addr_ret3.ToString(), "250.1.1.1:8333"); - BOOST_CHECK_EQUAL(addrman.size(), 1U); + BOOST_CHECK_EQUAL(addrman->size(), 1U); // Add three addresses to new table. @@ -210,65 +165,97 @@ BOOST_AUTO_TEST_CASE(addrman_select) CService addr3 = ResolveService("250.3.2.2", 9999); CService addr4 = ResolveService("250.3.3.3", 9999); - BOOST_CHECK(addrman.Add({CAddress(addr2, NODE_NONE)}, ResolveService("250.3.1.1", 8333))); - BOOST_CHECK(addrman.Add({CAddress(addr3, NODE_NONE)}, ResolveService("250.3.1.1", 8333))); - BOOST_CHECK(addrman.Add({CAddress(addr4, NODE_NONE)}, ResolveService("250.4.1.1", 8333))); + BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, ResolveService("250.3.1.1", 8333))); + BOOST_CHECK(addrman->Add({CAddress(addr3, NODE_NONE)}, ResolveService("250.3.1.1", 8333))); + BOOST_CHECK(addrman->Add({CAddress(addr4, NODE_NONE)}, ResolveService("250.4.1.1", 8333))); // Add three addresses to tried table. CService addr5 = ResolveService("250.4.4.4", 8333); CService addr6 = ResolveService("250.4.5.5", 7777); CService addr7 = ResolveService("250.4.6.6", 8333); - BOOST_CHECK(addrman.Add({CAddress(addr5, NODE_NONE)}, ResolveService("250.3.1.1", 8333))); - addrman.Good(CAddress(addr5, NODE_NONE)); - BOOST_CHECK(addrman.Add({CAddress(addr6, NODE_NONE)}, ResolveService("250.3.1.1", 8333))); - addrman.Good(CAddress(addr6, NODE_NONE)); - BOOST_CHECK(addrman.Add({CAddress(addr7, NODE_NONE)}, ResolveService("250.1.1.3", 8333))); - addrman.Good(CAddress(addr7, NODE_NONE)); + BOOST_CHECK(addrman->Add({CAddress(addr5, NODE_NONE)}, ResolveService("250.3.1.1", 8333))); + BOOST_CHECK(addrman->Good(CAddress(addr5, NODE_NONE))); + BOOST_CHECK(addrman->Add({CAddress(addr6, NODE_NONE)}, ResolveService("250.3.1.1", 8333))); + BOOST_CHECK(addrman->Good(CAddress(addr6, NODE_NONE))); + BOOST_CHECK(addrman->Add({CAddress(addr7, NODE_NONE)}, ResolveService("250.1.1.3", 8333))); + BOOST_CHECK(addrman->Good(CAddress(addr7, NODE_NONE))); // Test: 6 addrs + 1 addr from last test = 7. - BOOST_CHECK_EQUAL(addrman.size(), 7U); + BOOST_CHECK_EQUAL(addrman->size(), 7U); // Test: Select pulls from new and tried regardless of port number. std::set<uint16_t> ports; for (int i = 0; i < 20; ++i) { - ports.insert(addrman.Select().first.GetPort()); + ports.insert(addrman->Select().first.GetPort()); } BOOST_CHECK_EQUAL(ports.size(), 3U); } BOOST_AUTO_TEST_CASE(addrman_new_collisions) { - AddrManTest addrman; + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); CNetAddr source = ResolveIP("252.2.2.2"); uint32_t num_addrs{0}; - BOOST_CHECK_EQUAL(addrman.size(), num_addrs); + BOOST_CHECK_EQUAL(addrman->size(), num_addrs); while (num_addrs < 22) { // Magic number! 250.1.1.1 - 250.1.1.22 do not collide with deterministic key = 1 CService addr = ResolveService("250.1.1." + ToString(++num_addrs)); - BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source)); + BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source)); // Test: No collision in new table yet. - BOOST_CHECK_EQUAL(addrman.size(), num_addrs); + BOOST_CHECK_EQUAL(addrman->size(), num_addrs); } // Test: new table collision! CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs)); uint32_t collisions{1}; - BOOST_CHECK(addrman.Add({CAddress(addr1, NODE_NONE)}, source)); - BOOST_CHECK_EQUAL(addrman.size(), num_addrs - collisions); + BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source)); + BOOST_CHECK_EQUAL(addrman->size(), num_addrs - collisions); CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs)); - BOOST_CHECK(addrman.Add({CAddress(addr2, NODE_NONE)}, source)); - BOOST_CHECK_EQUAL(addrman.size(), num_addrs - collisions); + BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source)); + BOOST_CHECK_EQUAL(addrman->size(), num_addrs - collisions); +} + +BOOST_AUTO_TEST_CASE(addrman_new_multiplicity) +{ + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); + CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)}; + int64_t start_time{GetAdjustedTime()}; + addr.nTime = start_time; + + // test that multiplicity stays at 1 if nTime doesn't increase + for (unsigned int i = 1; i < 20; ++i) { + std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"}; + CNetAddr source{ResolveIP(addr_ip)}; + addrman->Add({addr}, source); + } + AddressPosition addr_pos = addrman->FindAddressEntry(addr).value(); + BOOST_CHECK_EQUAL(addr_pos.multiplicity, 1U); + BOOST_CHECK_EQUAL(addrman->size(), 1U); + + // if nTime increases, an addr can occur in up to 8 buckets + // The acceptance probability decreases exponentially with existing multiplicity - + // choose number of iterations such that it gets to 8 with deterministic addrman. + 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; + addrman->Add({addr}, source); + } + AddressPosition addr_pos_multi = addrman->FindAddressEntry(addr).value(); + BOOST_CHECK_EQUAL(addr_pos_multi.multiplicity, 8U); + // multiplicity doesn't affect size + BOOST_CHECK_EQUAL(addrman->size(), 1U); } BOOST_AUTO_TEST_CASE(addrman_tried_collisions) { - auto addrman = std::make_unique<AddrMan>(std::vector<bool>(), /*deterministic=*/true, /*consistency_check_ratio=*/100); + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); CNetAddr source = ResolveIP("252.2.2.2"); @@ -296,87 +283,15 @@ BOOST_AUTO_TEST_CASE(addrman_tried_collisions) BOOST_CHECK(addrman->Good(CAddress(addr2, NODE_NONE))); } -BOOST_AUTO_TEST_CASE(addrman_find) -{ - AddrManTest addrman; - - BOOST_CHECK_EQUAL(addrman.size(), 0U); - - CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); - CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE); - CAddress addr3 = CAddress(ResolveService("251.255.2.1", 8333), NODE_NONE); - - CNetAddr source1 = ResolveIP("250.1.2.1"); - CNetAddr source2 = ResolveIP("250.1.2.2"); - - BOOST_CHECK(addrman.Add({addr1}, source1)); - BOOST_CHECK(addrman.Add({addr2}, source2)); - BOOST_CHECK(addrman.Add({addr3}, source1)); - - // Test: ensure Find returns an IP/port matching what we searched on. - AddrInfo* info1 = addrman.Find(addr1); - BOOST_REQUIRE(info1); - BOOST_CHECK_EQUAL(info1->ToString(), "250.1.2.1:8333"); - - // Test; Find discriminates by port number. - AddrInfo* info2 = addrman.Find(addr2); - BOOST_REQUIRE(info2); - BOOST_CHECK_EQUAL(info2->ToString(), "250.1.2.1:9999"); - - // Test: Find returns another IP matching what we searched on. - AddrInfo* info3 = addrman.Find(addr3); - BOOST_REQUIRE(info3); - BOOST_CHECK_EQUAL(info3->ToString(), "251.255.2.1:8333"); -} - -BOOST_AUTO_TEST_CASE(addrman_create) -{ - AddrManTest addrman; - - BOOST_CHECK_EQUAL(addrman.size(), 0U); - - CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); - CNetAddr source1 = ResolveIP("250.1.2.1"); - - int nId; - AddrInfo* pinfo = addrman.Create(addr1, source1, &nId); - - // Test: The result should be the same as the input addr. - BOOST_CHECK_EQUAL(pinfo->ToString(), "250.1.2.1:8333"); - - AddrInfo* info2 = addrman.Find(addr1); - BOOST_CHECK_EQUAL(info2->ToString(), "250.1.2.1:8333"); -} - - -BOOST_AUTO_TEST_CASE(addrman_delete) -{ - AddrManTest addrman; - - BOOST_CHECK_EQUAL(addrman.size(), 0U); - - CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); - CNetAddr source1 = ResolveIP("250.1.2.1"); - - int nId; - addrman.Create(addr1, source1, &nId); - - // Test: Delete should actually delete the addr. - BOOST_CHECK_EQUAL(addrman.size(), 1U); - addrman.Delete(nId); - BOOST_CHECK_EQUAL(addrman.size(), 0U); - AddrInfo* info2 = addrman.Find(addr1); - BOOST_CHECK(info2 == nullptr); -} BOOST_AUTO_TEST_CASE(addrman_getaddr) { - AddrManTest addrman; + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); // Test: Sanity check, GetAddr should never return anything if addrman // is empty. - BOOST_CHECK_EQUAL(addrman.size(), 0U); - std::vector<CAddress> vAddr1 = addrman.GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt); + BOOST_CHECK_EQUAL(addrman->size(), 0U); + std::vector<CAddress> vAddr1 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt); BOOST_CHECK_EQUAL(vAddr1.size(), 0U); CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE); @@ -393,18 +308,18 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) CNetAddr source2 = ResolveIP("250.2.3.3"); // Test: Ensure GetAddr works with new addresses. - BOOST_CHECK(addrman.Add({addr1, addr3, addr5}, source1)); - BOOST_CHECK(addrman.Add({addr2, addr4}, source2)); + BOOST_CHECK(addrman->Add({addr1, addr3, addr5}, source1)); + BOOST_CHECK(addrman->Add({addr2, addr4}, source2)); - BOOST_CHECK_EQUAL(addrman.GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U); + BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U); // Net processing asks for 23% of addresses. 23% of 5 is 1 rounded down. - BOOST_CHECK_EQUAL(addrman.GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U); + BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U); // Test: Ensure GetAddr works with new and tried addresses. - addrman.Good(CAddress(addr1, NODE_NONE)); - addrman.Good(CAddress(addr2, NODE_NONE)); - BOOST_CHECK_EQUAL(addrman.GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U); - BOOST_CHECK_EQUAL(addrman.GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U); + BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE))); + BOOST_CHECK(addrman->Good(CAddress(addr2, NODE_NONE))); + BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 5U); + BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt).size(), 1U); // Test: Ensure GetAddr still returns 23% when addrman has many addrs. for (unsigned int i = 1; i < (8 * 256); i++) { @@ -415,24 +330,22 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) // Ensure that for all addrs in addrman, isTerrible == false. addr.nTime = GetAdjustedTime(); - addrman.Add({addr}, ResolveIP(strAddr)); + addrman->Add({addr}, ResolveIP(strAddr)); if (i % 8 == 0) - addrman.Good(addr); + addrman->Good(addr); } - std::vector<CAddress> vAddr = addrman.GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt); + std::vector<CAddress> vAddr = addrman->GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt); - size_t percent23 = (addrman.size() * 23) / 100; + size_t percent23 = (addrman->size() * 23) / 100; BOOST_CHECK_EQUAL(vAddr.size(), percent23); BOOST_CHECK_EQUAL(vAddr.size(), 461U); // (Addrman.size() < number of addresses added) due to address collisions. - BOOST_CHECK_EQUAL(addrman.size(), 2006U); + BOOST_CHECK_EQUAL(addrman->size(), 2006U); } BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy) { - AddrManTest addrman; - CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE); CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE); @@ -486,8 +399,6 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy) BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy) { - AddrManTest addrman; - CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE); @@ -564,8 +475,6 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy) // 101.8.0.0/16 AS8 BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) { - AddrManTest addrman; - CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE); CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE); @@ -619,8 +528,6 @@ BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) { - AddrManTest addrman; - CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE); @@ -700,72 +607,71 @@ BOOST_AUTO_TEST_CASE(addrman_serialization) { std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8); - auto addrman_asmap1 = std::make_unique<AddrManTest>(asmap1); - auto addrman_asmap1_dup = std::make_unique<AddrManTest>(asmap1); - auto addrman_noasmap = std::make_unique<AddrManTest>(); + const auto ratio = GetCheckRatio(m_node); + auto addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio); + auto addrman_asmap1_dup = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio); + auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio); + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE); CNetAddr default_source; - addrman_asmap1->Add({addr}, default_source); stream << *addrman_asmap1; // serizalizing/deserializing addrman with the same asmap stream >> *addrman_asmap1_dup; - std::pair<int, int> bucketAndEntry_asmap1 = addrman_asmap1->GetBucketAndEntry(addr); - std::pair<int, int> bucketAndEntry_asmap1_dup = addrman_asmap1_dup->GetBucketAndEntry(addr); - BOOST_CHECK(bucketAndEntry_asmap1.second != -1); - BOOST_CHECK(bucketAndEntry_asmap1_dup.second != -1); + AddressPosition addr_pos1 = addrman_asmap1->FindAddressEntry(addr).value(); + AddressPosition addr_pos2 = addrman_asmap1_dup->FindAddressEntry(addr).value(); + BOOST_CHECK(addr_pos1.multiplicity != 0); + BOOST_CHECK(addr_pos2.multiplicity != 0); - BOOST_CHECK(bucketAndEntry_asmap1.first == bucketAndEntry_asmap1_dup.first); - BOOST_CHECK(bucketAndEntry_asmap1.second == bucketAndEntry_asmap1_dup.second); + BOOST_CHECK(addr_pos1 == addr_pos2); // deserializing asmaped peers.dat to non-asmaped addrman stream << *addrman_asmap1; stream >> *addrman_noasmap; - std::pair<int, int> bucketAndEntry_noasmap = addrman_noasmap->GetBucketAndEntry(addr); - BOOST_CHECK(bucketAndEntry_noasmap.second != -1); - BOOST_CHECK(bucketAndEntry_asmap1.first != bucketAndEntry_noasmap.first); - BOOST_CHECK(bucketAndEntry_asmap1.second != bucketAndEntry_noasmap.second); + AddressPosition addr_pos3 = addrman_noasmap->FindAddressEntry(addr).value(); + BOOST_CHECK(addr_pos3.multiplicity != 0); + BOOST_CHECK(addr_pos1.bucket != addr_pos3.bucket); + BOOST_CHECK(addr_pos1.position != addr_pos3.position); // deserializing non-asmaped peers.dat to asmaped addrman - addrman_asmap1 = std::make_unique<AddrManTest>(asmap1); - addrman_noasmap = std::make_unique<AddrManTest>(); + addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio); + addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio); addrman_noasmap->Add({addr}, default_source); stream << *addrman_noasmap; stream >> *addrman_asmap1; - std::pair<int, int> bucketAndEntry_asmap1_deser = addrman_asmap1->GetBucketAndEntry(addr); - BOOST_CHECK(bucketAndEntry_asmap1_deser.second != -1); - BOOST_CHECK(bucketAndEntry_asmap1_deser.first != bucketAndEntry_noasmap.first); - BOOST_CHECK(bucketAndEntry_asmap1_deser.first == bucketAndEntry_asmap1_dup.first); - BOOST_CHECK(bucketAndEntry_asmap1_deser.second == bucketAndEntry_asmap1_dup.second); + + AddressPosition addr_pos4 = addrman_asmap1->FindAddressEntry(addr).value(); + BOOST_CHECK(addr_pos4.multiplicity != 0); + BOOST_CHECK(addr_pos4.bucket != addr_pos3.bucket); + BOOST_CHECK(addr_pos4 == addr_pos2); // used to map to different buckets, now maps to the same bucket. - addrman_asmap1 = std::make_unique<AddrManTest>(asmap1); - addrman_noasmap = std::make_unique<AddrManTest>(); + addrman_asmap1 = std::make_unique<AddrMan>(asmap1, DETERMINISTIC, ratio); + addrman_noasmap = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, ratio); CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE); CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE); addrman_noasmap->Add({addr, addr2}, default_source); - std::pair<int, int> bucketAndEntry_noasmap_addr1 = addrman_noasmap->GetBucketAndEntry(addr1); - std::pair<int, int> bucketAndEntry_noasmap_addr2 = addrman_noasmap->GetBucketAndEntry(addr2); - BOOST_CHECK(bucketAndEntry_noasmap_addr1.first != bucketAndEntry_noasmap_addr2.first); - BOOST_CHECK(bucketAndEntry_noasmap_addr1.second != bucketAndEntry_noasmap_addr2.second); + AddressPosition addr_pos5 = addrman_noasmap->FindAddressEntry(addr1).value(); + AddressPosition addr_pos6 = addrman_noasmap->FindAddressEntry(addr2).value(); + BOOST_CHECK(addr_pos5.bucket != addr_pos6.bucket); stream << *addrman_noasmap; stream >> *addrman_asmap1; - std::pair<int, int> bucketAndEntry_asmap1_deser_addr1 = addrman_asmap1->GetBucketAndEntry(addr1); - std::pair<int, int> bucketAndEntry_asmap1_deser_addr2 = addrman_asmap1->GetBucketAndEntry(addr2); - BOOST_CHECK(bucketAndEntry_asmap1_deser_addr1.first == bucketAndEntry_asmap1_deser_addr2.first); - BOOST_CHECK(bucketAndEntry_asmap1_deser_addr1.second != bucketAndEntry_asmap1_deser_addr2.second); + AddressPosition addr_pos7 = addrman_asmap1->FindAddressEntry(addr1).value(); + AddressPosition addr_pos8 = addrman_asmap1->FindAddressEntry(addr2).value(); + BOOST_CHECK(addr_pos7.bucket == addr_pos8.bucket); + BOOST_CHECK(addr_pos7.position != addr_pos8.position); } BOOST_AUTO_TEST_CASE(remove_invalid) { // Confirm that invalid addresses are ignored in unserialization. - auto addrman = std::make_unique<AddrManTest>(); + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE}; @@ -797,150 +703,156 @@ BOOST_AUTO_TEST_CASE(remove_invalid) BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size()); memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement)); - addrman = std::make_unique<AddrManTest>(); + addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); stream >> *addrman; BOOST_CHECK_EQUAL(addrman->size(), 2); } BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision) { - AddrManTest addrman; + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); - BOOST_CHECK(addrman.size() == 0); + BOOST_CHECK(addrman->size() == 0); // Empty addrman should return blank addrman info. - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); + BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0"); // Add twenty two addresses. CNetAddr source = ResolveIP("252.2.2.2"); for (unsigned int i = 1; i < 23; i++) { CService addr = ResolveService("250.1.1." + ToString(i)); - BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source)); - addrman.Good(addr); + BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source)); - // No collisions yet. - BOOST_CHECK(addrman.size() == i); - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); + // No collisions in tried. + BOOST_CHECK(addrman->Good(addr)); + BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0"); } // Ensure Good handles duplicates well. + // If an address is a duplicate, Good will return false but will not count it as a collision. for (unsigned int i = 1; i < 23; i++) { CService addr = ResolveService("250.1.1." + ToString(i)); - addrman.Good(addr); - BOOST_CHECK(addrman.size() == 22); - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); + // Unable to add duplicate address to tried table. + BOOST_CHECK(!addrman->Good(addr)); + + // Verify duplicate address not marked as a collision. + BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0"); } } BOOST_AUTO_TEST_CASE(addrman_noevict) { - AddrManTest addrman; + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); // Add 35 addresses. CNetAddr source = ResolveIP("252.2.2.2"); for (unsigned int i = 1; i < 36; i++) { CService addr = ResolveService("250.1.1." + ToString(i)); - BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source)); - addrman.Good(addr); + BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source)); // No collision yet. - BOOST_CHECK(addrman.size() == i); - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); + BOOST_CHECK(addrman->Good(addr)); } - // Collision between 36 and 19. + // Collision in tried table between 36 and 19. CService addr36 = ResolveService("250.1.1.36"); - BOOST_CHECK(addrman.Add({CAddress(addr36, NODE_NONE)}, source)); - addrman.Good(addr36); - - BOOST_CHECK(addrman.size() == 36); - BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().first.ToString(), "250.1.1.19:0"); + BOOST_CHECK(addrman->Add({CAddress(addr36, NODE_NONE)}, source)); + BOOST_CHECK(!addrman->Good(addr36)); + BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToString(), "250.1.1.19:0"); // 36 should be discarded and 19 not evicted. - addrman.ResolveCollisions(); - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); + // This means we keep 19 in the tried table and + // 36 stays in the new table. + addrman->ResolveCollisions(); + BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0"); // Lets create two collisions. for (unsigned int i = 37; i < 59; i++) { CService addr = ResolveService("250.1.1." + ToString(i)); - BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source)); - addrman.Good(addr); - - BOOST_CHECK(addrman.size() == i); - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); + BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source)); + BOOST_CHECK(addrman->Good(addr)); } - // Cause a collision. + // Cause a collision in the tried table. CService addr59 = ResolveService("250.1.1.59"); - BOOST_CHECK(addrman.Add({CAddress(addr59, NODE_NONE)}, source)); - addrman.Good(addr59); - BOOST_CHECK(addrman.size() == 59); + BOOST_CHECK(addrman->Add({CAddress(addr59, NODE_NONE)}, source)); + BOOST_CHECK(!addrman->Good(addr59)); - BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().first.ToString(), "250.1.1.10:0"); + BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToString(), "250.1.1.10:0"); - // Cause a second collision. - BOOST_CHECK(!addrman.Add({CAddress(addr36, NODE_NONE)}, source)); - addrman.Good(addr36); - BOOST_CHECK(addrman.size() == 59); + // Cause a second collision in the new table. + BOOST_CHECK(!addrman->Add({CAddress(addr36, NODE_NONE)}, source)); - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() != "[::]:0"); - addrman.ResolveCollisions(); - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); + // 36 still cannot be moved from new to tried due to colliding with 19 + BOOST_CHECK(!addrman->Good(addr36)); + BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() != "[::]:0"); + + // Resolve all collisions. + addrman->ResolveCollisions(); + BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0"); } BOOST_AUTO_TEST_CASE(addrman_evictionworks) { - AddrManTest addrman; + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); - BOOST_CHECK(addrman.size() == 0); + BOOST_CHECK(addrman->size() == 0); // Empty addrman should return blank addrman info. - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); + BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0"); // Add 35 addresses CNetAddr source = ResolveIP("252.2.2.2"); for (unsigned int i = 1; i < 36; i++) { CService addr = ResolveService("250.1.1." + ToString(i)); - BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source)); - addrman.Good(addr); + BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source)); // No collision yet. - BOOST_CHECK(addrman.size() == i); - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); + BOOST_CHECK(addrman->Good(addr)); } // Collision between 36 and 19. CService addr = ResolveService("250.1.1.36"); - BOOST_CHECK(addrman.Add({CAddress(addr, NODE_NONE)}, source)); - addrman.Good(addr); + BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source)); + BOOST_CHECK(!addrman->Good(addr)); - BOOST_CHECK_EQUAL(addrman.size(), 36); - auto info = addrman.SelectTriedCollision().first; + auto info = addrman->SelectTriedCollision().first; BOOST_CHECK_EQUAL(info.ToString(), "250.1.1.19:0"); // Ensure test of address fails, so that it is evicted. - addrman.SimConnFail(info); + // 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); // Should swap 36 for 19. - addrman.ResolveCollisions(); - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); - - // If 36 was swapped for 19, then this should cause no collisions. - BOOST_CHECK(!addrman.Add({CAddress(addr, NODE_NONE)}, source)); - addrman.Good(addr); - - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); - - // If we insert 19 it should collide with 36 + addrman->ResolveCollisions(); + BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0"); + AddressPosition addr_pos{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()}; + BOOST_CHECK(addr_pos.tried); + + // If 36 was swapped for 19, then adding 36 to tried should fail because we + // are attempting to add a duplicate. + // We check this by verifying Good() returns false and also verifying that + // we have no collisions. + BOOST_CHECK(!addrman->Good(addr)); + BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0"); + + // 19 should fail as a collision (not a duplicate) if we now attempt to move + // it to the tried table. CService addr19 = ResolveService("250.1.1.19"); - BOOST_CHECK(!addrman.Add({CAddress(addr19, NODE_NONE)}, source)); - addrman.Good(addr19); - - BOOST_CHECK_EQUAL(addrman.SelectTriedCollision().first.ToString(), "250.1.1.36:0"); - - addrman.ResolveCollisions(); - BOOST_CHECK(addrman.SelectTriedCollision().first.ToString() == "[::]:0"); + BOOST_CHECK(!addrman->Good(addr19)); + BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToString(), "250.1.1.36:0"); + + // Eviction is also successful if too much time has passed since last try + SetMockTime(GetTime() + 4 * 60 *60); + addrman->ResolveCollisions(); + BOOST_CHECK(addrman->SelectTriedCollision().first.ToString() == "[::]:0"); + //Now 19 is in tried again, and 36 back to new + AddressPosition addr_pos19{addrman->FindAddressEntry(CAddress(addr19, NODE_NONE)).value()}; + BOOST_CHECK(addr_pos19.tried); + AddressPosition addr_pos36{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()}; + BOOST_CHECK(!addr_pos36.tried); } static CDataStream AddrmanToStream(const AddrMan& addrman) @@ -953,8 +865,7 @@ static CDataStream AddrmanToStream(const AddrMan& addrman) BOOST_AUTO_TEST_CASE(load_addrman) { - AddrMan addrman{/*asmap=*/ std::vector<bool>(), /*deterministic=*/ true, - /*consistency_check_ratio=*/ 100}; + AddrMan addrman{EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)}; CService addr1, addr2, addr3; BOOST_CHECK(Lookup("250.7.1.1", addr1, 8333, false)); @@ -973,7 +884,7 @@ BOOST_AUTO_TEST_CASE(load_addrman) // Test that the de-serialization does not throw an exception. CDataStream ssPeers1 = AddrmanToStream(addrman); bool exceptionThrown = false; - AddrMan addrman1(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); + AddrMan addrman1{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)}; BOOST_CHECK(addrman1.size() == 0); try { @@ -990,7 +901,7 @@ BOOST_AUTO_TEST_CASE(load_addrman) // Test that ReadFromStream creates an addrman with the correct number of addrs. CDataStream ssPeers2 = AddrmanToStream(addrman); - AddrMan addrman2(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); + AddrMan addrman2{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)}; BOOST_CHECK(addrman2.size() == 0); ReadFromStream(addrman2, ssPeers2); BOOST_CHECK(addrman2.size() == 3); @@ -1028,7 +939,7 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted) // Test that the de-serialization of corrupted peers.dat throws an exception. CDataStream ssPeers1 = MakeCorruptPeersDat(); bool exceptionThrown = false; - AddrMan addrman1(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); + AddrMan addrman1{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)}; BOOST_CHECK(addrman1.size() == 0); try { unsigned char pchMsgTmp[4]; @@ -1044,10 +955,40 @@ BOOST_AUTO_TEST_CASE(load_addrman_corrupted) // Test that ReadFromStream fails if peers.dat is corrupt CDataStream ssPeers2 = MakeCorruptPeersDat(); - AddrMan addrman2(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/100); + AddrMan addrman2{EMPTY_ASMAP, !DETERMINISTIC, GetCheckRatio(m_node)}; BOOST_CHECK(addrman2.size() == 0); BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure); } +BOOST_AUTO_TEST_CASE(addrman_update_address) +{ + // Tests updating nTime via Connected() and nServices via SetServices() + auto addrman = std::make_unique<AddrMan>(EMPTY_ASMAP, DETERMINISTIC, GetCheckRatio(m_node)); + CNetAddr source{ResolveIP("252.2.2.2")}; + CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)}; + + int64_t start_time{GetAdjustedTime() - 10000}; + addr.nTime = start_time; + BOOST_CHECK(addrman->Add({addr}, source)); + BOOST_CHECK_EQUAL(addrman->size(), 1U); + + // Updating an addrman entry with a different port doesn't change it + CAddress addr_diff_port{CAddress(ResolveService("250.1.1.1", 8334), NODE_NONE)}; + addr_diff_port.nTime = start_time; + addrman->Connected(addr_diff_port); + 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_EQUAL(vAddr1.at(0).nServices, NODE_NONE); + + // Updating an addrman entry with the correct port is successful + addrman->Connected(addr); + 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_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp index 3779e7b964..715ce0a5b4 100644 --- a/src/test/allocator_tests.cpp +++ b/src/test/allocator_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2019 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/amount_tests.cpp b/src/test/amount_tests.cpp index aa23d71671..3815a5bba6 100644 --- a/src/test/amount_tests.cpp +++ b/src/test/amount_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/test/arith_uint256_tests.cpp b/src/test/arith_uint256_tests.cpp index a00888aae6..a923d38467 100644 --- a/src/test/arith_uint256_tests.cpp +++ b/src/test/arith_uint256_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -129,11 +129,11 @@ static void shiftArrayRight(unsigned char* to, const unsigned char* from, unsign { unsigned int F = (T+bitsToShift/8); if (F < arrayLength) - to[T] = from[F] >> (bitsToShift%8); + to[T] = uint8_t(from[F] >> (bitsToShift % 8)); else to[T] = 0; if (F + 1 < arrayLength) - to[T] |= from[(F+1)] << (8-bitsToShift%8); + to[T] |= uint8_t(from[(F + 1)] << (8 - bitsToShift % 8)); } } @@ -144,9 +144,9 @@ static void shiftArrayLeft(unsigned char* to, const unsigned char* from, unsigne if (T >= bitsToShift/8) { unsigned int F = T-bitsToShift/8; - to[T] = from[F] << (bitsToShift%8); + to[T] = uint8_t(from[F] << (bitsToShift % 8)); if (T >= bitsToShift/8+1) - to[T] |= from[F-1] >> (8-bitsToShift%8); + to[T] |= uint8_t(from[F - 1] >> (8 - bitsToShift % 8)); } else { to[T] = 0; @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE( unaryOperators ) // ! ~ - BOOST_CHECK(~ZeroL == MaxL); unsigned char TmpArray[32]; - for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = ~R1Array[i]; } + for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = uint8_t(~R1Array[i]); } BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (~R1L)); BOOST_CHECK(-ZeroL == ZeroL); @@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE( unaryOperators ) // ! ~ - // Check if doing _A_ _OP_ _B_ results in the same as applying _OP_ onto each // element of Aarray and Barray, and then converting the result into an arith_uint256. #define CHECKBITWISEOPERATOR(_A_,_B_,_OP_) \ - for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = _A_##Array[i] _OP_ _B_##Array[i]; } \ + for (unsigned int i = 0; i < 32; ++i) { TmpArray[i] = uint8_t(_A_##Array[i] _OP_ _B_##Array[i]); } \ BOOST_CHECK(arith_uint256V(std::vector<unsigned char>(TmpArray,TmpArray+32)) == (_A_##L _OP_ _B_##L)); #define CHECKASSIGNMENTOPERATOR(_A_,_B_,_OP_) \ diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp index 22853555e2..5fab7f0d1e 100644 --- a/src/test/base32_tests.cpp +++ b/src/test/base32_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index a090cb340b..00f32ddcee 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp index c5fce7bec0..6ee1b83691 100644 --- a/src/test/base64_tests.cpp +++ b/src/test/base64_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp index 7d50def509..7c502349b3 100644 --- a/src/test/blockfilter_index_tests.cpp +++ b/src/test/blockfilter_index_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -16,6 +16,10 @@ #include <boost/test/unit_test.hpp> +using node::BlockAssembler; +using node::CBlockTemplate; +using node::IncrementExtraNonce; + BOOST_AUTO_TEST_SUITE(blockfilter_index_tests) struct BuildChainTestingSetup : public TestChain100Setup { diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index fe5ed0a3c8..35c4108caa 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -43,8 +43,9 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) stream << filter; std::vector<uint8_t> expected = ParseHex("03614e9b050000000000000001"); + auto result{MakeUCharSpan(stream)}; - BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter doesn't contain just-inserted object!"); } @@ -69,8 +70,9 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) stream << filter; std::vector<uint8_t> expected = ParseHex("03ce4299050000000100008001"); + auto result{MakeUCharSpan(stream)}; - BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); } BOOST_AUTO_TEST_CASE(bloom_create_insert_key) @@ -89,8 +91,9 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key) stream << filter; std::vector<unsigned char> expected = ParseHex("038fc16b080000000000000001"); + auto result{MakeUCharSpan(stream)}; - BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); + BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end()); } BOOST_AUTO_TEST_CASE(bloom_match) @@ -341,8 +344,9 @@ BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) merkleStream << merkleBlock; std::vector<uint8_t> expected = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101"); + auto result{MakeUCharSpan(merkleStream)}; - BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), merkleStream.begin(), merkleStream.end()); + BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), result.begin(), result.end()); } BOOST_AUTO_TEST_CASE(merkle_block_4) diff --git a/src/test/bswap_tests.cpp b/src/test/bswap_tests.cpp index 4e75e74d77..2be7122fc1 100644 --- a/src/test/bswap_tests.cpp +++ b/src/test/bswap_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 4d34407ca8..153ccd984b 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 91218511bd..82e4e1c90f 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020 The Bitcoin Core developers +// Copyright (c) 2014-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. @@ -324,7 +324,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) tx.vout.resize(1); tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate tx.vout[0].scriptPubKey.assign(InsecureRand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting - unsigned int height = InsecureRand32(); + const int height{int(InsecureRand32() >> 1)}; Coin old_coin; // 2/20 times create a new coinbase @@ -393,11 +393,11 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) // Update the expected result to know about the new output coins assert(tx.vout.size() == 1); const COutPoint outpoint(tx.GetHash(), 0); - result[outpoint] = Coin(tx.vout[0], height, CTransaction(tx).IsCoinBase()); + result[outpoint] = Coin{tx.vout[0], height, CTransaction{tx}.IsCoinBase()}; // Call UpdateCoins on the top cache CTxUndo undo; - UpdateCoins(CTransaction(tx), *(stack.back()), undo, height); + UpdateCoins(CTransaction{tx}, *(stack.back()), undo, height); // Update the utxo set for future spends utxoset.insert(outpoint); diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp index 597d7a7340..92de4ec7ba 100644 --- a/src/test/coinstatsindex_tests.cpp +++ b/src/test/coinstatsindex_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -11,6 +11,8 @@ #include <chrono> +using node::CCoinsStats; +using node::CoinStatsHashType; BOOST_AUTO_TEST_SUITE(coinstatsindex_tests) diff --git a/src/test/compilerbug_tests.cpp b/src/test/compilerbug_tests.cpp index a9cec624ae..ef558c1e32 100644 --- a/src/test/compilerbug_tests.cpp +++ b/src/test/compilerbug_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp index b7ba46bd30..de99b91c7f 100644 --- a/src/test/compress_tests.cpp +++ b/src/test/compress_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index bedef5de37..6148edf115 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020 The Bitcoin Core developers +// Copyright (c) 2014-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. diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp index 35b66cfc53..c7c34cc8c9 100644 --- a/src/test/cuckoocache_tests.cpp +++ b/src/test/cuckoocache_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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 <cuckoocache.h> diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json index 724789bbf9..ad05240369 100644 --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -1269,6 +1269,10 @@ [["51", 0.00000000 ], "", "0 0x206e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", "P2SH,WITNESS", "WITNESS_PROGRAM_MISMATCH", "Witness script hash mismatch"], [["00", 0.00000000 ], "", "0 0x206e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", "", "OK", "Invalid witness script without WITNESS"], [["51", 0.00000000 ], "", "0 0x206e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d", "", "OK", "Witness script hash mismatch without WITNESS"], +[["51", 0.00000000 ], "", "-1 0x021234", "P2SH,WITNESS", "WITNESS_UNEXPECTED", "OP_1NEGATE does not introduce a witness program"], +[["51", 0.00000000 ], "00", "1 0x021234", "P2SH,WITNESS", "WITNESS_MALLEATED", "OP_1 does introduce a witness program"], +[["51", 0.00000000 ], "00", "16 0x021234", "P2SH,WITNESS", "WITNESS_MALLEATED", "OP_16 does introduce a witness program"], +[["51", 0.00000000 ], "", "NOP 0x021234", "P2SH,WITNESS", "WITNESS_UNEXPECTED", "NOP does not introduce a witness program"], ["Automatically generated test cases"], [ diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index b6f5938892..2f95cc27a3 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 1465e80157..a17cc87730 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -59,7 +59,16 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) // Mock an outbound peer CAddress addr1(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK | NODE_WITNESS), INVALID_SOCKET, addr1, /*nKeyedNetGroupIn=*/0, /*nLocalHostNonceIn=*/0, CAddress(), /*addrNameIn=*/"", ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false); + CNode dummyNode1{id++, + ServiceFlags(NODE_NETWORK | NODE_WITNESS), + /*sock=*/nullptr, + addr1, + /*nKeyedNetGroupIn=*/0, + /*nLocalHostNonceIn=*/0, + CAddress(), + /*addrNameIn=*/"", + ConnectionType::OUTBOUND_FULL_RELAY, + /*inbound_onion=*/false}; dummyNode1.SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(&dummyNode1); @@ -108,7 +117,16 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) static void AddRandomOutboundPeer(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), INVALID_SOCKET, addr, /*nKeyedNetGroupIn=*/0, /*nLocalHostNonceIn=*/0, CAddress(), /*addrNameIn=*/"", connType, /*inbound_onion=*/false)); + vNodes.emplace_back(new CNode{id++, + ServiceFlags(NODE_NETWORK | NODE_WITNESS), + /*sock=*/nullptr, + addr, + /*nKeyedNetGroupIn=*/0, + /*nLocalHostNonceIn=*/0, + CAddress(), + /*addrNameIn=*/"", + connType, + /*inbound_onion=*/false}); CNode &node = *vNodes.back(); node.SetCommonVersion(PROTOCOL_VERSION); @@ -279,9 +297,16 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) std::array<CNode*, 3> nodes; banman->ClearBanned(); - nodes[0] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[0], /*nKeyedNetGroupIn=*/0, - /*nLocalHostNonceIn=*/0, CAddress(), /*addrNameIn=*/"", - ConnectionType::INBOUND, /*inbound_onion=*/false}; + nodes[0] = new CNode{id++, + NODE_NETWORK, + /*sock=*/nullptr, + addr[0], + /*nKeyedNetGroupIn=*/0, + /*nLocalHostNonceIn=*/0, + CAddress(), + /*addrNameIn=*/"", + ConnectionType::INBOUND, + /*inbound_onion=*/false}; nodes[0]->SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(nodes[0]); nodes[0]->fSuccessfullyConnected = true; @@ -295,9 +320,16 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) BOOST_CHECK(nodes[0]->fDisconnect); BOOST_CHECK(!banman->IsDiscouraged(other_addr)); // Different address, not discouraged - nodes[1] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[1], /*nKeyedNetGroupIn=*/1, - /*nLocalHostNonceIn=*/1, CAddress(), /*addrNameIn=*/"", - ConnectionType::INBOUND, /*inbound_onion=*/false}; + nodes[1] = new CNode{id++, + NODE_NETWORK, + /*sock=*/nullptr, + addr[1], + /*nKeyedNetGroupIn=*/1, + /*nLocalHostNonceIn=*/1, + CAddress(), + /*addrNameIn=*/"", + ConnectionType::INBOUND, + /*inbound_onion=*/false}; nodes[1]->SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(nodes[1]); nodes[1]->fSuccessfullyConnected = true; @@ -326,9 +358,16 @@ BOOST_AUTO_TEST_CASE(peer_discouragement) // Make sure non-IP peers are discouraged and disconnected properly. - nodes[2] = new CNode{id++, NODE_NETWORK, INVALID_SOCKET, addr[2], /*nKeyedNetGroupIn=*/1, - /*nLocalHostNonceIn=*/1, CAddress(), /*addrNameIn=*/"", - ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false}; + nodes[2] = new CNode{id++, + NODE_NETWORK, + /*sock=*/nullptr, + addr[2], + /*nKeyedNetGroupIn=*/1, + /*nLocalHostNonceIn=*/1, + CAddress(), + /*addrNameIn=*/"", + ConnectionType::OUTBOUND_FULL_RELAY, + /*inbound_onion=*/false}; nodes[2]->SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(nodes[2]); nodes[2]->fSuccessfullyConnected = true; @@ -364,7 +403,16 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) SetMockTime(nStartTime); // Overrides future calls to GetTime() CAddress addr(ip(0xa0b0c001), NODE_NONE); - CNode dummyNode(id++, NODE_NETWORK, INVALID_SOCKET, addr, /*nKeyedNetGroupIn=*/4, /*nLocalHostNonceIn=*/4, CAddress(), /*addrNameIn=*/"", ConnectionType::INBOUND, /*inbound_onion=*/false); + CNode dummyNode{id++, + NODE_NETWORK, + /*sock=*/nullptr, + addr, + /*nKeyedNetGroupIn=*/4, + /*nLocalHostNonceIn=*/4, + CAddress(), + /*addrNameIn=*/"", + ConnectionType::INBOUND, + /*inbound_onion=*/false}; dummyNode.SetCommonVersion(PROTOCOL_VERSION); peerLogic->InitializeNode(&dummyNode); dummyNode.fSuccessfullyConnected = true; diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index 8553f80a17..5a3e382c3f 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -42,6 +42,7 @@ constexpr int HARDENED = 2; // Derivation needs access to private keys constexpr int UNSOLVABLE = 4; // This descriptor is not expected to be solvable constexpr int SIGNABLE = 8; // We can sign with this descriptor (this is not true when actual BIP32 derivation is used, as that's not integrated in our signing code) constexpr int DERIVE_HARDENED = 16; // The final derivation is hardened, i.e. ends with *' or *h +constexpr int MIXED_PUBKEYS = 32; /** Compare two descriptors. If only one of them has a checksum, the checksum is ignored. */ bool EqualDescriptor(std::string a, std::string b) @@ -73,6 +74,18 @@ std::string UseHInsteadOfApostrophe(const std::string& desc) return ret; } +// Count the number of times the string "xpub" appears in a descriptor string +static size_t CountXpubs(const std::string& desc) +{ + size_t count = 0; + size_t p = desc.find("xpub", 0); + while (p != std::string::npos) { + count++; + p = desc.find("xpub", p + 1); + } + return count; +} + const std::set<std::vector<uint32_t>> ONLY_EMPTY{{}}; void DoCheck(const std::string& prv, const std::string& pub, const std::string& norm_prv, const std::string& norm_pub, int flags, const std::vector<std::vector<std::string>>& scripts, const std::optional<OutputType>& type, const std::set<std::vector<uint32_t>>& paths = ONLY_EMPTY, @@ -171,7 +184,8 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string& // Check whether keys are in the cache const auto& der_xpub_cache = desc_cache.GetCachedDerivedExtPubKeys(); const auto& parent_xpub_cache = desc_cache.GetCachedParentExtPubKeys(); - if ((flags & RANGE) && !(flags & DERIVE_HARDENED)) { + const size_t num_xpubs = CountXpubs(pub1); + if ((flags & RANGE) && !(flags & (DERIVE_HARDENED))) { // For ranged, unhardened derivation, None of the keys in origins should appear in the cache but the cache should have parent keys // But we can derive one level from each of those parent keys and find them all BOOST_CHECK(der_xpub_cache.empty()); @@ -183,13 +197,22 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string& xpub.Derive(der, i); pubkeys.insert(der.pubkey); } + int count_pks = 0; for (const auto& origin_pair : script_provider_cached.origins) { const CPubKey& pk = origin_pair.second.first; - BOOST_CHECK(pubkeys.count(pk) > 0); + count_pks += pubkeys.count(pk); } - } else if (pub1.find("xpub") != std::string::npos) { + if (flags & MIXED_PUBKEYS) { + BOOST_CHECK_EQUAL(num_xpubs, count_pks); + } else { + BOOST_CHECK_EQUAL(script_provider_cached.origins.size(), count_pks); + } + } else if (num_xpubs > 0) { // For ranged, hardened derivation, or not ranged, but has an xpub, all of the keys should appear in the cache - BOOST_CHECK(der_xpub_cache.size() + parent_xpub_cache.size() == script_provider_cached.origins.size()); + BOOST_CHECK(der_xpub_cache.size() + parent_xpub_cache.size() == num_xpubs); + if (!(flags & MIXED_PUBKEYS)) { + BOOST_CHECK(num_xpubs == script_provider_cached.origins.size()); + } // Get all of the derived pubkeys std::set<CPubKey> pubkeys; for (const auto& xpub_map_pair : der_xpub_cache) { @@ -206,12 +229,18 @@ void DoCheck(const std::string& prv, const std::string& pub, const std::string& xpub.Derive(der, i); pubkeys.insert(der.pubkey); } + int count_pks = 0; for (const auto& origin_pair : script_provider_cached.origins) { const CPubKey& pk = origin_pair.second.first; - BOOST_CHECK(pubkeys.count(pk) > 0); + count_pks += pubkeys.count(pk); } - } else { - // No xpub, nothing should be cached + if (flags & MIXED_PUBKEYS) { + BOOST_CHECK_EQUAL(num_xpubs, count_pks); + } else { + BOOST_CHECK_EQUAL(script_provider_cached.origins.size(), count_pks); + } + } else if (!(flags & MIXED_PUBKEYS)) { + // Only const pubkeys, nothing should be cached BOOST_CHECK(der_xpub_cache.empty()); BOOST_CHECK(parent_xpub_cache.empty()); } @@ -333,6 +362,11 @@ BOOST_AUTO_TEST_CASE(descriptor_test) Check("wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", "wpkh([ffffffff/13']xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt/1/2/*)", "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)", RANGE, {{"0014326b2249e3a25d5dc60935f044ee835d090ba859"},{"0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7"},{"00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27"}}, OutputType::BECH32, {{0x8000000DUL, 1, 2, 0}, {0x8000000DUL, 1, 2, 1}, {0x8000000DUL, 1, 2, 2}}); Check("sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", "sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))", "sh(wpkh(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8/10/20/30/40/*'))", RANGE | HARDENED | DERIVE_HARDENED, {{"a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87"},{"a914bed59fc0024fae941d6e20a3b44a109ae740129287"},{"a9148483aa1116eb9c05c482a72bada4b1db24af654387"}}, OutputType::P2SH_SEGWIT, {{10, 20, 30, 40, 0x80000000UL}, {10, 20, 30, 40, 0x80000001UL}, {10, 20, 30, 40, 0x80000002UL}}); Check("combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", "combo(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*)", "combo(xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*)", RANGE, {{"2102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076ac","76a914f90e3178ca25f2c808dc76624032d352fdbdfaf288ac","0014f90e3178ca25f2c808dc76624032d352fdbdfaf2","a91408f3ea8c68d4a7585bf9e8bda226723f70e445f087"},{"21032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ecac","76a914a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b788ac","0014a8409d1b6dfb1ed2a3e8aa5e0ef2ff26b15b75b7","a91473e39884cb71ae4e5ac9739e9225026c99763e6687"}}, std::nullopt, {{0}, {1}}); + // Mixed xpubs and const pubkeys + Check("wsh(multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))","wsh(multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))","wsh(multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/0,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))", MIXED_PUBKEYS, {{"0020cb155486048b23a6da976d4c6fe071a2dbc8a7b57aaf225b8955f2e2a27b5f00"}},OutputType::BECH32,{{0},{}}); + // Mixed range xpubs and const pubkeys + Check("multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)","multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)","multi(1,xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/*,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1)","multi(1,xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV/*,03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd)", RANGE | MIXED_PUBKEYS, {{"512102df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e0762103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"},{"5121032869a233c9adff9a994e4966e5b821fd5bac066da6c3112488dc52383b4a98ec2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"},{"5121035d30b6c66dc1e036c45369da8287518cf7e0d6ed1e2b905171c605708f14ca032103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd52ae"}}, std::nullopt,{{2},{1},{0},{}}); + CheckUnparsable("combo([012345678]xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc)", "combo([012345678]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL)", "Fingerprint is not 4 bytes (9 characters instead of 8 characters)"); // Too long key fingerprint CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/2147483648)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483648)", "Key path value 2147483648 is out of range"); // BIP 32 path element overflow CheckUnparsable("pkh(xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U/1aa)", "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1aa)", "Key path value '1aa' is not a valid uint32"); // Path is not valid uint diff --git a/src/test/flatfile_tests.cpp b/src/test/flatfile_tests.cpp index f4bc320f3c..d54d6b6471 100644 --- a/src/test/flatfile_tests.cpp +++ b/src/test/flatfile_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index ecb838a7dd..4fb2c23d98 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. // @@ -9,6 +9,10 @@ #include <boost/test/unit_test.hpp> +#include <fstream> +#include <ios> +#include <string> + BOOST_FIXTURE_TEST_SUITE(fs_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(fsbridge_pathtostring) @@ -45,37 +49,37 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream) fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃"; fs::path tmpfile2 = tmpfolder / "fs_tests_₿_🏃"; { - fsbridge::ofstream file(tmpfile1); + std::ofstream file{tmpfile1}; file << "bitcoin"; } { - fsbridge::ifstream file(tmpfile2); + std::ifstream file{tmpfile2}; std::string input_buffer; file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); } { - fsbridge::ifstream file(tmpfile1, std::ios_base::in | std::ios_base::ate); + std::ifstream file{tmpfile1, std::ios_base::in | std::ios_base::ate}; std::string input_buffer; file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, ""); } { - fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::app); + std::ofstream file{tmpfile2, std::ios_base::out | std::ios_base::app}; file << "tests"; } { - fsbridge::ifstream file(tmpfile1); + std::ifstream file{tmpfile1}; std::string input_buffer; file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, "bitcointests"); } { - fsbridge::ofstream file(tmpfile2, std::ios_base::out | std::ios_base::trunc); + std::ofstream file{tmpfile2, std::ios_base::out | std::ios_base::trunc}; file << "bitcoin"; } { - fsbridge::ifstream file(tmpfile1); + std::ifstream file{tmpfile1}; std::string input_buffer; file >> input_buffer; BOOST_CHECK_EQUAL(input_buffer, "bitcoin"); @@ -114,4 +118,38 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream) } } -BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file +BOOST_AUTO_TEST_CASE(rename) +{ + const fs::path tmpfolder{m_args.GetDataDirBase()}; + + const fs::path path1{GetUniquePath(tmpfolder)}; + const fs::path path2{GetUniquePath(tmpfolder)}; + + const std::string path1_contents{"1111"}; + const std::string path2_contents{"2222"}; + + { + std::ofstream file{path1}; + file << path1_contents; + } + + { + std::ofstream file{path2}; + file << path2_contents; + } + + // Rename path1 -> path2. + BOOST_CHECK(RenameOver(path1, path2)); + + BOOST_CHECK(!fs::exists(path1)); + + { + std::ifstream file{path2}; + std::string contents; + file >> contents; + BOOST_CHECK_EQUAL(contents, path1_contents); + } + fs::remove(path2); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/fuzz/addition_overflow.cpp b/src/test/fuzz/addition_overflow.cpp index c6cfbd8d30..cfad41659e 100644 --- a/src/test/fuzz/addition_overflow.cpp +++ b/src/test/fuzz/addition_overflow.cpp @@ -5,6 +5,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <util/overflow.h> #include <cstdint> #include <string> diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index 9c85c20e2b..3699abb597 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -11,8 +11,10 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/util/setup_common.h> #include <time.h> #include <util/asmap.h> +#include <util/system.h> #include <cassert> #include <cstdint> @@ -20,16 +22,26 @@ #include <string> #include <vector> +namespace { +const BasicTestingSetup* g_setup; + +int32_t GetCheckRatio() +{ + return std::clamp<int32_t>(g_setup->m_node.args->GetIntArg("-checkaddrman", 0), 0, 1000000); +} +} // namespace + void initialize_addrman() { - SelectParams(CBaseChainParams::REGTEST); + static const auto testing_setup = MakeNoLogFileContext<>(CBaseChainParams::REGTEST); + g_setup = testing_setup.get(); } FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); - AddrMan addr_man(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); + AddrMan addr_man{/*asmap=*/std::vector<bool>(), /*deterministic=*/false, GetCheckRatio()}; try { ReadFromStream(addr_man, data_stream); } catch (const std::exception&) { @@ -113,7 +125,7 @@ class AddrManDeterministic : public AddrMan { public: explicit AddrManDeterministic(std::vector<bool> asmap, FuzzedDataProvider& fuzzed_data_provider) - : AddrMan(std::move(asmap), /*deterministic=*/true, /*consistency_check_ratio=*/0) + : AddrMan{std::move(asmap), /*deterministic=*/true, GetCheckRatio()} { WITH_LOCK(m_impl->cs, m_impl->insecure_rand = FastRandomContext{ConsumeUInt256(fuzzed_data_provider)}); } diff --git a/src/test/fuzz/asmap.cpp b/src/test/fuzz/asmap.cpp index c5e9c56049..95be963dc8 100644 --- a/src/test/fuzz/asmap.cpp +++ b/src/test/fuzz/asmap.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/asmap_direct.cpp b/src/test/fuzz/asmap_direct.cpp index 8ca4de3919..8a355fd3f6 100644 --- a/src/test/fuzz/asmap_direct.cpp +++ b/src/test/fuzz/asmap_direct.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/autofile.cpp b/src/test/fuzz/autofile.cpp index 0cc2d12d29..3b410930ed 100644 --- a/src/test/fuzz/autofile.cpp +++ b/src/test/fuzz/autofile.cpp @@ -23,16 +23,16 @@ FUZZ_TARGET(autofile) CallOneOf( fuzzed_data_provider, [&] { - std::array<uint8_t, 4096> arr{}; + std::array<std::byte, 4096> arr{}; try { - auto_file.read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); + auto_file.read({arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)}); } catch (const std::ios_base::failure&) { } }, [&] { - const std::array<uint8_t, 4096> arr{}; + const std::array<std::byte, 4096> arr{}; try { - auto_file.write((const char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); + auto_file.write({arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)}); } catch (const std::ios_base::failure&) { } }, diff --git a/src/test/fuzz/base_encode_decode.cpp b/src/test/fuzz/base_encode_decode.cpp index 2b4f15115b..196410e29c 100644 --- a/src/test/fuzz/base_encode_decode.cpp +++ b/src/test/fuzz/base_encode_decode.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/test/fuzz/bech32.cpp b/src/test/fuzz/bech32.cpp index ad3bf73af4..ffc5ba518f 100644 --- a/src/test/fuzz/bech32.cpp +++ b/src/test/fuzz/bech32.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp index 65a33de4b4..b7ed2c6abd 100644 --- a/src/test/fuzz/block.cpp +++ b/src/test/fuzz/block.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -58,8 +58,6 @@ FUZZ_TARGET_INIT(block, initialize_block) (void)block.ToString(); (void)BlockMerkleRoot(block); if (!block.vtx.empty()) { - // TODO: Avoid array index out of bounds error in BlockWitnessMerkleRoot - // when block.vtx.empty(). (void)BlockWitnessMerkleRoot(block); } (void)GetBlockWeight(block); diff --git a/src/test/fuzz/blockfilter.cpp b/src/test/fuzz/blockfilter.cpp index 96f049625d..3adc114515 100644 --- a/src/test/fuzz/blockfilter.cpp +++ b/src/test/fuzz/blockfilter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/buffered_file.cpp b/src/test/fuzz/buffered_file.cpp index c3c2e4050f..a8c3318629 100644 --- a/src/test/fuzz/buffered_file.cpp +++ b/src/test/fuzz/buffered_file.cpp @@ -33,9 +33,9 @@ FUZZ_TARGET(buffered_file) CallOneOf( fuzzed_data_provider, [&] { - std::array<uint8_t, 4096> arr{}; + std::array<std::byte, 4096> arr{}; try { - opt_buffered_file->read((char*)arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)); + opt_buffered_file->read({arr.data(), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096)}); } catch (const std::ios_base::failure&) { } }, @@ -53,7 +53,7 @@ FUZZ_TARGET(buffered_file) return; } try { - opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral<char>()); + opt_buffered_file->FindByte(fuzzed_data_provider.ConsumeIntegral<uint8_t>()); } catch (const std::ios_base::failure&) { } }, diff --git a/src/test/fuzz/chain.cpp b/src/test/fuzz/chain.cpp index 0e12a55408..8c0ed32d51 100644 --- a/src/test/fuzz/chain.cpp +++ b/src/test/fuzz/chain.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -21,15 +21,18 @@ FUZZ_TARGET(chain) const uint256 zero{}; disk_block_index->phashBlock = &zero; - (void)disk_block_index->GetBlockHash(); - (void)disk_block_index->GetBlockPos(); - (void)disk_block_index->GetBlockTime(); - (void)disk_block_index->GetBlockTimeMax(); - (void)disk_block_index->GetMedianTimePast(); - (void)disk_block_index->GetUndoPos(); - (void)disk_block_index->HaveTxsDownloaded(); - (void)disk_block_index->IsValid(); - (void)disk_block_index->ToString(); + { + LOCK(::cs_main); + (void)disk_block_index->GetBlockHash(); + (void)disk_block_index->GetBlockPos(); + (void)disk_block_index->GetBlockTime(); + (void)disk_block_index->GetBlockTimeMax(); + (void)disk_block_index->GetMedianTimePast(); + (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(); (void)CDiskBlockIndex{*disk_block_index}; @@ -55,7 +58,7 @@ FUZZ_TARGET(chain) if (block_status & ~BLOCK_VALID_MASK) { continue; } - (void)disk_block_index->RaiseValidity(block_status); + WITH_LOCK(::cs_main, (void)disk_block_index->RaiseValidity(block_status)); } CBlockIndex block_index{block_header}; diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp index 2f33598348..360dc00307 100644 --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -26,6 +26,10 @@ #include <string> #include <vector> +using node::CCoinsStats; +using node::CoinStatsHashType; +using node::GetUTXOStats; + namespace { const TestingSetup* g_setup; const Coin EMPTY_COIN{}; @@ -207,7 +211,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view) return; } bool expected_code_path = false; - const int height = fuzzed_data_provider.ConsumeIntegral<int>(); + const int height{int(fuzzed_data_provider.ConsumeIntegral<uint32_t>() >> 1)}; const bool possible_overwrite = fuzzed_data_provider.ConsumeBool(); try { AddCoins(coins_view_cache, transaction, height, possible_overwrite); @@ -269,7 +273,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view) CCoinsStats stats{CoinStatsHashType::HASH_SERIALIZED}; bool expected_code_path = false; try { - (void)GetUTXOStats(&coins_view_cache, WITH_LOCK(::cs_main, return std::ref(g_setup->m_node.chainman->m_blockman)), stats); + (void)GetUTXOStats(&coins_view_cache, g_setup->m_node.chainman->m_blockman, stats); } catch (const std::logic_error&) { expected_code_path = true; } diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index f87b6f1503..a14d28f4ef 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -12,21 +12,29 @@ #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> #include <test/util/setup_common.h> +#include <util/system.h> #include <util/translation.h> #include <cstdint> #include <vector> +namespace { +const BasicTestingSetup* g_setup; +} // namespace + void initialize_connman() { static const auto testing_setup = MakeNoLogFileContext<>(); + g_setup = testing_setup.get(); } FUZZ_TARGET_INIT(connman, initialize_connman) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; SetMockTime(ConsumeTime(fuzzed_data_provider)); - AddrMan addrman(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); + AddrMan addrman(/*asmap=*/std::vector<bool>(), + /*deterministic=*/false, + g_setup->m_node.args->GetIntArg("-checkaddrman", 0)); CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman, fuzzed_data_provider.ConsumeBool()}; CNetAddr random_netaddr; CNode random_node = ConsumeNode(fuzzed_data_provider); @@ -90,12 +98,6 @@ FUZZ_TARGET_INIT(connman, initialize_connman) (void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool()); }, [&] { - // Limit now to int32_t to avoid signed integer overflow - (void)connman.PoissonNextSendInbound( - std::chrono::microseconds{fuzzed_data_provider.ConsumeIntegral<int32_t>()}, - std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<int>()}); - }, - [&] { CSerializedNetMsg serialized_net_msg; serialized_net_msg.m_type = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::COMMAND_SIZE); serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider); diff --git a/src/test/fuzz/crypto_aes256.cpp b/src/test/fuzz/crypto_aes256.cpp index 0937026fdd..c5dd79a61e 100644 --- a/src/test/fuzz/crypto_aes256.cpp +++ b/src/test/fuzz/crypto_aes256.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/crypto_aes256cbc.cpp b/src/test/fuzz/crypto_aes256cbc.cpp index 5fe67bd4da..72bf962fee 100644 --- a/src/test/fuzz/crypto_aes256cbc.cpp +++ b/src/test/fuzz/crypto_aes256cbc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp index 5e60b0f25b..596614a71b 100644 --- a/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp +++ b/src/test/fuzz/crypto_chacha20_poly1305_aead.cpp @@ -7,6 +7,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <util/overflow.h> #include <cassert> #include <cstdint> diff --git a/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp b/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp index 24bcc03dfd..af6d108c07 100644 --- a/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp +++ b/src/test/fuzz/crypto_hkdf_hmac_sha256_l32.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/cuckoocache.cpp b/src/test/fuzz/cuckoocache.cpp index 019afe1c47..50a71ee03f 100644 --- a/src/test/fuzz/cuckoocache.cpp +++ b/src/test/fuzz/cuckoocache.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp index ffe4855662..f5f86a574a 100644 --- a/src/test/fuzz/descriptor_parse.cpp +++ b/src/test/fuzz/descriptor_parse.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index 48574d71cc..ed6f172a2a 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -22,7 +22,9 @@ #include <pubkey.h> #include <script/keyorigin.h> #include <streams.h> +#include <test/util/setup_common.h> #include <undo.h> +#include <util/system.h> #include <version.h> #include <exception> @@ -33,8 +35,17 @@ #include <test/fuzz/fuzz.h> +using node::SnapshotMetadata; + +namespace { +const BasicTestingSetup* g_setup; +} // namespace + void initialize_deserialize() { + static const auto testing_setup = MakeNoLogFileContext<>(); + g_setup = testing_setup.get(); + // Fuzzers using pubkey must hold an ECCVerifyHandle. static const ECCVerifyHandle verify_handle; } @@ -189,7 +200,9 @@ FUZZ_TARGET_DESERIALIZE(blockmerkleroot, { BlockMerkleRoot(block, &mutated); }) FUZZ_TARGET_DESERIALIZE(addrman_deserialize, { - AddrMan am(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); + AddrMan am(/*asmap=*/std::vector<bool>(), + /*deterministic=*/false, + g_setup->m_node.args->GetIntArg("-checkaddrman", 0)); DeserializeFromFuzzingInput(buffer, am); }) FUZZ_TARGET_DESERIALIZE(blockheader_deserialize, { diff --git a/src/test/fuzz/eval_script.cpp b/src/test/fuzz/eval_script.cpp index 77ed798923..e7c49c2dbc 100644 --- a/src/test/fuzz/eval_script.cpp +++ b/src/test/fuzz/eval_script.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/test/fuzz/fee_rate.cpp b/src/test/fuzz/fee_rate.cpp index a852f8fb60..92616b62be 100644 --- a/src/test/fuzz/fee_rate.cpp +++ b/src/test/fuzz/fee_rate.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/fees.cpp b/src/test/fuzz/fees.cpp index bcab66842c..deb0ed65ca 100644 --- a/src/test/fuzz/fees.cpp +++ b/src/test/fuzz/fees.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/float.cpp b/src/test/fuzz/float.cpp index 2f77c8949e..8714ab8a04 100644 --- a/src/test/fuzz/float.cpp +++ b/src/test/fuzz/float.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index a33297e0ed..a490bbfa1d 100644 --- a/src/test/fuzz/fuzz.cpp +++ b/src/test/fuzz/fuzz.cpp @@ -4,6 +4,7 @@ #include <test/fuzz/fuzz.h> +#include <fs.h> #include <netaddress.h> #include <netbase.h> #include <test/util/setup_common.h> @@ -12,13 +13,40 @@ #include <cstdint> #include <exception> +#include <fstream> +#include <functional> +#include <map> #include <memory> #include <string> +#include <tuple> #include <unistd.h> #include <vector> const std::function<void(const std::string&)> G_TEST_LOG_FUN{}; +/** + * A copy of the command line arguments that start with `--`. + * First `LLVMFuzzerInitialize()` is called, which saves the arguments to `g_args`. + * Later, depending on the fuzz test, `G_TEST_COMMAND_LINE_ARGUMENTS()` may be + * called by `BasicTestingSetup` constructor to fetch those arguments and store + * them in `BasicTestingSetup::m_node::args`. + */ +static std::vector<const char*> g_args; + +static void SetArgs(int argc, char** argv) { + for (int i = 1; i < argc; ++i) { + // Only take into account arguments that start with `--`. The others are for the fuzz engine: + // `fuzz -runs=1 fuzz_seed_corpus/address_deserialize_v2 --checkaddrman=5` + if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == '-') { + g_args.push_back(argv[i]); + } + } +} + +const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS = []() { + return g_args; +}; + std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>>& FuzzTargets() { static std::map<std::string_view, std::tuple<TypeTestOneInput, TypeInitialize, TypeHidden>> g_fuzz_targets; @@ -56,7 +84,7 @@ void initialize() } if (const char* out_path = std::getenv("WRITE_ALL_FUZZ_TARGETS_AND_ABORT")) { std::cout << "Writing all fuzz target names to '" << out_path << "'." << std::endl; - std::ofstream out_stream(out_path, std::ios::binary); + std::ofstream out_stream{out_path, std::ios::binary}; for (const auto& t : FuzzTargets()) { if (std::get<2>(t.second)) continue; out_stream << t.first << std::endl; @@ -95,6 +123,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) // This function is used by libFuzzer extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + SetArgs(*argc, *argv); initialize(); return 0; } diff --git a/src/test/fuzz/golomb_rice.cpp b/src/test/fuzz/golomb_rice.cpp index 746347ac95..b4bb4c6dc6 100644 --- a/src/test/fuzz/golomb_rice.cpp +++ b/src/test/fuzz/golomb_rice.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -19,27 +19,13 @@ #include <vector> namespace { -uint64_t MapIntoRange(const uint64_t x, const uint64_t n) -{ - const uint64_t x_hi = x >> 32; - const uint64_t x_lo = x & 0xFFFFFFFF; - const uint64_t n_hi = n >> 32; - const uint64_t n_lo = n & 0xFFFFFFFF; - const uint64_t ac = x_hi * n_hi; - const uint64_t ad = x_hi * n_lo; - const uint64_t bc = x_lo * n_hi; - const uint64_t bd = x_lo * n_lo; - const uint64_t mid34 = (bd >> 32) + (bc & 0xFFFFFFFF) + (ad & 0xFFFFFFFF); - const uint64_t upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32); - return upper64; -} uint64_t HashToRange(const std::vector<uint8_t>& element, const uint64_t f) { const uint64_t hash = CSipHasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL) .Write(element.data(), element.size()) .Finalize(); - return MapIntoRange(hash, f); + return FastRange64(hash, f); } std::vector<uint64_t> BuildHashedSet(const std::unordered_set<std::vector<uint8_t>, ByteVectorHash>& elements, const uint64_t f) diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index ce424c443e..72574612a2 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -26,6 +26,7 @@ #include <univalue.h> #include <util/check.h> #include <util/moneystr.h> +#include <util/overflow.h> #include <util/strencodings.h> #include <util/string.h> #include <util/system.h> @@ -205,11 +206,6 @@ FUZZ_TARGET_INIT(integer, initialize_integer) stream >> deserialized_i8; assert(i8 == deserialized_i8 && stream.empty()); - char deserialized_ch; - stream << ch; - stream >> deserialized_ch; - assert(ch == deserialized_ch && stream.empty()); - bool deserialized_b; stream << b; stream >> deserialized_b; diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp index 32077b1fe2..bfea9778f4 100644 --- a/src/test/fuzz/key.cpp +++ b/src/test/fuzz/key.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/key_io.cpp b/src/test/fuzz/key_io.cpp index f58bf8b316..32a81c2e17 100644 --- a/src/test/fuzz/key_io.cpp +++ b/src/test/fuzz/key_io.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/locale.cpp b/src/test/fuzz/locale.cpp index 4ad8123554..0f2985b504 100644 --- a/src/test/fuzz/locale.cpp +++ b/src/test/fuzz/locale.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/minisketch.cpp b/src/test/fuzz/minisketch.cpp index 93954bd3cf..a17be73f6c 100644 --- a/src/test/fuzz/minisketch.cpp +++ b/src/test/fuzz/minisketch.cpp @@ -12,6 +12,8 @@ #include <map> #include <numeric> +using node::MakeMinisketch32; + FUZZ_TARGET(minisketch) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; diff --git a/src/test/fuzz/multiplication_overflow.cpp b/src/test/fuzz/multiplication_overflow.cpp index c7251650c2..fbe4d061bf 100644 --- a/src/test/fuzz/multiplication_overflow.cpp +++ b/src/test/fuzz/multiplication_overflow.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/net_permissions.cpp b/src/test/fuzz/net_permissions.cpp index 6ea79464d0..e62fe0328e 100644 --- a/src/test/fuzz/net_permissions.cpp +++ b/src/test/fuzz/net_permissions.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/node_eviction.cpp b/src/test/fuzz/node_eviction.cpp index bb0515cfab..2e90085744 100644 --- a/src/test/fuzz/node_eviction.cpp +++ b/src/test/fuzz/node_eviction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/p2p_transport_serialization.cpp b/src/test/fuzz/p2p_transport_serialization.cpp index 29b7223c90..88c22ca305 100644 --- a/src/test/fuzz/p2p_transport_serialization.cpp +++ b/src/test/fuzz/p2p_transport_serialization.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -70,13 +70,13 @@ FUZZ_TARGET_INIT(p2p_transport_serialization, initialize_p2p_transport_serializa const std::chrono::microseconds m_time{std::numeric_limits<int64_t>::max()}; bool reject_message{false}; CNetMessage msg = deserializer.GetMessage(m_time, reject_message); - assert(msg.m_command.size() <= CMessageHeader::COMMAND_SIZE); + assert(msg.m_type.size() <= CMessageHeader::COMMAND_SIZE); assert(msg.m_raw_message_size <= mutable_msg_bytes.size()); assert(msg.m_raw_message_size == CMessageHeader::HEADER_SIZE + msg.m_message_size); assert(msg.m_time == m_time); std::vector<unsigned char> header; - auto msg2 = CNetMsgMaker{msg.m_recv.GetVersion()}.Make(msg.m_command, MakeUCharSpan(msg.m_recv)); + auto msg2 = CNetMsgMaker{msg.m_recv.GetVersion()}.Make(msg.m_type, MakeUCharSpan(msg.m_recv)); serializer.prepareForTransport(msg2, header); } } diff --git a/src/test/fuzz/parse_iso8601.cpp b/src/test/fuzz/parse_iso8601.cpp index 3c56fa49ee..0fef9a9a1d 100644 --- a/src/test/fuzz/parse_iso8601.cpp +++ b/src/test/fuzz/parse_iso8601.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/test/fuzz/parse_numbers.cpp b/src/test/fuzz/parse_numbers.cpp index 85fee062f0..2cd3146679 100644 --- a/src/test/fuzz/parse_numbers.cpp +++ b/src/test/fuzz/parse_numbers.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp index 3fffaac8d0..c7a76aa52f 100644 --- a/src/test/fuzz/parse_univalue.cpp +++ b/src/test/fuzz/parse_univalue.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/test/fuzz/pow.cpp b/src/test/fuzz/pow.cpp index 1123c8c170..0004d82d66 100644 --- a/src/test/fuzz/pow.cpp +++ b/src/test/fuzz/pow.cpp @@ -9,6 +9,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <util/overflow.h> #include <cstdint> #include <optional> diff --git a/src/test/fuzz/prevector.cpp b/src/test/fuzz/prevector.cpp index d4b3ed501f..a48bab1ee2 100644 --- a/src/test/fuzz/prevector.cpp +++ b/src/test/fuzz/prevector.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. diff --git a/src/test/fuzz/psbt.cpp b/src/test/fuzz/psbt.cpp index 6c62dd6e48..669688a80d 100644 --- a/src/test/fuzz/psbt.cpp +++ b/src/test/fuzz/psbt.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -18,6 +18,10 @@ #include <string> #include <vector> +using node::AnalyzePSBT; +using node::PSBTAnalysis; +using node::PSBTInputAnalysis; + void initialize_psbt() { static const ECCVerifyHandle verify_handle; diff --git a/src/test/fuzz/rbf.cpp b/src/test/fuzz/rbf.cpp index 990bce5f6c..8dcaa609b5 100644 --- a/src/test/fuzz/rbf.cpp +++ b/src/test/fuzz/rbf.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/rpc.cpp b/src/test/fuzz/rpc.cpp index b6ecf1c492..03a84b697d 100644 --- a/src/test/fuzz/rpc.cpp +++ b/src/test/fuzz/rpc.cpp @@ -120,6 +120,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{ "getchaintips", "getchaintxstats", "getconnectioncount", + "getdeploymentinfo", "getdescriptorinfo", "getdifficulty", "getindexinfo", @@ -271,7 +272,7 @@ std::string ConsumeScalarRPCArgument(FuzzedDataProvider& fuzzed_data_provider) } CDataStream data_stream{SER_NETWORK, PROTOCOL_VERSION}; data_stream << *opt_psbt; - r = EncodeBase64({data_stream.begin(), data_stream.end()}); + r = EncodeBase64(data_stream); }, [&] { // base58 encoded key diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index eb170aab76..14a59912db 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -102,17 +102,6 @@ FUZZ_TARGET_INIT(script, initialize_script) (void)script.IsPushOnly(); (void)script.GetSigOpCount(/* fAccurate= */ false); - (void)FormatScript(script); - (void)ScriptToAsmStr(script, false); - (void)ScriptToAsmStr(script, true); - - UniValue o1(UniValue::VOBJ); - ScriptPubKeyToUniv(script, o1, true); - UniValue o2(UniValue::VOBJ); - ScriptPubKeyToUniv(script, o2, false); - UniValue o3(UniValue::VOBJ); - ScriptToUniv(script, o3); - { const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); CompressedScript compressed_script; @@ -178,4 +167,12 @@ FUZZ_TARGET_INIT(script, initialize_script) Assert(dest == GetScriptForDestination(tx_destination_2)); } } + + (void)FormatScript(script); + (void)ScriptToAsmStr(script, /*fAttemptSighashDecode=*/fuzzed_data_provider.ConsumeBool()); + + UniValue o1(UniValue::VOBJ); + ScriptPubKeyToUniv(script, o1, /*include_hex=*/fuzzed_data_provider.ConsumeBool()); + UniValue o3(UniValue::VOBJ); + ScriptToUniv(script, o3); } diff --git a/src/test/fuzz/script_descriptor_cache.cpp b/src/test/fuzz/script_descriptor_cache.cpp index a90ad5e8ed..ceb5cfe17e 100644 --- a/src/test/fuzz/script_descriptor_cache.cpp +++ b/src/test/fuzz/script_descriptor_cache.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp index 43927772ae..8dc99ee069 100644 --- a/src/test/fuzz/script_flags.cpp +++ b/src/test/fuzz/script_flags.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/test/fuzz/script_sign.cpp b/src/test/fuzz/script_sign.cpp index 1a42179724..1446eafe92 100644 --- a/src/test/fuzz/script_sign.cpp +++ b/src/test/fuzz/script_sign.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/signature_checker.cpp b/src/test/fuzz/signature_checker.cpp index c3f416632d..f6c591aca4 100644 --- a/src/test/fuzz/signature_checker.cpp +++ b/src/test/fuzz/signature_checker.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -34,7 +34,7 @@ public: return m_fuzzed_data_provider.ConsumeBool(); } - bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override + bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override { return m_fuzzed_data_provider.ConsumeBool(); } diff --git a/src/test/fuzz/string.cpp b/src/test/fuzz/string.cpp index ab646c68fc..ca57af25c4 100644 --- a/src/test/fuzz/string.cpp +++ b/src/test/fuzz/string.cpp @@ -145,7 +145,8 @@ FUZZ_TARGET(string) (void)CopyrightHolders(random_string_1); FeeEstimateMode fee_estimate_mode; (void)FeeModeFromString(random_string_1, fee_estimate_mode); - (void)FormatParagraph(random_string_1, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 1000), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 1000)); + const auto width{fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 1000)}; + (void)FormatParagraph(random_string_1, width, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, width)); (void)FormatSubVersion(random_string_1, fuzzed_data_provider.ConsumeIntegral<int>(), random_string_vector); (void)GetDescriptorChecksum(random_string_1); (void)HelpExampleCli(random_string_1, random_string_2); @@ -276,20 +277,14 @@ FUZZ_TARGET(string) } { - const int atoi_result = atoi(random_string_1.c_str()); const int locale_independent_atoi_result = LocaleIndependentAtoi<int>(random_string_1); const int64_t atoi64_result = atoi64_legacy(random_string_1); - const bool out_of_range = atoi64_result < std::numeric_limits<int>::min() || atoi64_result > std::numeric_limits<int>::max(); - if (out_of_range) { - assert(locale_independent_atoi_result == 0); - } else { - assert(atoi_result == locale_independent_atoi_result); - } + assert(locale_independent_atoi_result == std::clamp<int64_t>(atoi64_result, std::numeric_limits<int>::min(), std::numeric_limits<int>::max())); } { const int64_t atoi64_result = atoi64_legacy(random_string_1); const int64_t locale_independent_atoi_result = LocaleIndependentAtoi<int64_t>(random_string_1); - assert(atoi64_result == locale_independent_atoi_result || locale_independent_atoi_result == 0); + assert(atoi64_result == locale_independent_atoi_result); } } diff --git a/src/test/fuzz/timedata.cpp b/src/test/fuzz/timedata.cpp index f7dc5f433e..f5d005296b 100644 --- a/src/test/fuzz/timedata.cpp +++ b/src/test/fuzz/timedata.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index 389da6f5d7..6dd8a36692 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index fe1b9c7c0c..df5b271d06 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -14,6 +14,8 @@ #include <validation.h> #include <validationinterface.h> +using node::BlockAssembler; + namespace { const TestingSetup* g_setup; diff --git a/src/test/fuzz/txrequest.cpp b/src/test/fuzz/txrequest.cpp index a73bbcfc25..74d20f86e0 100644 --- a/src/test/fuzz/txrequest.cpp +++ b/src/test/fuzz/txrequest.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index 843b29b911..2514636d6e 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -8,10 +8,13 @@ #include <pubkey.h> #include <test/fuzz/util.h> #include <test/util/script.h> +#include <util/overflow.h> #include <util/rbf.h> #include <util/time.h> #include <version.h> +#include <memory> + FuzzedSock::FuzzedSock(FuzzedDataProvider& fuzzed_data_provider) : m_fuzzed_data_provider{fuzzed_data_provider} { @@ -157,6 +160,20 @@ int FuzzedSock::Connect(const sockaddr*, socklen_t) const return 0; } +std::unique_ptr<Sock> FuzzedSock::Accept(sockaddr* addr, socklen_t* addr_len) const +{ + constexpr std::array accept_errnos{ + ECONNABORTED, + EINTR, + ENOMEM, + }; + if (m_fuzzed_data_provider.ConsumeBool()) { + SetFuzzedErrNo(m_fuzzed_data_provider, accept_errnos); + return std::unique_ptr<FuzzedSock>(); + } + return std::make_unique<FuzzedSock>(m_fuzzed_data_provider); +} + int FuzzedSock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const { constexpr std::array getsockopt_errnos{ @@ -264,8 +281,8 @@ CAmount ConsumeMoney(FuzzedDataProvider& fuzzed_data_provider, const std::option int64_t ConsumeTime(FuzzedDataProvider& fuzzed_data_provider, const std::optional<int64_t>& min, const std::optional<int64_t>& max) noexcept { // Avoid t=0 (1970-01-01T00:00:00Z) since SetMockTime(0) disables mocktime. - static const int64_t time_min = ParseISO8601DateTime("1970-01-01T00:00:01Z"); - static const int64_t time_max = ParseISO8601DateTime("9999-12-31T23:59:59Z"); + static const int64_t time_min{ParseISO8601DateTime("2000-01-01T00:00:01Z")}; + static const int64_t time_max{ParseISO8601DateTime("2100-12-31T23:59:59Z")}; return fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(min.value_or(time_min), max.value_or(time_max)); } @@ -391,7 +408,7 @@ uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept return fuzzed_data_provider.ConsumeBool() ? fuzzed_data_provider.PickValueInArray({ CTxIn::SEQUENCE_FINAL, - CTxIn::SEQUENCE_FINAL - 1, + CTxIn::MAX_SEQUENCE_NONFINAL, MAX_BIP125_RBF_SEQUENCE, }) : fuzzed_data_provider.ConsumeIntegral<uint32_t>(); diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 7937315822..6c91844633 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -38,6 +38,46 @@ class PeerManager; +class FuzzedSock : public Sock +{ + FuzzedDataProvider& m_fuzzed_data_provider; + + /** + * Data to return when `MSG_PEEK` is used as a `Recv()` flag. + * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next + * `Recv()` call we must return the same data, thus we remember it here. + */ + mutable std::optional<uint8_t> m_peek_data; + +public: + explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider); + + ~FuzzedSock() override; + + FuzzedSock& operator=(Sock&& other) override; + + void Reset() override; + + ssize_t Send(const void* data, size_t len, int flags) const override; + + ssize_t Recv(void* buf, size_t len, int flags) const override; + + int Connect(const sockaddr*, socklen_t) const override; + + std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override; + + int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override; + + bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override; + + bool IsConnected(std::string& errmsg) const override; +}; + +[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider) +{ + return FuzzedSock{fuzzed_data_provider}; +} + template <typename... Callables> size_t CallOneOf(FuzzedDataProvider& fuzzed_data_provider, Callables... callables) { @@ -193,17 +233,6 @@ template <typename T> } } -template <class T> -[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept -{ - static_assert(std::is_integral<T>::value, "Integral required."); - if (std::numeric_limits<T>::is_signed) { - return (i > 0 && j > std::numeric_limits<T>::max() - i) || - (i < 0 && j < std::numeric_limits<T>::min() - i); - } - return std::numeric_limits<T>::max() - i < j; -} - [[nodiscard]] bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) noexcept; /** @@ -261,7 +290,7 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N { 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 SOCKET socket = INVALID_SOCKET; + 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>(); const uint64_t local_host_nonce = fuzzed_data_provider.ConsumeIntegral<uint64_t>(); @@ -270,9 +299,27 @@ auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<N const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES); 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, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion); + return std::make_unique<CNode>(node_id, + local_services, + sock, + address, + keyed_net_group, + local_host_nonce, + addr_bind, + addr_name, + conn_type, + inbound_onion); } else { - return CNode{node_id, local_services, socket, address, keyed_net_group, local_host_nonce, addr_bind, addr_name, conn_type, inbound_onion}; + return CNode{node_id, + local_services, + sock, + address, + keyed_net_group, + local_host_nonce, + addr_bind, + addr_name, + conn_type, + inbound_onion}; } } inline std::unique_ptr<CNode> ConsumeNodeAsUniquePtr(FuzzedDataProvider& fdp, const std::optional<NodeId>& node_id_in = std::nullopt) { return ConsumeNode<true>(fdp, node_id_in); } @@ -339,7 +386,6 @@ void WriteToStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noe CallOneOf( fuzzed_data_provider, WRITE_TO_STREAM_CASE(bool, fuzzed_data_provider.ConsumeBool()), - WRITE_TO_STREAM_CASE(char, fuzzed_data_provider.ConsumeIntegral<char>()), WRITE_TO_STREAM_CASE(int8_t, fuzzed_data_provider.ConsumeIntegral<int8_t>()), WRITE_TO_STREAM_CASE(uint8_t, fuzzed_data_provider.ConsumeIntegral<uint8_t>()), WRITE_TO_STREAM_CASE(int16_t, fuzzed_data_provider.ConsumeIntegral<int16_t>()), @@ -349,7 +395,7 @@ void WriteToStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) noe WRITE_TO_STREAM_CASE(int64_t, fuzzed_data_provider.ConsumeIntegral<int64_t>()), WRITE_TO_STREAM_CASE(uint64_t, fuzzed_data_provider.ConsumeIntegral<uint64_t>()), WRITE_TO_STREAM_CASE(std::string, fuzzed_data_provider.ConsumeRandomLengthString(32)), - WRITE_TO_STREAM_CASE(std::vector<char>, ConsumeRandomLengthIntegralVector<char>(fuzzed_data_provider))); + WRITE_TO_STREAM_CASE(std::vector<uint8_t>, ConsumeRandomLengthIntegralVector<uint8_t>(fuzzed_data_provider))); } catch (const std::ios_base::failure&) { break; } @@ -369,7 +415,6 @@ void ReadFromStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) no CallOneOf( fuzzed_data_provider, READ_FROM_STREAM_CASE(bool), - READ_FROM_STREAM_CASE(char), READ_FROM_STREAM_CASE(int8_t), READ_FROM_STREAM_CASE(uint8_t), READ_FROM_STREAM_CASE(int16_t), @@ -379,49 +424,11 @@ void ReadFromStream(FuzzedDataProvider& fuzzed_data_provider, Stream& stream) no READ_FROM_STREAM_CASE(int64_t), READ_FROM_STREAM_CASE(uint64_t), READ_FROM_STREAM_CASE(std::string), - READ_FROM_STREAM_CASE(std::vector<char>)); + READ_FROM_STREAM_CASE(std::vector<uint8_t>)); } catch (const std::ios_base::failure&) { break; } } } -class FuzzedSock : public Sock -{ - FuzzedDataProvider& m_fuzzed_data_provider; - - /** - * Data to return when `MSG_PEEK` is used as a `Recv()` flag. - * If `MSG_PEEK` is used, then our `Recv()` returns some random data as usual, but on the next - * `Recv()` call we must return the same data, thus we remember it here. - */ - mutable std::optional<uint8_t> m_peek_data; - -public: - explicit FuzzedSock(FuzzedDataProvider& fuzzed_data_provider); - - ~FuzzedSock() override; - - FuzzedSock& operator=(Sock&& other) override; - - void Reset() override; - - ssize_t Send(const void* data, size_t len, int flags) const override; - - ssize_t Recv(void* buf, size_t len, int flags) const override; - - int Connect(const sockaddr*, socklen_t) const override; - - int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override; - - bool Wait(std::chrono::milliseconds timeout, Event requested, Event* occurred = nullptr) const override; - - bool IsConnected(std::string& errmsg) const override; -}; - -[[nodiscard]] inline FuzzedSock ConsumeSock(FuzzedDataProvider& fuzzed_data_provider) -{ - return FuzzedSock{fuzzed_data_provider}; -} - #endif // BITCOIN_TEST_FUZZ_UTIL_H diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index 1b9f0c8a02..e513f1883c 100644 --- a/src/test/fuzz/utxo_snapshot.cpp +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -4,6 +4,7 @@ #include <chainparams.h> #include <consensus/validation.h> +#include <fs.h> #include <node/utxo_snapshot.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> @@ -13,6 +14,8 @@ #include <validation.h> #include <validationinterface.h> +using node::SnapshotMetadata; + namespace { const std::vector<std::shared_ptr<CBlock>>* g_chain; diff --git a/src/test/fuzz/versionbits.cpp b/src/test/fuzz/versionbits.cpp index cf95c0b9bf..95eb71099d 100644 --- a/src/test/fuzz/versionbits.cpp +++ b/src/test/fuzz/versionbits.cpp @@ -51,7 +51,7 @@ public: ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, dummy_params, m_cache); } int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, dummy_params, m_cache); } - BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateStatisticsFor(pindexPrev, dummy_params); } + BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindex, std::vector<bool>* signals=nullptr) const { return AbstractThresholdConditionChecker::GetStateStatisticsFor(pindex, dummy_params, signals); } bool Condition(int32_t version) const { @@ -220,7 +220,14 @@ FUZZ_TARGET_INIT(versionbits, initialize) CBlockIndex* prev = blocks.tip(); const int exp_since = checker.GetStateSinceHeightFor(prev); const ThresholdState exp_state = checker.GetStateFor(prev); - BIP9Stats last_stats = checker.GetStateStatisticsFor(prev); + + // get statistics from end of previous period, then reset + BIP9Stats last_stats; + last_stats.period = period; + last_stats.threshold = threshold; + last_stats.count = last_stats.elapsed = 0; + last_stats.possible = (period >= threshold); + std::vector<bool> last_signals{}; int prev_next_height = (prev == nullptr ? 0 : prev->nHeight + 1); assert(exp_since <= prev_next_height); @@ -241,17 +248,25 @@ FUZZ_TARGET_INIT(versionbits, initialize) assert(state == exp_state); assert(since == exp_since); - // GetStateStatistics may crash when state is not STARTED - if (state != ThresholdState::STARTED) continue; - // check that after mining this block stats change as expected - const BIP9Stats stats = checker.GetStateStatisticsFor(current_block); + std::vector<bool> signals; + const BIP9Stats stats = checker.GetStateStatisticsFor(current_block, &signals); + const BIP9Stats stats_no_signals = checker.GetStateStatisticsFor(current_block); + assert(stats.period == stats_no_signals.period && stats.threshold == stats_no_signals.threshold + && stats.elapsed == stats_no_signals.elapsed && stats.count == stats_no_signals.count + && stats.possible == stats_no_signals.possible); + assert(stats.period == period); assert(stats.threshold == threshold); assert(stats.elapsed == b); assert(stats.count == last_stats.count + (signal ? 1 : 0)); assert(stats.possible == (stats.count + period >= stats.elapsed + threshold)); last_stats = stats; + + assert(signals.size() == last_signals.size() + 1); + assert(signals.back() == signal); + last_signals.push_back(signal); + assert(signals == last_signals); } if (exp_state == ThresholdState::STARTED) { @@ -265,14 +280,12 @@ FUZZ_TARGET_INIT(versionbits, initialize) CBlockIndex* current_block = blocks.mine_block(signal); assert(checker.Condition(current_block) == signal); - // GetStateStatistics is safe on a period boundary - // and has progressed to a new period const BIP9Stats stats = checker.GetStateStatisticsFor(current_block); assert(stats.period == period); assert(stats.threshold == threshold); - assert(stats.elapsed == 0); - assert(stats.count == 0); - assert(stats.possible == true); + assert(stats.elapsed == period); + assert(stats.count == blocks_sig); + assert(stats.possible == (stats.count + period >= stats.elapsed + threshold)); // More interesting is whether the state changed. const ThresholdState state = checker.GetStateFor(current_block); diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index b0c8068ab9..597d774673 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -6,6 +6,7 @@ #include <util/strencodings.h> #include <util/system.h> +#include <limits> #include <string> #include <utility> #include <vector> @@ -144,6 +145,11 @@ BOOST_AUTO_TEST_CASE(intarg) BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 11), 0); BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 0); + // Check under-/overflow behavior. + ResetArgs("-foo=-9223372036854775809 -bar=9223372036854775808"); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 0), std::numeric_limits<int64_t>::min()); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 0), std::numeric_limits<int64_t>::max()); + ResetArgs("-foo=11 -bar=12"); BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 0), 11); BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 12); @@ -153,6 +159,98 @@ BOOST_AUTO_TEST_CASE(intarg) BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 0); } +BOOST_AUTO_TEST_CASE(patharg) +{ + const auto dir = std::make_pair("-dir", ArgsManager::ALLOW_ANY); + SetupArgs({dir}); + ResetArgs(""); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), fs::path{}); + + const fs::path root_path{"/"}; + ResetArgs("-dir=/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + + ResetArgs("-dir=/."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + + ResetArgs("-dir=/./"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + + ResetArgs("-dir=/.//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + +#ifdef WIN32 + const fs::path win_root_path{"C:\\"}; + ResetArgs("-dir=C:\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\.\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\.\\\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); +#endif + + const fs::path absolute_path{"/home/user/.bitcoin"}; + ResetArgs("-dir=/home/user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/root/../home/user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/./user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/./"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/.//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + const fs::path relative_path{"user/.bitcoin"}; + ResetArgs("-dir=user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=somewhere/../user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/./.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/./"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/.//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); +} + BOOST_AUTO_TEST_CASE(doubledash) { const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY); diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 677bf39fd9..5b5158884a 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2020 The Bitcoin Core developers +// Copyright (c) 2013-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. diff --git a/src/test/interfaces_tests.cpp b/src/test/interfaces_tests.cpp index 44779f7d7c..49b7d2003b 100644 --- a/src/test/interfaces_tests.cpp +++ b/src/test/interfaces_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -123,6 +123,7 @@ BOOST_AUTO_TEST_CASE(findCommonAncestor) BOOST_AUTO_TEST_CASE(hasBlocks) { + LOCK(::cs_main); auto& chain = m_node.chain; const CChain& active = Assert(m_node.chainman)->ActiveChain(); diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp index 02268dbcf5..b06157e99f 100644 --- a/src/test/key_io_tests.cpp +++ b/src/test/key_io_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 2769dde367..61d334ab18 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/logging_tests.cpp b/src/test/logging_tests.cpp index 84ddbc50c6..cbfb6c67c3 100644 --- a/src/test/logging_tests.cpp +++ b/src/test/logging_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/test/main.cpp b/src/test/main.cpp index 5885564074..73bb331e21 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -3,14 +3,15 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. /** - * See https://www.boost.org/doc/libs/1_71_0/libs/test/doc/html/boost_test/utf_reference/link_references/link_boost_test_module_macro.html + * See https://www.boost.org/doc/libs/1_78_0/libs/test/doc/html/boost_test/adv_scenarios/single_header_customizations/multiple_translation_units.html */ #define BOOST_TEST_MODULE Bitcoin Core Test Suite -#include <boost/test/unit_test.hpp> +#include <boost/test/included/unit_test.hpp> #include <test/util/setup_common.h> +#include <functional> #include <iostream> /** Redirect debug log to unit_test.log files */ @@ -24,3 +25,17 @@ const std::function<void(const std::string&)> G_TEST_LOG_FUN = [](const std::str if (!should_log) return; std::cout << s; }; + +/** + * Retrieve the command line arguments from boost. + * Allows usage like: + * `test_bitcoin --run_test="net_tests/cnode_listen_port" -- -checkaddrman=1 -printtoconsole=1` + * which would return `["-checkaddrman=1", "-printtoconsole=1"]`. + */ +const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS = []() { + std::vector<const char*> args; + for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i) { + args.push_back(boost::unit_test::framework::master_test_suite().argv[i]); + } + return args; +}; diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index 005752d508..d6f24210eb 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/test/merkleblock_tests.cpp b/src/test/merkleblock_tests.cpp index e540b59b35..c7ec5fec15 100644 --- a/src/test/merkleblock_tests.cpp +++ b/src/test/merkleblock_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index bdc6ff6130..c453dae701 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -24,6 +24,9 @@ #include <boost/test/unit_test.hpp> +using node::BlockAssembler; +using node::CBlockTemplate; + namespace miner_tests { struct MinerTestingSetup : public TestingSetup { void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs); @@ -456,7 +459,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // absolute height locked tx.vin[0].prevout.hash = txFirst[2]->GetHash(); - tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1; + tx.vin[0].nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; prevheights[0] = baseheight + 3; tx.nLockTime = m_node.chainman->ActiveChain().Tip()->nHeight + 1; hash = tx.GetHash(); diff --git a/src/test/minisketch_tests.cpp b/src/test/minisketch_tests.cpp index f7dd18923b..9c53ace633 100644 --- a/src/test/minisketch_tests.cpp +++ b/src/test/minisketch_tests.cpp @@ -11,6 +11,8 @@ #include <utility> +using node::MakeMinisketch32; + BOOST_AUTO_TEST_SUITE(minisketch_tests) BOOST_AUTO_TEST_CASE(minisketch_test) diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 39f9b7ee28..dccc7ce795 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index d0f0e7d50f..908b030eea 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -43,7 +43,6 @@ BOOST_AUTO_TEST_CASE(cnode_listen_port) BOOST_AUTO_TEST_CASE(cnode_simple_test) { - SOCKET hSocket = INVALID_SOCKET; NodeId id = 0; in_addr ipv4Addr; @@ -52,12 +51,16 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK); std::string pszDest; - std::unique_ptr<CNode> pnode1 = std::make_unique<CNode>( - id++, NODE_NETWORK, hSocket, addr, - /* nKeyedNetGroupIn = */ 0, - /* nLocalHostNonceIn = */ 0, - CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY, - /* inbound_onion = */ false); + std::unique_ptr<CNode> pnode1 = std::make_unique<CNode>(id++, + NODE_NETWORK, + /*sock=*/nullptr, + addr, + /*nKeyedNetGroupIn=*/0, + /*nLocalHostNonceIn=*/0, + CAddress(), + pszDest, + ConnectionType::OUTBOUND_FULL_RELAY, + /*inbound_onion=*/false); BOOST_CHECK(pnode1->IsFullOutboundConn() == true); BOOST_CHECK(pnode1->IsManualConn() == false); BOOST_CHECK(pnode1->IsBlockOnlyConn() == false); @@ -67,12 +70,16 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) BOOST_CHECK(pnode1->m_inbound_onion == false); BOOST_CHECK_EQUAL(pnode1->ConnectedThroughNetwork(), Network::NET_IPV4); - std::unique_ptr<CNode> pnode2 = std::make_unique<CNode>( - id++, NODE_NETWORK, hSocket, addr, - /* nKeyedNetGroupIn = */ 1, - /* nLocalHostNonceIn = */ 1, - CAddress(), pszDest, ConnectionType::INBOUND, - /* inbound_onion = */ false); + std::unique_ptr<CNode> pnode2 = std::make_unique<CNode>(id++, + NODE_NETWORK, + /*sock=*/nullptr, + addr, + /*nKeyedNetGroupIn=*/1, + /*nLocalHostNonceIn=*/1, + CAddress(), + pszDest, + ConnectionType::INBOUND, + /*inbound_onion=*/false); BOOST_CHECK(pnode2->IsFullOutboundConn() == false); BOOST_CHECK(pnode2->IsManualConn() == false); BOOST_CHECK(pnode2->IsBlockOnlyConn() == false); @@ -82,12 +89,16 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) BOOST_CHECK(pnode2->m_inbound_onion == false); BOOST_CHECK_EQUAL(pnode2->ConnectedThroughNetwork(), Network::NET_IPV4); - std::unique_ptr<CNode> pnode3 = std::make_unique<CNode>( - id++, NODE_NETWORK, hSocket, addr, - /* nKeyedNetGroupIn = */ 0, - /* nLocalHostNonceIn = */ 0, - CAddress(), pszDest, ConnectionType::OUTBOUND_FULL_RELAY, - /* inbound_onion = */ false); + std::unique_ptr<CNode> pnode3 = std::make_unique<CNode>(id++, + NODE_NETWORK, + /*sock=*/nullptr, + addr, + /*nKeyedNetGroupIn=*/0, + /*nLocalHostNonceIn=*/0, + CAddress(), + pszDest, + ConnectionType::OUTBOUND_FULL_RELAY, + /*inbound_onion=*/false); BOOST_CHECK(pnode3->IsFullOutboundConn() == true); BOOST_CHECK(pnode3->IsManualConn() == false); BOOST_CHECK(pnode3->IsBlockOnlyConn() == false); @@ -97,12 +108,16 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) BOOST_CHECK(pnode3->m_inbound_onion == false); BOOST_CHECK_EQUAL(pnode3->ConnectedThroughNetwork(), Network::NET_IPV4); - std::unique_ptr<CNode> pnode4 = std::make_unique<CNode>( - id++, NODE_NETWORK, hSocket, addr, - /* nKeyedNetGroupIn = */ 1, - /* nLocalHostNonceIn = */ 1, - CAddress(), pszDest, ConnectionType::INBOUND, - /* inbound_onion = */ true); + std::unique_ptr<CNode> pnode4 = std::make_unique<CNode>(id++, + NODE_NETWORK, + /*sock=*/nullptr, + addr, + /*nKeyedNetGroupIn=*/1, + /*nLocalHostNonceIn=*/1, + CAddress(), + pszDest, + ConnectionType::INBOUND, + /*inbound_onion=*/true); BOOST_CHECK(pnode4->IsFullOutboundConn() == false); BOOST_CHECK(pnode4->IsManualConn() == false); BOOST_CHECK(pnode4->IsBlockOnlyConn() == false); @@ -593,7 +608,7 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) // that a normal IPv4 address is among the entries, but if this address is // !IsRoutable the undefined behavior is easier to trigger deterministically { - LOCK(cs_mapLocalHost); + LOCK(g_maplocalhost_mutex); in_addr ipv4AddrLocal; ipv4AddrLocal.s_addr = 0x0100007f; CNetAddr addr = CNetAddr(ipv4AddrLocal); @@ -607,7 +622,16 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) in_addr ipv4AddrPeer; ipv4AddrPeer.s_addr = 0xa0b0c001; CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK); - std::unique_ptr<CNode> pnode = std::make_unique<CNode>(0, NODE_NETWORK, INVALID_SOCKET, addr, /*nKeyedNetGroupIn=*/0, /*nLocalHostNonceIn=*/0, CAddress{}, /*pszDest=*/std::string{}, ConnectionType::OUTBOUND_FULL_RELAY, /*inbound_onion=*/false); + std::unique_ptr<CNode> pnode = std::make_unique<CNode>(/*id=*/0, + NODE_NETWORK, + /*sock=*/nullptr, + addr, + /*nKeyedNetGroupIn=*/0, + /*nLocalHostNonceIn=*/0, + CAddress{}, + /*pszDest=*/std::string{}, + ConnectionType::OUTBOUND_FULL_RELAY, + /*inbound_onion=*/false); pnode->fSuccessfullyConnected.store(true); // the peer claims to be reaching us via IPv6 diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index b6d7496cc7..6410ac565a 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/policy_fee_tests.cpp b/src/test/policy_fee_tests.cpp index f9c7d04d6c..25fb5343e3 100644 --- a/src/test/policy_fee_tests.cpp +++ b/src/test/policy_fee_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index d5a4d3fd80..2f43ae52f7 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -73,7 +73,7 @@ BOOST_AUTO_TEST_CASE(CheckProofOfWork_test_overflow_target) { const auto consensus = CreateChainParams(*m_node.args, CBaseChainParams::MAIN)->GetConsensus(); uint256 hash; - unsigned int nBits = ~0x00800000; + unsigned int nBits{~0x00800000U}; hash.SetHex("0x1"); BOOST_CHECK(!CheckProofOfWork(hash, nBits, consensus)); } diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp index 12c5848eaf..89814748fe 100644 --- a/src/test/prevector_tests.cpp +++ b/src/test/prevector_tests.cpp @@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt) prevector_tester<8, int> test; for (int i = 0; i < 2048; i++) { if (InsecureRandBits(2) == 0) { - test.insert(InsecureRandRange(test.size() + 1), InsecureRand32()); + test.insert(InsecureRandRange(test.size() + 1), int(InsecureRand32())); } if (test.size() > 0 && InsecureRandBits(2) == 1) { test.erase(InsecureRandRange(test.size())); @@ -230,7 +230,7 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt) test.resize(new_size); } if (InsecureRandBits(3) == 3) { - test.insert(InsecureRandRange(test.size() + 1), 1 + InsecureRandBool(), InsecureRand32()); + test.insert(InsecureRandRange(test.size() + 1), 1 + InsecureRandBool(), int(InsecureRand32())); } if (InsecureRandBits(3) == 4) { int del = std::min<int>(test.size(), 1 + (InsecureRandBool())); @@ -238,7 +238,7 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt) test.erase(beg, beg + del); } if (InsecureRandBits(4) == 5) { - test.push_back(InsecureRand32()); + test.push_back(int(InsecureRand32())); } if (test.size() > 0 && InsecureRandBits(4) == 6) { test.pop_back(); @@ -247,7 +247,7 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt) int values[4]; int num = 1 + (InsecureRandBits(2)); for (int k = 0; k < num; k++) { - values[k] = InsecureRand32(); + values[k] = int(InsecureRand32()); } test.insert_range(InsecureRandRange(test.size() + 1), values, values + num); } @@ -263,13 +263,13 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt) test.shrink_to_fit(); } if (test.size() > 0) { - test.update(InsecureRandRange(test.size()), InsecureRand32()); + test.update(InsecureRandRange(test.size()), int(InsecureRand32())); } if (InsecureRandBits(10) == 11) { test.clear(); } if (InsecureRandBits(9) == 12) { - test.assign(InsecureRandBits(5), InsecureRand32()); + test.assign(InsecureRandBits(5), int(InsecureRand32())); } if (InsecureRandBits(3) == 3) { test.swap(); @@ -283,8 +283,8 @@ BOOST_AUTO_TEST_CASE(PrevectorTestInt) if (InsecureRandBits(5) == 19) { unsigned int num = 1 + (InsecureRandBits(4)); std::vector<int> values(num); - for (auto &v : values) { - v = InsecureRand32(); + for (int& v : values) { + v = int(InsecureRand32()); } test.resize_uninitialized(values); } diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp index 21576bb868..0a9ff5f294 100644 --- a/src/test/reverselock_tests.cpp +++ b/src/test/reverselock_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 67fbc9f8a2..50b5078110 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/sanity_tests.cpp b/src/test/sanity_tests.cpp index 496292875d..a7057f8361 100644 --- a/src/test/sanity_tests.cpp +++ b/src/test/sanity_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp index fed941247c..4195d413fc 100644 --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/script_p2sh_tests.cpp b/src/test/script_p2sh_tests.cpp index 17b3359624..a221e02d2f 100644 --- a/src/test/script_p2sh_tests.cpp +++ b/src/test/script_p2sh_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 5a5cc6ab29..75bc616cf9 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index f1304dfc82..c453f22594 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -24,7 +24,8 @@ #include <script/bitcoinconsensus.h> #endif -#include <stdint.h> +#include <cstdint> +#include <fstream> #include <string> #include <vector> @@ -155,10 +156,10 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript if (libconsensus_flags == flags) { int expectedSuccessCode = expect ? 1 : 0; if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) { - BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue, stream.data(), stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message); + BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), txCredit.vout[0].nValue, UCharCast(stream.data()), stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message); } else { - BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), 0, stream.data(), stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message); - BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), stream.data(), stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message); + BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(scriptPubKey.data(), scriptPubKey.size(), 0, UCharCast(stream.data()), stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message); + BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), 0, libconsensus_flags, nullptr) == expectedSuccessCode, message); } } #endif @@ -923,7 +924,7 @@ BOOST_AUTO_TEST_CASE(script_build) } #ifdef UPDATE_JSON_TESTS - FILE* file = fopen("script_tests.json.gen", "w"); + FILE* file = fsbridge::fopen("script_tests.json.gen", "w"); fputs(strGen.c_str(), file); fclose(file); #endif @@ -1520,7 +1521,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_returns_true) stream << spendTx; bitcoinconsensus_error err; - int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), stream.data(), stream.size(), nIn, libconsensus_flags, &err); + int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err); BOOST_CHECK_EQUAL(result, 1); BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_OK); } @@ -1543,7 +1544,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_index_err) stream << spendTx; bitcoinconsensus_error err; - int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), stream.data(), stream.size(), nIn, libconsensus_flags, &err); + int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err); BOOST_CHECK_EQUAL(result, 0); BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_TX_INDEX); } @@ -1566,7 +1567,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_size) stream << spendTx; bitcoinconsensus_error err; - int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), stream.data(), stream.size() * 2, nIn, libconsensus_flags, &err); + int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size() * 2, nIn, libconsensus_flags, &err); BOOST_CHECK_EQUAL(result, 0); BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH); } @@ -1589,7 +1590,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_tx_serialization) stream << 0xffffffff; bitcoinconsensus_error err; - int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), stream.data(), stream.size(), nIn, libconsensus_flags, &err); + int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err); BOOST_CHECK_EQUAL(result, 0); BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_TX_DESERIALIZE); } @@ -1612,7 +1613,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_amount_required_err) stream << spendTx; bitcoinconsensus_error err; - int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), stream.data(), stream.size(), nIn, libconsensus_flags, &err); + int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err); BOOST_CHECK_EQUAL(result, 0); BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_AMOUNT_REQUIRED); } @@ -1635,7 +1636,7 @@ BOOST_AUTO_TEST_CASE(bitcoinconsensus_verify_script_invalid_flags) stream << spendTx; bitcoinconsensus_error err; - int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), stream.data(), stream.size(), nIn, libconsensus_flags, &err); + int result = bitcoinconsensus_verify_script(scriptPubKey.data(), scriptPubKey.size(), UCharCast(stream.data()), stream.size(), nIn, libconsensus_flags, &err); BOOST_CHECK_EQUAL(result, 0); BOOST_CHECK_EQUAL(err, bitcoinconsensus_ERR_INVALID_FLAGS); } @@ -1727,7 +1728,7 @@ BOOST_AUTO_TEST_CASE(script_assets_test) bool exists = fs::exists(path); BOOST_WARN_MESSAGE(exists, "File $DIR_UNIT_TEST_DATA/script_assets_test.json not found, skipping script_assets_test"); if (!exists) return; - fs::ifstream file(path); + std::ifstream file{path}; BOOST_CHECK(file.is_open()); file.seekg(0, std::ios::end); size_t length = file.tellg(); diff --git a/src/test/scriptnum10.h b/src/test/scriptnum10.h index 3937366f01..1381d5d431 100644 --- a/src/test/scriptnum10.h +++ b/src/test/scriptnum10.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/test/serfloat_tests.cpp b/src/test/serfloat_tests.cpp index 15612e2950..ed1f081913 100644 --- a/src/test/serfloat_tests.cpp +++ b/src/test/serfloat_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020 The Bitcoin Core developers +// Copyright (c) 2014-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. diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 4b55e3bc26..2441847f99 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -61,7 +61,7 @@ public: BOOST_AUTO_TEST_CASE(sizes) { - BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(char(0), 0)); + BOOST_CHECK_EQUAL(sizeof(unsigned char), GetSerializeSize((unsigned char)0, 0)); BOOST_CHECK_EQUAL(sizeof(int8_t), GetSerializeSize(int8_t(0), 0)); BOOST_CHECK_EQUAL(sizeof(uint8_t), GetSerializeSize(uint8_t(0), 0)); BOOST_CHECK_EQUAL(sizeof(int16_t), GetSerializeSize(int16_t(0), 0)); @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(sizes) BOOST_CHECK_EQUAL(sizeof(uint8_t), GetSerializeSize(bool(0), 0)); // Sanity-check GetSerializeSize and c++ type matching - BOOST_CHECK_EQUAL(GetSerializeSize(char(0), 0), 1U); + BOOST_CHECK_EQUAL(GetSerializeSize((unsigned char)0, 0), 1U); BOOST_CHECK_EQUAL(GetSerializeSize(int8_t(0), 0), 1U); BOOST_CHECK_EQUAL(GetSerializeSize(uint8_t(0), 0), 1U); BOOST_CHECK_EQUAL(GetSerializeSize(int16_t(0), 0), 2U); @@ -186,78 +186,35 @@ BOOST_AUTO_TEST_CASE(noncanonical) std::vector<char>::size_type n; // zero encoded with three bytes: - ss.write("\xfd\x00\x00", 3); + ss.write(MakeByteSpan("\xfd\x00\x00").first(3)); BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); // 0xfc encoded with three bytes: - ss.write("\xfd\xfc\x00", 3); + ss.write(MakeByteSpan("\xfd\xfc\x00").first(3)); BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); // 0xfd encoded with three bytes is OK: - ss.write("\xfd\xfd\x00", 3); + ss.write(MakeByteSpan("\xfd\xfd\x00").first(3)); n = ReadCompactSize(ss); BOOST_CHECK(n == 0xfd); // zero encoded with five bytes: - ss.write("\xfe\x00\x00\x00\x00", 5); + ss.write(MakeByteSpan("\xfe\x00\x00\x00\x00").first(5)); BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); // 0xffff encoded with five bytes: - ss.write("\xfe\xff\xff\x00\x00", 5); + ss.write(MakeByteSpan("\xfe\xff\xff\x00\x00").first(5)); BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); // zero encoded with nine bytes: - ss.write("\xff\x00\x00\x00\x00\x00\x00\x00\x00", 9); + ss.write(MakeByteSpan("\xff\x00\x00\x00\x00\x00\x00\x00\x00").first(9)); BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); // 0x01ffffff encoded with nine bytes: - ss.write("\xff\xff\xff\xff\x01\x00\x00\x00\x00", 9); + ss.write(MakeByteSpan("\xff\xff\xff\xff\x01\x00\x00\x00\x00").first(9)); BOOST_CHECK_EXCEPTION(ReadCompactSize(ss), std::ios_base::failure, isCanonicalException); } -BOOST_AUTO_TEST_CASE(insert_delete) -{ - // Test inserting/deleting bytes. - CDataStream ss(SER_DISK, 0); - BOOST_CHECK_EQUAL(ss.size(), 0U); - - ss.write("\x00\x01\x02\xff", 4); - BOOST_CHECK_EQUAL(ss.size(), 4U); - - char c = (char)11; - - // Inserting at beginning/end/middle: - ss.insert(ss.begin(), c); - BOOST_CHECK_EQUAL(ss.size(), 5U); - BOOST_CHECK_EQUAL(ss[0], c); - BOOST_CHECK_EQUAL(ss[1], 0); - - ss.insert(ss.end(), c); - BOOST_CHECK_EQUAL(ss.size(), 6U); - BOOST_CHECK_EQUAL(ss[4], 0xff); - BOOST_CHECK_EQUAL(ss[5], c); - - ss.insert(ss.begin()+2, c); - BOOST_CHECK_EQUAL(ss.size(), 7U); - BOOST_CHECK_EQUAL(ss[2], c); - - // Delete at beginning/end/middle - ss.erase(ss.begin()); - BOOST_CHECK_EQUAL(ss.size(), 6U); - BOOST_CHECK_EQUAL(ss[0], 0); - - ss.erase(ss.begin()+ss.size()-1); - BOOST_CHECK_EQUAL(ss.size(), 5U); - BOOST_CHECK_EQUAL(ss[4], 0xff); - - ss.erase(ss.begin()+1); - BOOST_CHECK_EQUAL(ss.size(), 4U); - BOOST_CHECK_EQUAL(ss[0], 0); - BOOST_CHECK_EQUAL(ss[1], 1); - BOOST_CHECK_EQUAL(ss[2], 2); - BOOST_CHECK_EQUAL(ss[3], 0xff); -} - BOOST_AUTO_TEST_CASE(class_methods) { int intval(100); diff --git a/src/test/settings_tests.cpp b/src/test/settings_tests.cpp index 15cba9e3e5..15ffd068c7 100644 --- a/src/test/settings_tests.cpp +++ b/src/test/settings_tests.cpp @@ -1,9 +1,10 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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 <util/settings.h> +#include <fs.h> #include <test/util/setup_common.h> #include <test/util/str.h> @@ -13,6 +14,11 @@ #include <util/strencodings.h> #include <util/string.h> #include <util/system.h> + +#include <fstream> +#include <map> +#include <string> +#include <system_error> #include <vector> inline bool operator==(const util::SettingsValue& a, const util::SettingsValue& b) @@ -36,7 +42,7 @@ inline std::ostream& operator<<(std::ostream& os, const std::pair<std::string, u inline void WriteText(const fs::path& path, const std::string& text) { - fsbridge::ofstream file; + std::ofstream file; file.open(path); file << text; } diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 195565c1f8..1601b02356 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2020 The Bitcoin Core developers +// Copyright (c) 2013-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. @@ -91,8 +91,9 @@ void static RandomScript(CScript &script) { script << oplist[InsecureRandRange(std::size(oplist))]; } -void static RandomTransaction(CMutableTransaction &tx, bool fSingle) { - tx.nVersion = InsecureRand32(); +void static RandomTransaction(CMutableTransaction& tx, bool fSingle) +{ + tx.nVersion = int(InsecureRand32()); tx.vin.clear(); tx.vout.clear(); tx.nLockTime = (InsecureRandBool()) ? InsecureRand32() : 0; @@ -126,7 +127,7 @@ BOOST_AUTO_TEST_CASE(sighash_test) int nRandomTests = 50000; #endif for (int i=0; i<nRandomTests; i++) { - int nHashType = InsecureRand32(); + int nHashType{int(InsecureRand32())}; CMutableTransaction txTo; RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); CScript scriptCode; diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index db96fd4940..55486db6b2 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index 7ede79279f..6dadf09176 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -114,8 +114,8 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test) } else { // randomly choose something in the range [MTP, MTP*2] int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast(); - int r = InsecureRandRange(medianTimePast); - vBlocksMain[i].nTime = r + medianTimePast; + int r{int(InsecureRandRange(medianTimePast))}; + vBlocksMain[i].nTime = uint32_t(r + medianTimePast); vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i-1].nTimeMax); } } diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index 8d44e92f97..0925e2e9ee 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -1,12 +1,15 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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 <fs.h> #include <streams.h> #include <test/util/setup_common.h> #include <boost/test/unit_test.hpp> +using namespace std::string_literals; + BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(streams_vector_writer) @@ -160,57 +163,36 @@ BOOST_AUTO_TEST_CASE(bitstream_reader_writer) BOOST_AUTO_TEST_CASE(streams_serializedata_xor) { - std::vector<uint8_t> in; - std::vector<char> expected_xor; - std::vector<unsigned char> key; - CDataStream ds(in, 0, 0); + std::vector<std::byte> in; // Degenerate case + { + CDataStream ds{in, 0, 0}; + ds.Xor({0x00, 0x00}); + BOOST_CHECK_EQUAL(""s, ds.str()); + } - key.push_back('\x00'); - key.push_back('\x00'); - ds.Xor(key); - BOOST_CHECK_EQUAL( - std::string(expected_xor.begin(), expected_xor.end()), - ds.str()); - - in.push_back('\x0f'); - in.push_back('\xf0'); - expected_xor.push_back('\xf0'); - expected_xor.push_back('\x0f'); + in.push_back(std::byte{0x0f}); + in.push_back(std::byte{0xf0}); // Single character key - - ds.clear(); - ds.insert(ds.begin(), in.begin(), in.end()); - key.clear(); - - key.push_back('\xff'); - ds.Xor(key); - BOOST_CHECK_EQUAL( - std::string(expected_xor.begin(), expected_xor.end()), - ds.str()); + { + CDataStream ds{in, 0, 0}; + ds.Xor({0xff}); + BOOST_CHECK_EQUAL("\xf0\x0f"s, ds.str()); + } // Multi character key in.clear(); - expected_xor.clear(); - in.push_back('\xf0'); - in.push_back('\x0f'); - expected_xor.push_back('\x0f'); - expected_xor.push_back('\x00'); - - ds.clear(); - ds.insert(ds.begin(), in.begin(), in.end()); - - key.clear(); - key.push_back('\xff'); - key.push_back('\x0f'); - - ds.Xor(key); - BOOST_CHECK_EQUAL( - std::string(expected_xor.begin(), expected_xor.end()), - ds.str()); + in.push_back(std::byte{0xf0}); + in.push_back(std::byte{0x0f}); + + { + CDataStream ds{in, 0, 0}; + ds.Xor({0xff, 0x0f}); + BOOST_CHECK_EQUAL("\x0f\x00"s, ds.str()); + } } BOOST_AUTO_TEST_CASE(streams_buffered_file) @@ -421,7 +403,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) size_t find = currentPos + InsecureRandRange(8); if (find >= fileSize) find = fileSize - 1; - bf.FindByte(static_cast<char>(find)); + bf.FindByte(uint8_t(find)); // The value at each offset is the offset. BOOST_CHECK_EQUAL(bf.GetPos(), find); currentPos = find; diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp index f5a8fc3aa6..55c2c5108d 100644 --- a/src/test/sync_tests.cpp +++ b/src/test/sync_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. diff --git a/src/test/system_tests.cpp b/src/test/system_tests.cpp index bdb4b4ed7f..9c6950f11f 100644 --- a/src/test/system_tests.cpp +++ b/src/test/system_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. // diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 6b0614ed97..4fb7f9c405 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) fValid = false; break; } - COutPoint outpoint(uint256S(vinput[0].get_str()), vinput[1].get_int()); + COutPoint outpoint{uint256S(vinput[0].get_str()), uint32_t(vinput[1].get_int())}; mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str()); if (vinput.size() >= 4) { @@ -308,7 +308,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) fValid = false; break; } - COutPoint outpoint(uint256S(vinput[0].get_str()), vinput[1].get_int()); + COutPoint outpoint{uint256S(vinput[0].get_str()), uint32_t(vinput[1].get_int())}; mapprevOutScriptPubKeys[outpoint] = ParseScript(vinput[2].get_str()); if (vinput.size() >= 4) { diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp index 3ce7ecb5f2..15213f826b 100644 --- a/src/test/txindex_tests.cpp +++ b/src/test/txindex_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp index 6f78b43826..560efb6b42 100644 --- a/src/test/txpackage_tests.cpp +++ b/src/test/txpackage_tests.cpp @@ -327,4 +327,236 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(tx_child->GetHash()))); } } + +// Tests for packages containing transactions that have same-txid-different-witness equivalents in +// the mempool. +BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) +{ + // Mine blocks to mature coinbases. + mineBlocks(5); + LOCK(cs_main); + + // Transactions with a same-txid-different-witness transaction in the mempool should be ignored, + // and the mempool entry's wtxid returned. + CScript witnessScript = CScript() << OP_DROP << OP_TRUE; + CScript scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript)); + auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/ m_coinbase_txns[0], /*vout=*/ 0, + /*input_height=*/ 0, /*input_signing_key=*/ coinbaseKey, + /*output_destination=*/ scriptPubKey, + /*output_amount=*/ CAmount(49 * COIN), /*submit=*/ false); + CTransactionRef ptx_parent = MakeTransactionRef(mtx_parent); + + // Make two children with the same txid but different witnesses. + CScriptWitness witness1; + witness1.stack.push_back(std::vector<unsigned char>(1)); + witness1.stack.push_back(std::vector<unsigned char>(witnessScript.begin(), witnessScript.end())); + + CScriptWitness witness2(witness1); + witness2.stack.push_back(std::vector<unsigned char>(2)); + witness2.stack.push_back(std::vector<unsigned char>(witnessScript.begin(), witnessScript.end())); + + CKey child_key; + child_key.MakeNewKey(true); + CScript child_locking_script = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey())); + CMutableTransaction mtx_child1; + mtx_child1.nVersion = 1; + mtx_child1.vin.resize(1); + mtx_child1.vin[0].prevout.hash = ptx_parent->GetHash(); + mtx_child1.vin[0].prevout.n = 0; + mtx_child1.vin[0].scriptSig = CScript(); + mtx_child1.vin[0].scriptWitness = witness1; + mtx_child1.vout.resize(1); + mtx_child1.vout[0].nValue = CAmount(48 * COIN); + mtx_child1.vout[0].scriptPubKey = child_locking_script; + + CMutableTransaction mtx_child2{mtx_child1}; + mtx_child2.vin[0].scriptWitness = witness2; + + CTransactionRef ptx_child1 = MakeTransactionRef(mtx_child1); + CTransactionRef ptx_child2 = MakeTransactionRef(mtx_child2); + + // child1 and child2 have the same txid + BOOST_CHECK_EQUAL(ptx_child1->GetHash(), ptx_child2->GetHash()); + // child1 and child2 have different wtxids + BOOST_CHECK(ptx_child1->GetWitnessHash() != ptx_child2->GetWitnessHash()); + + // Try submitting Package1{parent, child1} and Package2{parent, child2} where the children are + // same-txid-different-witness. + { + const auto submit_witness1 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, + {ptx_parent, ptx_child1}, /*test_accept=*/ false); + BOOST_CHECK_MESSAGE(submit_witness1.m_state.IsValid(), + "Package validation unexpectedly failed: " << submit_witness1.m_state.GetRejectReason()); + auto it_parent1 = submit_witness1.m_tx_results.find(ptx_parent->GetWitnessHash()); + auto it_child1 = submit_witness1.m_tx_results.find(ptx_child1->GetWitnessHash()); + BOOST_CHECK(it_parent1 != submit_witness1.m_tx_results.end()); + BOOST_CHECK_MESSAGE(it_parent1->second.m_state.IsValid(), + "Transaction unexpectedly failed: " << it_parent1->second.m_state.GetRejectReason()); + BOOST_CHECK(it_child1 != submit_witness1.m_tx_results.end()); + BOOST_CHECK_MESSAGE(it_child1->second.m_state.IsValid(), + "Transaction unexpectedly failed: " << it_child1->second.m_state.GetRejectReason()); + + BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_parent->GetHash()))); + BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_child1->GetHash()))); + + const auto submit_witness2 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, + {ptx_parent, ptx_child2}, /*test_accept=*/ false); + BOOST_CHECK_MESSAGE(submit_witness2.m_state.IsValid(), + "Package validation unexpectedly failed: " << submit_witness2.m_state.GetRejectReason()); + auto it_parent2_deduped = submit_witness2.m_tx_results.find(ptx_parent->GetWitnessHash()); + auto it_child2 = submit_witness2.m_tx_results.find(ptx_child2->GetWitnessHash()); + BOOST_CHECK(it_parent2_deduped != submit_witness2.m_tx_results.end()); + BOOST_CHECK(it_parent2_deduped->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY); + BOOST_CHECK(it_child2 != submit_witness2.m_tx_results.end()); + BOOST_CHECK(it_child2->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS); + BOOST_CHECK_EQUAL(ptx_child1->GetWitnessHash(), it_child2->second.m_other_wtxid.value()); + + BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_child2->GetHash()))); + BOOST_CHECK(!m_node.mempool->exists(GenTxid::Wtxid(ptx_child2->GetWitnessHash()))); + } + + // Try submitting Package1{child2, grandchild} where child2 is same-txid-different-witness as + // the in-mempool transaction, child1. Since child1 exists in the mempool and its outputs are + // available, child2 should be ignored and grandchild should be accepted. + // + // This tests a potential censorship vector in which an attacker broadcasts a competing package + // where a parent's witness is mutated. The honest package should be accepted despite the fact + // that we don't allow witness replacement. + CKey grandchild_key; + grandchild_key.MakeNewKey(true); + CScript grandchild_locking_script = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey())); + auto mtx_grandchild = CreateValidMempoolTransaction(/*input_transaction=*/ ptx_child2, /* vout=*/ 0, + /*input_height=*/ 0, /*input_signing_key=*/ child_key, + /*output_destination=*/ grandchild_locking_script, + /*output_amount=*/ CAmount(47 * COIN), /*submit=*/ false); + CTransactionRef ptx_grandchild = MakeTransactionRef(mtx_grandchild); + + // We already submitted child1 above. + { + const auto submit_spend_ignored = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, + {ptx_child2, ptx_grandchild}, /*test_accept=*/ false); + BOOST_CHECK_MESSAGE(submit_spend_ignored.m_state.IsValid(), + "Package validation unexpectedly failed: " << submit_spend_ignored.m_state.GetRejectReason()); + auto it_child2_ignored = submit_spend_ignored.m_tx_results.find(ptx_child2->GetWitnessHash()); + auto it_grandchild = submit_spend_ignored.m_tx_results.find(ptx_grandchild->GetWitnessHash()); + BOOST_CHECK(it_child2_ignored != submit_spend_ignored.m_tx_results.end()); + BOOST_CHECK(it_child2_ignored->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS); + BOOST_CHECK(it_grandchild != submit_spend_ignored.m_tx_results.end()); + BOOST_CHECK(it_grandchild->second.m_result_type == MempoolAcceptResult::ResultType::VALID); + + BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_child2->GetHash()))); + BOOST_CHECK(!m_node.mempool->exists(GenTxid::Wtxid(ptx_child2->GetWitnessHash()))); + BOOST_CHECK(m_node.mempool->exists(GenTxid::Wtxid(ptx_grandchild->GetWitnessHash()))); + } + + // A package Package{parent1, parent2, parent3, child} where the parents are a mixture of + // identical-tx-in-mempool, same-txid-different-witness-in-mempool, and new transactions. + Package package_mixed; + + // Give all the parents anyone-can-spend scripts so we don't have to deal with signing the child. + CScript acs_script = CScript() << OP_TRUE; + CScript acs_spk = GetScriptForDestination(WitnessV0ScriptHash(acs_script)); + CScriptWitness acs_witness; + acs_witness.stack.push_back(std::vector<unsigned char>(acs_script.begin(), acs_script.end())); + + // parent1 will already be in the mempool + auto mtx_parent1 = CreateValidMempoolTransaction(/*input_transaction=*/ m_coinbase_txns[1], /*vout=*/ 0, + /*input_height=*/ 0, /*input_signing_key=*/ coinbaseKey, + /*output_destination=*/ acs_spk, + /*output_amount=*/ CAmount(49 * COIN), /*submit=*/ true); + CTransactionRef ptx_parent1 = MakeTransactionRef(mtx_parent1); + package_mixed.push_back(ptx_parent1); + + // parent2 will have a same-txid-different-witness tx already in the mempool + CScript grandparent2_script = CScript() << OP_DROP << OP_TRUE; + CScript grandparent2_spk = GetScriptForDestination(WitnessV0ScriptHash(grandparent2_script)); + CScriptWitness parent2_witness1; + parent2_witness1.stack.push_back(std::vector<unsigned char>(1)); + parent2_witness1.stack.push_back(std::vector<unsigned char>(grandparent2_script.begin(), grandparent2_script.end())); + CScriptWitness parent2_witness2; + parent2_witness2.stack.push_back(std::vector<unsigned char>(2)); + parent2_witness2.stack.push_back(std::vector<unsigned char>(grandparent2_script.begin(), grandparent2_script.end())); + + // Create grandparent2 creating an output with multiple spending paths. Submit to mempool. + auto mtx_grandparent2 = CreateValidMempoolTransaction(/*input_transaction=*/ m_coinbase_txns[2], /* vout=*/ 0, + /*input_height=*/ 0, /*input_signing_key=*/ coinbaseKey, + /*output_destination=*/ grandparent2_spk, + /*output_amount=*/ CAmount(49 * COIN), /*submit=*/ true); + CTransactionRef ptx_grandparent2 = MakeTransactionRef(mtx_grandparent2); + + CMutableTransaction mtx_parent2_v1; + mtx_parent2_v1.nVersion = 1; + mtx_parent2_v1.vin.resize(1); + mtx_parent2_v1.vin[0].prevout.hash = ptx_grandparent2->GetHash(); + mtx_parent2_v1.vin[0].prevout.n = 0; + mtx_parent2_v1.vin[0].scriptSig = CScript(); + mtx_parent2_v1.vin[0].scriptWitness = parent2_witness1; + mtx_parent2_v1.vout.resize(1); + mtx_parent2_v1.vout[0].nValue = CAmount(48 * COIN); + mtx_parent2_v1.vout[0].scriptPubKey = acs_spk; + + CMutableTransaction mtx_parent2_v2{mtx_parent2_v1}; + mtx_parent2_v2.vin[0].scriptWitness = parent2_witness2; + + CTransactionRef ptx_parent2_v1 = MakeTransactionRef(mtx_parent2_v1); + CTransactionRef ptx_parent2_v2 = MakeTransactionRef(mtx_parent2_v2); + // Put parent2_v1 in the package, submit parent2_v2 to the mempool. + const MempoolAcceptResult parent2_v2_result = m_node.chainman->ProcessTransaction(ptx_parent2_v2); + BOOST_CHECK(parent2_v2_result.m_result_type == MempoolAcceptResult::ResultType::VALID); + package_mixed.push_back(ptx_parent2_v1); + + // parent3 will be a new transaction + auto mtx_parent3 = CreateValidMempoolTransaction(/*input_transaction=*/ m_coinbase_txns[3], /*vout=*/ 0, + /*input_height=*/ 0, /*input_signing_key=*/ coinbaseKey, + /*output_destination=*/ acs_spk, + /*output_amount=*/ CAmount(49 * COIN), /*submit=*/ false); + CTransactionRef ptx_parent3 = MakeTransactionRef(mtx_parent3); + package_mixed.push_back(ptx_parent3); + + // child spends parent1, parent2, and parent3 + CKey mixed_grandchild_key; + mixed_grandchild_key.MakeNewKey(true); + CScript mixed_child_spk = GetScriptForDestination(WitnessV0KeyHash(mixed_grandchild_key.GetPubKey())); + + CMutableTransaction mtx_mixed_child; + mtx_mixed_child.vin.push_back(CTxIn(COutPoint(ptx_parent1->GetHash(), 0))); + mtx_mixed_child.vin.push_back(CTxIn(COutPoint(ptx_parent2_v1->GetHash(), 0))); + mtx_mixed_child.vin.push_back(CTxIn(COutPoint(ptx_parent3->GetHash(), 0))); + mtx_mixed_child.vin[0].scriptWitness = acs_witness; + mtx_mixed_child.vin[1].scriptWitness = acs_witness; + mtx_mixed_child.vin[2].scriptWitness = acs_witness; + mtx_mixed_child.vout.push_back(CTxOut(145 * COIN, mixed_child_spk)); + CTransactionRef ptx_mixed_child = MakeTransactionRef(mtx_mixed_child); + package_mixed.push_back(ptx_mixed_child); + + // Submit package: + // parent1 should be ignored + // parent2_v1 should be ignored (and v2 wtxid returned) + // parent3 should be accepted + // child should be accepted + { + const auto mixed_result = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_mixed, false); + BOOST_CHECK_MESSAGE(mixed_result.m_state.IsValid(), mixed_result.m_state.GetRejectReason()); + auto it_parent1 = mixed_result.m_tx_results.find(ptx_parent1->GetWitnessHash()); + auto it_parent2 = mixed_result.m_tx_results.find(ptx_parent2_v1->GetWitnessHash()); + auto it_parent3 = mixed_result.m_tx_results.find(ptx_parent3->GetWitnessHash()); + auto it_child = mixed_result.m_tx_results.find(ptx_mixed_child->GetWitnessHash()); + BOOST_CHECK(it_parent1 != mixed_result.m_tx_results.end()); + BOOST_CHECK(it_parent2 != mixed_result.m_tx_results.end()); + BOOST_CHECK(it_parent3 != mixed_result.m_tx_results.end()); + BOOST_CHECK(it_child != mixed_result.m_tx_results.end()); + + BOOST_CHECK(it_parent1->second.m_result_type == MempoolAcceptResult::ResultType::MEMPOOL_ENTRY); + BOOST_CHECK(it_parent2->second.m_result_type == MempoolAcceptResult::ResultType::DIFFERENT_WITNESS); + BOOST_CHECK(it_parent3->second.m_result_type == MempoolAcceptResult::ResultType::VALID); + BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID); + BOOST_CHECK_EQUAL(ptx_parent2_v2->GetWitnessHash(), it_parent2->second.m_other_wtxid.value()); + + BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_parent1->GetHash()))); + BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_parent2_v1->GetHash()))); + BOOST_CHECK(!m_node.mempool->exists(GenTxid::Wtxid(ptx_parent2_v1->GetWitnessHash()))); + BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_parent3->GetHash()))); + BOOST_CHECK(m_node.mempool->exists(GenTxid::Txid(ptx_mixed_child->GetHash()))); + } +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txrequest_tests.cpp b/src/test/txrequest_tests.cpp index 99d41882c9..a4ed1e8b3a 100644 --- a/src/test/txrequest_tests.cpp +++ b/src/test/txrequest_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp index c71ab01af4..f06bef3589 100644 --- a/src/test/txvalidation_tests.cpp +++ b/src/test/txvalidation_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 8be64531c4..b1e2119c64 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index b4744cabc7..bc206fc945 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. diff --git a/src/test/util/blockfilter.cpp b/src/test/util/blockfilter.cpp index b8ab9d2344..3ae22921b9 100644 --- a/src/test/util/blockfilter.cpp +++ b/src/test/util/blockfilter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -8,9 +8,13 @@ #include <node/blockstorage.h> #include <validation.h> +using node::ReadBlockFromDisk; +using node::UndoReadFromDisk; bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex* block_index, BlockFilter& filter) { + LOCK(::cs_main); + CBlock block; if (!ReadBlockFromDisk(block, block_index->GetBlockPos(), Params().GetConsensus())) { return false; diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h index a9092bd0ef..09f96a033c 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, SnapshotMetadata& meta){}; +const auto NoMalleation = [](CAutoFile& file, node::SnapshotMetadata& meta){}; /** * Create and activate a UTXO snapshot, optionally providing a function to @@ -24,7 +24,7 @@ const auto NoMalleation = [](CAutoFile& file, SnapshotMetadata& meta){}; */ template<typename F = decltype(NoMalleation)> static bool -CreateAndActivateUTXOSnapshot(NodeContext& node, const fs::path root, F malleation = NoMalleation) +CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F malleation = NoMalleation) { // Write out a snapshot to the test's tempdir. // @@ -43,7 +43,7 @@ CreateAndActivateUTXOSnapshot(NodeContext& node, const fs::path root, F malleati // FILE* infile{fsbridge::fopen(snapshot_path, "rb")}; CAutoFile auto_infile{infile, SER_DISK, CLIENT_VERSION}; - SnapshotMetadata metadata; + node::SnapshotMetadata metadata; auto_infile >> metadata; malleation(auto_infile, metadata); diff --git a/src/test/util/logging.cpp b/src/test/util/logging.cpp index 66f4efc139..753e50d054 100644 --- a/src/test/util/logging.cpp +++ b/src/test/util/logging.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/test/util/mining.cpp b/src/test/util/mining.cpp index 8b9069bea3..5ed8598e8e 100644 --- a/src/test/util/mining.cpp +++ b/src/test/util/mining.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -16,6 +16,9 @@ #include <validation.h> #include <versionbits.h> +using node::BlockAssembler; +using node::NodeContext; + CTxIn generatetoaddress(const NodeContext& node, const std::string& address) { const auto dest = DecodeDestination(address); diff --git a/src/test/util/mining.h b/src/test/util/mining.h index 1fc1864b91..09e712cd35 100644 --- a/src/test/util/mining.h +++ b/src/test/util/mining.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -13,18 +13,20 @@ class CBlock; class CChainParams; class CScript; class CTxIn; +namespace node { struct NodeContext; +} // namespace node /** Create a blockchain, starting from genesis */ std::vector<std::shared_ptr<CBlock>> CreateBlockChain(size_t total_height, const CChainParams& params); /** Returns the generated coin */ -CTxIn MineBlock(const NodeContext&, const CScript& coinbase_scriptPubKey); +CTxIn MineBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey); /** Prepare a block to be mined */ -std::shared_ptr<CBlock> PrepareBlock(const NodeContext&, const CScript& coinbase_scriptPubKey); +std::shared_ptr<CBlock> PrepareBlock(const node::NodeContext&, const CScript& coinbase_scriptPubKey); /** RPC-like helper function, returns the generated coin */ -CTxIn generatetoaddress(const NodeContext&, const std::string& address); +CTxIn generatetoaddress(const node::NodeContext&, const std::string& address); #endif // BITCOIN_TEST_UTIL_MINING_H diff --git a/src/test/util/net.cpp b/src/test/util/net.cpp index 4f15feb8e6..fe3cf52974 100644 --- a/src/test/util/net.cpp +++ b/src/test/util/net.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/test/util/net.h b/src/test/util/net.h index ad1061a451..20c45058a1 100644 --- a/src/test/util/net.h +++ b/src/test/util/net.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -13,6 +13,7 @@ #include <array> #include <cassert> #include <cstring> +#include <memory> #include <string> struct ConnmanTestMsg : public CConnman { @@ -126,6 +127,23 @@ public: int Connect(const sockaddr*, socklen_t) const override { return 0; } + std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const override + { + if (addr != nullptr) { + // Pretend all connections come from 5.5.5.5:6789 + memset(addr, 0x00, *addr_len); + const socklen_t write_len = static_cast<socklen_t>(sizeof(sockaddr_in)); + if (*addr_len >= write_len) { + *addr_len = write_len; + sockaddr_in* addr_in = reinterpret_cast<sockaddr_in*>(addr); + addr_in->sin_family = AF_INET; + memset(&addr_in->sin_addr, 0x05, sizeof(addr_in->sin_addr)); + addr_in->sin_port = htons(6789); + } + } + return std::make_unique<StaticContentsSock>(""); + }; + int GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const override { std::memset(opt_val, 0x0, *opt_len); diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index d0be9fe73a..c968e4d124 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -42,6 +42,15 @@ #include <walletinitinterface.h> #include <functional> +#include <stdexcept> + +using node::BlockAssembler; +using node::CalculateCacheSizes; +using node::LoadChainstate; +using node::RegenerateCommitments; +using node::VerifyLoadedChainstate; +using node::fPruneMode; +using node::fReindex; const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; UrlDecodeFn* const URL_DECODE = nullptr; @@ -80,7 +89,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve m_args{} { m_node.args = &gArgs; - const std::vector<const char*> arguments = Cat( + std::vector<const char*> arguments = Cat( { "dummy", "-printtoconsole=0", @@ -92,6 +101,9 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve "-debugexclude=leveldb", }, extra_args); + if (G_TEST_COMMAND_LINE_ARGUMENTS) { + arguments = Cat(arguments, G_TEST_COMMAND_LINE_ARGUMENTS()); + } util::ThreadRename("test"); fs::create_directories(m_path_root); m_args.ForceSetArg("-datadir", fs::PathToString(m_path_root)); @@ -100,9 +112,10 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve { SetupServerArgs(*m_node.args); std::string error; - const bool success{m_node.args->ParseParameters(arguments.size(), arguments.data(), error)}; - assert(success); - assert(error.empty()); + if (!m_node.args->ParseParameters(arguments.size(), arguments.data(), error)) { + m_node.args->ClearArgs(); + throw std::runtime_error{error}; + } } SelectParams(chainName); SeedInsecureRand(); @@ -182,25 +195,37 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const // instead of unit tests, but for now we need these here. RegisterAllCoreRPCCommands(tableRPC); - auto rv = LoadChainstate(fReindex.load(), - *Assert(m_node.chainman.get()), - Assert(m_node.mempool.get()), - fPruneMode, - chainparams.GetConsensus(), - m_args.GetBoolArg("-reindex-chainstate", false), - m_cache_sizes.block_tree_db, - m_cache_sizes.coins_db, - m_cache_sizes.coins, - true, - true); - assert(!rv.has_value()); + auto maybe_load_error = LoadChainstate(fReindex.load(), + *Assert(m_node.chainman.get()), + Assert(m_node.mempool.get()), + fPruneMode, + chainparams.GetConsensus(), + 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), + chainparams.GetConsensus(), + m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS), + m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL), + /*get_unix_time_seconds=*/static_cast<int64_t(*)()>(GetTime)); + assert(!maybe_verify_error.has_value()); BlockValidationState state; if (!m_node.chainman->ActiveChainstate().ActivateBestChain(state)) { throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString())); } - m_node.addrman = std::make_unique<AddrMan>(/*asmap=*/std::vector<bool>(), /*deterministic=*/false, /*consistency_check_ratio=*/0); + m_node.addrman = std::make_unique<AddrMan>(/*asmap=*/std::vector<bool>(), + /*deterministic=*/false, + m_node.args->GetIntArg("-checkaddrman", 0)); m_node.banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests. m_node.peerman = PeerManager::make(chainparams, *m_node.connman, *m_node.addrman, diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index df2c8952bc..a1b7525cf4 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. @@ -19,18 +19,24 @@ #include <util/string.h> #include <util/vector.h> +#include <functional> #include <type_traits> #include <vector> /** This is connected to the logger. Can be used to redirect logs to any other log */ extern const std::function<void(const std::string&)> G_TEST_LOG_FUN; +/** Retrieve the command line arguments. */ +extern const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS; + // Enable BOOST_CHECK_EQUAL for enum class types +namespace std { template <typename T> std::ostream& operator<<(typename std::enable_if<std::is_enum<T>::value, std::ostream>::type& stream, const T& e) { return stream << static_cast<typename std::underlying_type<T>::type>(e); } +} // namespace std /** * This global and the helpers that use it are not thread-safe. @@ -76,7 +82,7 @@ static constexpr CAmount CENT{1000000}; */ struct BasicTestingSetup { ECCVerifyHandle globalVerifyHandle; - NodeContext m_node; + node::NodeContext m_node; explicit BasicTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {}); ~BasicTestingSetup(); @@ -90,7 +96,7 @@ struct BasicTestingSetup { * initialization behaviour. */ struct ChainTestingSetup : public BasicTestingSetup { - CacheSizes m_cache_sizes{}; + node::CacheSizes m_cache_sizes{}; explicit ChainTestingSetup(const std::string& chainName = CBaseChainParams::MAIN, const std::vector<const char*>& extra_args = {}); ~ChainTestingSetup(); diff --git a/src/test/util/wallet.cpp b/src/test/util/wallet.cpp index 76c1bf93a5..52aaeabccf 100644 --- a/src/test/util/wallet.cpp +++ b/src/test/util/wallet.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -12,6 +12,8 @@ #include <wallet/wallet.h> #endif +using wallet::CWallet; + const std::string ADDRESS_BCRT1_UNSPENDABLE = "bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj"; #ifdef ENABLE_WALLET diff --git a/src/test/util/wallet.h b/src/test/util/wallet.h index 565ef1756a..31281bf70e 100644 --- a/src/test/util/wallet.h +++ b/src/test/util/wallet.h @@ -7,7 +7,9 @@ #include <string> +namespace wallet { class CWallet; +} // namespace wallet // Constants // @@ -16,9 +18,9 @@ extern const std::string ADDRESS_BCRT1_UNSPENDABLE; // RPC-like // /** Import the address to the wallet */ -void importaddress(CWallet& wallet, const std::string& address); +void importaddress(wallet::CWallet& wallet, const std::string& address); /** Returns a new address from the wallet */ -std::string getnewaddress(CWallet& w); +std::string getnewaddress(wallet::CWallet& w); #endif // BITCOIN_TEST_UTIL_WALLET_H diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 9540cead24..52b24327ec 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -1,10 +1,11 @@ -// Copyright (c) 2011-2020 The Bitcoin Core developers +// Copyright (c) 2011-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 <util/system.h> #include <clientversion.h> +#include <fs.h> #include <hash.h> // For Hash() #include <key.h> // For CKey #include <sync.h> @@ -15,6 +16,7 @@ #include <util/getuniquepath.h> #include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC #include <util/moneystr.h> +#include <util/overflow.h> #include <util/spanparsing.h> #include <util/strencodings.h> #include <util/string.h> @@ -23,6 +25,8 @@ #include <array> #include <optional> +#include <limits> +#include <map> #include <stdint.h> #include <string.h> #include <thread> @@ -1463,6 +1467,38 @@ BOOST_AUTO_TEST_CASE(test_IsDigit) BOOST_CHECK_EQUAL(IsDigit(9), false); } +/* Check for overflow */ +template <typename T> +static void TestAddMatrixOverflow() +{ + constexpr T MAXI{std::numeric_limits<T>::max()}; + BOOST_CHECK(!CheckedAdd(T{1}, MAXI)); + BOOST_CHECK(!CheckedAdd(MAXI, MAXI)); + BOOST_CHECK_EQUAL(0, CheckedAdd(T{0}, T{0}).value()); + BOOST_CHECK_EQUAL(MAXI, CheckedAdd(T{0}, MAXI).value()); + BOOST_CHECK_EQUAL(MAXI, CheckedAdd(T{1}, MAXI - 1).value()); +} + +/* Check for overflow or underflow */ +template <typename T> +static void TestAddMatrix() +{ + TestAddMatrixOverflow<T>(); + constexpr T MINI{std::numeric_limits<T>::min()}; + constexpr T MAXI{std::numeric_limits<T>::max()}; + BOOST_CHECK(!CheckedAdd(T{-1}, MINI)); + BOOST_CHECK(!CheckedAdd(MINI, MINI)); + BOOST_CHECK_EQUAL(MINI, CheckedAdd(T{0}, MINI).value()); + BOOST_CHECK_EQUAL(MINI, CheckedAdd(T{-1}, MINI + 1).value()); + BOOST_CHECK_EQUAL(-1, CheckedAdd(MINI, MAXI).value()); +} + +BOOST_AUTO_TEST_CASE(util_overflow) +{ + TestAddMatrixOverflow<unsigned>(); + TestAddMatrix<signed>(); +} + BOOST_AUTO_TEST_CASE(test_ParseInt32) { int32_t n; @@ -1588,6 +1624,11 @@ BOOST_AUTO_TEST_CASE(test_ToIntegral) BOOST_CHECK(!ToIntegral<uint8_t>("256")); } +int64_t atoi64_legacy(const std::string& str) +{ + return strtoll(str.c_str(), nullptr, 10); +} + BOOST_AUTO_TEST_CASE(test_LocaleIndependentAtoi) { BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("1234"), 1'234); @@ -1615,48 +1656,68 @@ BOOST_AUTO_TEST_CASE(test_LocaleIndependentAtoi) BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>(""), 0); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("aap"), 0); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("0x1"), 0); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-32482348723847471234"), 0); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("32482348723847471234"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-32482348723847471234"), -2'147'483'647 - 1); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("32482348723847471234"), 2'147'483'647); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("-9223372036854775809"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("-9223372036854775809"), -9'223'372'036'854'775'807LL - 1LL); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("-9223372036854775808"), -9'223'372'036'854'775'807LL - 1LL); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("9223372036854775807"), 9'223'372'036'854'775'807); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("9223372036854775808"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>("9223372036854775808"), 9'223'372'036'854'775'807); + + std::map<std::string, int64_t> atoi64_test_pairs = { + {"-9223372036854775809", std::numeric_limits<int64_t>::min()}, + {"-9223372036854775808", -9'223'372'036'854'775'807LL - 1LL}, + {"9223372036854775807", 9'223'372'036'854'775'807}, + {"9223372036854775808", std::numeric_limits<int64_t>::max()}, + {"+-", 0}, + {"0x1", 0}, + {"ox1", 0}, + {"", 0}, + }; + + for (const auto& pair : atoi64_test_pairs) { + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>(pair.first), pair.second); + } + + // Ensure legacy compatibility with previous versions of Bitcoin Core's atoi64 + for (const auto& pair : atoi64_test_pairs) { + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int64_t>(pair.first), atoi64_legacy(pair.first)); + } BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("-1"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("0"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("18446744073709551615"), 18'446'744'073'709'551'615ULL); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("18446744073709551616"), 0U); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint64_t>("18446744073709551616"), 18'446'744'073'709'551'615ULL); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-2147483649"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-2147483649"), -2'147'483'648LL); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("-2147483648"), -2'147'483'648LL); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("2147483647"), 2'147'483'647); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("2147483648"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int32_t>("2147483648"), 2'147'483'647); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("-1"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("0"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("4294967295"), 4'294'967'295U); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("4294967296"), 0U); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint32_t>("4294967296"), 4'294'967'295U); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("-32769"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("-32769"), -32'768); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("-32768"), -32'768); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("32767"), 32'767); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("32768"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int16_t>("32768"), 32'767); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("-1"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("0"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("65535"), 65'535U); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("65536"), 0U); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint16_t>("65536"), 65'535U); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("-129"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("-129"), -128); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("-128"), -128); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("127"), 127); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("128"), 0); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<int8_t>("128"), 127); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("-1"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("0"), 0U); BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("255"), 255U); - BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("256"), 0U); + BOOST_CHECK_EQUAL(LocaleIndependentAtoi<uint8_t>("256"), 255U); } BOOST_AUTO_TEST_CASE(test_ParseInt64) diff --git a/src/test/util_threadnames_tests.cpp b/src/test/util_threadnames_tests.cpp index a5b456dd7a..dbb5423a77 100644 --- a/src/test/util_threadnames_tests.cpp +++ b/src/test/util_threadnames_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 3efa74fcc3..c5b1dabcb7 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -19,6 +19,8 @@ #include <thread> +using node::BlockAssembler; + namespace validation_block_tests { struct MinerTestingSetup : public RegTestingSetup { std::shared_ptr<CBlock> Block(const uint256& prev_hash); diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp index b890ae4931..1beef5cf04 100644 --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. // @@ -43,6 +43,7 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) c1.InitCoinsDB( /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23)); + BOOST_REQUIRE(c1.LoadGenesisBlock()); // Need at least one block loaded to be able to flush caches // Add a coin to the in-memory cache, upsize once, then downsize. { diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index e6bd903b92..26392e690d 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. // @@ -20,6 +20,8 @@ #include <boost/test/unit_test.hpp> +using node::SnapshotMetadata; + BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, ChainTestingSetup) //! Basic tests for ChainstateManager. @@ -233,7 +235,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup) *chainman.SnapshotBlockhash()); // Ensure that the genesis block was not marked assumed-valid. - BOOST_CHECK(!chainman.ActiveChain().Genesis()->IsAssumedValid()); + BOOST_CHECK(WITH_LOCK(::cs_main, return !chainman.ActiveChain().Genesis()->IsAssumedValid())); const AssumeutxoData& au_data = *ExpectedAssumeutxo(snapshot_height, ::Params()); const CBlockIndex* tip = chainman.ActiveTip(); @@ -354,6 +356,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup) // Mark some region of the chain assumed-valid. for (int i = 0; i <= cs1.m_chain.Height(); ++i) { + LOCK(::cs_main); auto index = cs1.m_chain[i]; if (i < last_assumed_valid_idx && i >= assumed_valid_start_idx) { diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp index b4daceb72c..a34895d4ae 100644 --- a/src/test/validation_flush_tests.cpp +++ b/src/test/validation_flush_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. // @@ -9,6 +9,8 @@ #include <boost/test/unit_test.hpp> +using node::BlockManager; + BOOST_FIXTURE_TEST_SUITE(validation_flush_tests, ChainTestingSetup) //! Test utilities for detecting when we need to flush the coins cache based diff --git a/src/test/validation_tests.cpp b/src/test/validation_tests.cpp index ca52ecba2f..6ea49cb4ee 100644 --- a/src/test/validation_tests.cpp +++ b/src/test/validation_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020 The Bitcoin Core developers +// Copyright (c) 2014-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. diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp index 690031cdc1..bf87812a8a 100644 --- a/src/test/versionbits_tests.cpp +++ b/src/test/versionbits_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020 The Bitcoin Core developers +// Copyright (c) 2014-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. diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h index 42470c70ee..cb9a5fbf8b 100644 --- a/src/threadinterrupt.h +++ b/src/threadinterrupt.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/timedata.cpp b/src/timedata.cpp index 69d0273e79..541580b3ff 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020 The Bitcoin Core developers +// Copyright (c) 2014-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. diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 776981b7f7..1bbced8cb6 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-2021 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/torcontrol.h b/src/torcontrol.h index 8fc852f843..4ace3edcb1 100644 --- a/src/torcontrol.h +++ b/src/torcontrol.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. diff --git a/src/txdb.cpp b/src/txdb.cpp index 3839c9083c..5e4379a60a 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -296,8 +296,8 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex) { + AssertLockHeld(::cs_main); std::unique_ptr<CDBIterator> pcursor(NewIterator()); - pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256())); // Load m_block_index @@ -322,8 +322,9 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; - if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams)) + if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams)) { return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString()); + } pcursor->Next(); } else { diff --git a/src/txdb.h b/src/txdb.h index 1bdce71126..e70f3cd1f2 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -86,7 +86,8 @@ public: void ReadReindexing(bool &fReindexing); bool WriteFlag(const std::string &name, bool fValue); bool ReadFlag(const std::string &name, bool &fValue); - bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex); + bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex) + EXCLUSIVE_LOCKS_REQUIRED(::cs_main); }; std::optional<bilingual_str> CheckLegacyTxindex(CBlockTreeDB& block_tree_db); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index fcfc27d38e..fb5652d0a0 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -64,16 +64,6 @@ private: int64_t feeDelta; }; -struct update_lock_points -{ - explicit update_lock_points(const LockPoints& _lp) : lp(_lp) { } - - void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); } - -private: - const LockPoints& lp; -}; - bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp) { AssertLockHeld(cs_main); @@ -126,10 +116,9 @@ size_t CTxMemPoolEntry::GetTxSize() const return GetVirtualTransactionSize(nTxWeight, sigOpCost); } -// Update the given tx for any in-mempool descendants. -// Assumes that CTxMemPool::m_children is correct for the given tx and all -// descendants. -void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendants, const std::set<uint256> &setExclude) +void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants, + const std::set<uint256>& setExclude, std::set<uint256>& descendants_to_remove, + uint64_t ancestor_size_limit, uint64_t ancestor_count_limit) { CTxMemPoolEntry::Children stageEntries, descendants; stageEntries = updateIt->GetMemPoolChildrenConst(); @@ -166,17 +155,18 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap &cachedDescendan cachedDescendants[updateIt].insert(mapTx.iterator_to(descendant)); // Update ancestor state for each descendant mapTx.modify(mapTx.iterator_to(descendant), update_ancestor_state(updateIt->GetTxSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCost())); + // Don't directly remove the transaction here -- doing so would + // invalidate iterators in cachedDescendants. Mark it for removal + // by inserting into descendants_to_remove. + if (descendant.GetCountWithAncestors() > ancestor_count_limit || descendant.GetSizeWithAncestors() > ancestor_size_limit) { + descendants_to_remove.insert(descendant.GetTx().GetHash()); + } } } mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount)); } -// vHashesToUpdate is the set of transaction hashes from a disconnected block -// which has been re-added to the mempool. -// for each entry, look for descendants that are outside vHashesToUpdate, and -// add fee/size information for such descendants to the parent. -// for each such descendant, also update the ancestor state to include the parent. -void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate) +void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate, uint64_t ancestor_size_limit, uint64_t ancestor_count_limit) { AssertLockHeld(cs); // For each entry in vHashesToUpdate, store the set of in-mempool, but not @@ -188,6 +178,8 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes // accounted for in the state of their ancestors) std::set<uint256> setAlreadyIncluded(vHashesToUpdate.begin(), vHashesToUpdate.end()); + std::set<uint256> descendants_to_remove; + // Iterate in reverse, so that whenever we are looking at a transaction // we are sure that all in-mempool descendants have already been processed. // This maximizes the benefit of the descendant cache and guarantees that @@ -217,7 +209,15 @@ void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashes } } } // release epoch guard for UpdateForDescendants - UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded); + UpdateForDescendants(it, mapMemPoolDescendantsToUpdate, setAlreadyIncluded, descendants_to_remove, ancestor_size_limit, ancestor_count_limit); + } + + for (const auto& txid : descendants_to_remove) { + // This txid may have been removed already in a prior call to removeRecursive. + // Therefore we ensure it is not yet removed already. + if (const std::optional<txiter> txiter = GetIter(txid)) { + removeRecursive((*txiter)->GetTx(), MemPoolRemovalReason::SIZELIMIT); + } } } @@ -649,10 +649,7 @@ void CTxMemPool::removeForReorg(CChain& chain, std::function<bool(txiter)> check } RemoveStaged(setAllRemoves, false, MemPoolRemovalReason::REORG); for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { - const LockPoints lp{it->GetLockPoints()}; - if (!TestLockPointValidity(chain, lp)) { - mapTx.modify(it, update_lock_points(lp)); - } + assert(TestLockPointValidity(chain, it->GetLockPoints())); } } diff --git a/src/txmempool.h b/src/txmempool.h index f87ecc9cd0..e7e5a3c402 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -589,10 +589,14 @@ public: void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs); - /** After reorg, check if mempool entries are now non-final, premature coinbase spends, or have - * invalid lockpoints. Update lockpoints and remove entries (and descendants of entries) that - * are no longer valid. */ - void removeForReorg(CChain& chain, std::function<bool(txiter)> check_final_and_mature) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); + /** After reorg, filter the entries that would no longer be valid in the next block, and update + * the entries' cached LockPoints if needed. The mempool does not have any knowledge of + * consensus rules. It just appplies the callable function and removes the ones for which it + * returns true. + * @param[in] filter_final_and_mature Predicate that checks the relevant validation rules + * and updates an entry's LockPoints. + * */ + void removeForReorg(CChain& chain, std::function<bool(txiter)> filter_final_and_mature) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs); @@ -632,16 +636,25 @@ public: */ void RemoveStaged(setEntries& stage, bool updateDescendants, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs); - /** When adding transactions from a disconnected block back to the mempool, - * new mempool entries may have children in the mempool (which is generally - * not the case when otherwise adding transactions). - * UpdateTransactionsFromBlock() will find child transactions and update the - * descendant state for each transaction in vHashesToUpdate (excluding any - * child transactions present in vHashesToUpdate, which are already accounted - * for). Note: vHashesToUpdate should be the set of transactions from the - * disconnected block that have been accepted back into the mempool. + /** UpdateTransactionsFromBlock is called when adding transactions from a + * disconnected block back to the mempool, new mempool entries may have + * children in the mempool (which is generally not the case when otherwise + * adding transactions). + * @post updated descendant state for descendants of each transaction in + * vHashesToUpdate (excluding any child transactions present in + * vHashesToUpdate, which are already accounted for). Updated state + * includes add fee/size information for such descendants to the + * parent and updated ancestor state to include the parent. + * + * @param[in] vHashesToUpdate The set of txids from the + * disconnected block that have been accepted back into the mempool. + * @param[in] ancestor_size_limit The maximum allowed size in virtual + * bytes of an entry and its ancestors + * @param[in] ancestor_count_limit The maximum allowed number of + * transactions including the entry and its ancestors. */ - void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch); + void UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate, + uint64_t ancestor_size_limit, uint64_t ancestor_count_limit) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main) LOCKS_EXCLUDED(m_epoch); /** Try to calculate all in-mempool ancestors of entry. * (these are all calculated including the tx itself) @@ -790,19 +803,38 @@ private: /** UpdateForDescendants is used by UpdateTransactionsFromBlock to update * the descendants for a single transaction that has been added to the * mempool but may have child transactions in the mempool, eg during a - * chain reorg. setExclude is the set of descendant transactions in the - * mempool that must not be accounted for (because any descendants in - * setExclude were added to the mempool after the transaction being - * updated and hence their state is already reflected in the parent - * state). + * chain reorg. + * + * @pre CTxMemPool::m_children is correct for the given tx and all + * descendants. + * @pre cachedDescendants is an accurate cache where each entry has all + * descendants of the corresponding key, including those that should + * be removed for violation of ancestor limits. + * @post if updateIt has any non-excluded descendants, cachedDescendants has + * a new cache line for updateIt. + * @post descendants_to_remove has a new entry for any descendant which exceeded + * ancestor limits relative to updateIt. * - * cachedDescendants will be updated with the descendants of the transaction - * being updated, so that future invocations don't need to walk the - * same transaction again, if encountered in another transaction chain. + * @param[in] updateIt the entry to update for its descendants + * @param[in,out] cachedDescendants a cache where each line corresponds to all + * descendants. It will be updated with the descendants of the transaction + * being updated, so that future invocations don't need to walk the same + * transaction again, if encountered in another transaction chain. + * @param[in] setExclude the set of descendant transactions in the mempool + * that must not be accounted for (because any descendants in setExclude + * were added to the mempool after the transaction being updated and hence + * their state is already reflected in the parent state). + * @param[out] descendants_to_remove Populated with the txids of entries that + * exceed ancestor limits. It's the responsibility of the caller to + * removeRecursive them. + * @param[in] ancestor_size_limit the max number of ancestral bytes allowed + * for any descendant + * @param[in] ancestor_count_limit the max number of ancestor transactions + * allowed for any descendant */ - void UpdateForDescendants(txiter updateIt, - cacheMap &cachedDescendants, - const std::set<uint256> &setExclude) EXCLUSIVE_LOCKS_REQUIRED(cs); + void UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendants, + const std::set<uint256>& setExclude, std::set<uint256>& descendants_to_remove, + uint64_t ancestor_size_limit, uint64_t ancestor_count_limit) EXCLUSIVE_LOCKS_REQUIRED(cs); /** Update ancestors of hash to add/remove it as a descendant transaction. */ void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors) EXCLUSIVE_LOCKS_REQUIRED(cs); /** Set ancestor state for an entry */ diff --git a/src/txrequest.cpp b/src/txrequest.cpp index 7d478a5b26..96a3d2eeeb 100644 --- a/src/txrequest.cpp +++ b/src/txrequest.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/uint256.h b/src/uint256.h index d4917d0eac..5c3a2f5409 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -1,11 +1,13 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. #ifndef BITCOIN_UINT256_H #define BITCOIN_UINT256_H +#include <span.h> + #include <assert.h> #include <cstring> #include <stdint.h> @@ -96,13 +98,13 @@ public: template<typename Stream> void Serialize(Stream& s) const { - s.write((char*)m_data, sizeof(m_data)); + s.write(MakeByteSpan(m_data)); } template<typename Stream> void Unserialize(Stream& s) { - s.read((char*)m_data, sizeof(m_data)); + s.read(MakeWritableByteSpan(m_data)); } }; diff --git a/src/util/asmap.cpp b/src/util/asmap.cpp index b696c65e9d..ceb8379c1c 100644 --- a/src/util/asmap.cpp +++ b/src/util/asmap.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -6,6 +6,7 @@ #include <clientversion.h> #include <crypto/common.h> +#include <fs.h> #include <logging.h> #include <streams.h> diff --git a/src/util/asmap.h b/src/util/asmap.h index 810d70b9a1..844037f816 100644 --- a/src/util/asmap.h +++ b/src/util/asmap.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/util/check.h b/src/util/check.h index b12527546c..a443c13cf2 100644 --- a/src/util/check.h +++ b/src/util/check.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/util/epochguard.h b/src/util/epochguard.h index 3e63e093da..0fec7d2624 100644 --- a/src/util/epochguard.h +++ b/src/util/epochguard.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/util/error.cpp b/src/util/error.cpp index d019ba018d..af8cbd0353 100644 --- a/src/util/error.cpp +++ b/src/util/error.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020 The Bitcoin Core developers +// Copyright (c) 2010-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. diff --git a/src/util/fastrange.h b/src/util/fastrange.h new file mode 100644 index 0000000000..77cb883ce0 --- /dev/null +++ b/src/util/fastrange.h @@ -0,0 +1,51 @@ +// Copyright (c) 2018-2020 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_UTIL_FASTRANGE_H +#define BITCOIN_UTIL_FASTRANGE_H + +#include <cstdint> + +/* This file offers implementations of the fast range reduction technique described + * in https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ + * + * In short, they take an integer x and a range n, and return the upper bits of + * (x * n). If x is uniformly distributed over its domain, the result is as close to + * uniformly distributed over [0, n) as (x mod n) would be, but significantly faster. + */ + +/** Fast range reduction with 32-bit input and 32-bit range. */ +static inline uint32_t FastRange32(uint32_t x, uint32_t n) +{ + return (uint64_t{x} * n) >> 32; +} + +/** Fast range reduction with 64-bit input and 64-bit range. */ +static inline uint64_t FastRange64(uint64_t x, uint64_t n) +{ +#ifdef __SIZEOF_INT128__ + return (static_cast<unsigned __int128>(x) * static_cast<unsigned __int128>(n)) >> 64; +#else + // To perform the calculation on 64-bit numbers without losing the + // result to overflow, split the numbers into the most significant and + // least significant 32 bits and perform multiplication piece-wise. + // + // See: https://stackoverflow.com/a/26855440 + const uint64_t x_hi = x >> 32; + const uint64_t x_lo = x & 0xFFFFFFFF; + const uint64_t n_hi = n >> 32; + const uint64_t n_lo = n & 0xFFFFFFFF; + + const uint64_t ac = x_hi * n_hi; + const uint64_t ad = x_hi * n_lo; + const uint64_t bc = x_lo * n_hi; + const uint64_t bd = x_lo * n_lo; + + const uint64_t mid34 = (bd >> 32) + (bc & 0xFFFFFFFF) + (ad & 0xFFFFFFFF); + const uint64_t upper64 = ac + (bc >> 32) + (ad >> 32) + (mid34 >> 32); + return upper64; +#endif +} + +#endif // BITCOIN_UTIL_FASTRANGE_H diff --git a/src/util/golombrice.h b/src/util/golombrice.h index 67d262406f..4ff4f6d7e5 100644 --- a/src/util/golombrice.h +++ b/src/util/golombrice.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_UTIL_GOLOMBRICE_H #define BITCOIN_UTIL_GOLOMBRICE_H +#include <util/fastrange.h> + #include <streams.h> #include <cstdint> diff --git a/src/util/hasher.h b/src/util/hasher.h index 9b79a1b5f1..3d24a4d23c 100644 --- a/src/util/hasher.h +++ b/src/util/hasher.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/util/macros.h b/src/util/macros.h index 0887c80fd7..c9740c8e82 100644 --- a/src/util/macros.h +++ b/src/util/macros.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/util/message.cpp b/src/util/message.cpp index 73948e4ff1..2c7f0406f0 100644 --- a/src/util/message.cpp +++ b/src/util/message.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/util/moneystr.cpp b/src/util/moneystr.cpp index 1aed7daacf..2cd7a426f8 100644 --- a/src/util/moneystr.cpp +++ b/src/util/moneystr.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/util/moneystr.h b/src/util/moneystr.h index f37dc1cffd..8180604342 100644 --- a/src/util/moneystr.h +++ b/src/util/moneystr.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/util/overflow.h b/src/util/overflow.h new file mode 100644 index 0000000000..5982af8d04 --- /dev/null +++ b/src/util/overflow.h @@ -0,0 +1,31 @@ +// 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. + +#ifndef BITCOIN_UTIL_OVERFLOW_H +#define BITCOIN_UTIL_OVERFLOW_H + +#include <limits> +#include <type_traits> + +template <class T> +[[nodiscard]] bool AdditionOverflow(const T i, const T j) noexcept +{ + static_assert(std::is_integral<T>::value, "Integral required."); + if (std::numeric_limits<T>::is_signed) { + return (i > 0 && j > std::numeric_limits<T>::max() - i) || + (i < 0 && j < std::numeric_limits<T>::min() - i); + } + return std::numeric_limits<T>::max() - i < j; +} + +template <class T> +[[nodiscard]] std::optional<T> CheckedAdd(const T i, const T j) noexcept +{ + if (AdditionOverflow(i, j)) { + return std::nullopt; + } + return i + j; +} + +#endif // BITCOIN_UTIL_OVERFLOW_H diff --git a/src/util/rbf.h b/src/util/rbf.h index aa522d8bfb..a957617389 100644 --- a/src/util/rbf.h +++ b/src/util/rbf.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-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. diff --git a/src/util/readwritefile.h b/src/util/readwritefile.h index a59d0be131..73437baf1b 100644 --- a/src/util/readwritefile.h +++ b/src/util/readwritefile.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. diff --git a/src/util/settings.cpp b/src/util/settings.cpp index 7fb35c073e..26439b010b 100644 --- a/src/util/settings.cpp +++ b/src/util/settings.cpp @@ -1,12 +1,18 @@ -// Copyright (c) 2019 The Bitcoin Core developers +// Copyright (c) 2019-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 <fs.h> #include <util/settings.h> #include <tinyformat.h> #include <univalue.h> +#include <fstream> +#include <map> +#include <string> +#include <vector> + namespace util { namespace { @@ -63,7 +69,7 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va // Ok for file to not exist if (!fs::exists(path)) return true; - fsbridge::ifstream file; + std::ifstream file; file.open(path); if (!file.is_open()) { errors.emplace_back(strprintf("%s. Please check permissions.", fs::PathToString(path))); @@ -106,13 +112,13 @@ bool WriteSettings(const fs::path& path, for (const auto& value : values) { out.__pushKV(value.first, value.second); } - fsbridge::ofstream file; + std::ofstream file; file.open(path); if (file.fail()) { errors.emplace_back(strprintf("Error: Unable to open settings file %s for writing", fs::PathToString(path))); return false; } - file << out.write(/* prettyIndent= */ 1, /* indentLevel= */ 4) << std::endl; + file << out.write(/* prettyIndent= */ 4, /* indentLevel= */ 1) << std::endl; file.close(); return true; } diff --git a/src/util/sock.cpp b/src/util/sock.cpp index 1a4d67a65e..2029d70a37 100644 --- a/src/util/sock.cpp +++ b/src/util/sock.cpp @@ -10,6 +10,7 @@ #include <util/system.h> #include <util/time.h> +#include <memory> #include <stdexcept> #include <string> @@ -73,6 +74,32 @@ int Sock::Connect(const sockaddr* addr, socklen_t addr_len) const return connect(m_socket, addr, addr_len); } +std::unique_ptr<Sock> Sock::Accept(sockaddr* addr, socklen_t* addr_len) const +{ +#ifdef WIN32 + static constexpr auto ERR = INVALID_SOCKET; +#else + static constexpr auto ERR = SOCKET_ERROR; +#endif + + std::unique_ptr<Sock> sock; + + const auto socket = accept(m_socket, addr, addr_len); + if (socket != ERR) { + try { + sock = std::make_unique<Sock>(socket); + } catch (const std::exception&) { +#ifdef WIN32 + closesocket(socket); +#else + close(socket); +#endif + } + } + + return sock; +} + int Sock::GetSockOpt(int level, int opt_name, void* opt_val, socklen_t* opt_len) const { return getsockopt(m_socket, level, opt_name, static_cast<char*>(opt_val), opt_len); diff --git a/src/util/sock.h b/src/util/sock.h index 59cc8c0b1d..7510482857 100644 --- a/src/util/sock.h +++ b/src/util/sock.h @@ -10,6 +10,7 @@ #include <util/time.h> #include <chrono> +#include <memory> #include <string> /** @@ -97,6 +98,14 @@ public: [[nodiscard]] virtual int Connect(const sockaddr* addr, socklen_t addr_len) const; /** + * accept(2) wrapper. Equivalent to `std::make_unique<Sock>(accept(this->Get(), addr, addr_len))`. + * Code that uses this wrapper can be unit tested if this method is overridden by a mock Sock + * implementation. + * The returned unique_ptr is empty if `accept()` failed in which case errno will be set. + */ + [[nodiscard]] virtual std::unique_ptr<Sock> Accept(sockaddr* addr, socklen_t* addr_len) const; + + /** * getsockopt(2) wrapper. Equivalent to * `getsockopt(this->Get(), level, opt_name, opt_val, opt_len)`. Code that uses this * wrapper can be unit tested if this method is overridden by a mock Sock implementation. diff --git a/src/util/spanparsing.cpp b/src/util/spanparsing.cpp index e2e2782bec..50f6aee419 100644 --- a/src/util/spanparsing.cpp +++ b/src/util/spanparsing.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-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. diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index f4768d5bb6..940fa90da2 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -113,7 +113,7 @@ void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut) // if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator bool fHaveColon = colon != in.npos; bool fBracketed = fHaveColon && (in[0] == '[' && in[colon - 1] == ']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe - bool fMultiColon = fHaveColon && (in.find_last_of(':', colon - 1) != in.npos); + bool fMultiColon{fHaveColon && colon != 0 && (in.find_last_of(':', colon - 1) != in.npos)}; if (fHaveColon && (colon == 0 || fBracketed || !fMultiColon)) { uint16_t n; if (ParseUInt16(in.substr(colon + 1), &n)) { @@ -328,6 +328,7 @@ bool ParseUInt64(const std::string& str, uint64_t* out) std::string FormatParagraph(const std::string& in, size_t width, size_t indent) { + assert(width >= indent); std::stringstream out; size_t ptr = 0; size_t indented = 0; diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 5813e8d212..1f83fa3ffa 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -16,6 +16,7 @@ #include <charconv> #include <cstdint> #include <iterator> +#include <limits> #include <optional> #include <string> #include <vector> @@ -93,8 +94,12 @@ void SplitHostPort(std::string in, uint16_t& portOut, std::string& hostOut); // New code should use ToIntegral or the ParseInt* functions // which provide parse error feedback. // -// The goal of LocaleIndependentAtoi is to replicate the exact defined behaviour -// of atoi and atoi64 as they behave under the "C" locale. +// The goal of LocaleIndependentAtoi is to replicate the defined behaviour of +// std::atoi as it behaves under the "C" locale, and remove some undefined +// behavior. If the parsed value is bigger than the integer type's maximum +// value, or smaller than the integer type's minimum value, std::atoi has +// undefined behavior, while this function returns the maximum or minimum +// values, respectively. template <typename T> T LocaleIndependentAtoi(const std::string& str) { @@ -109,7 +114,15 @@ T LocaleIndependentAtoi(const std::string& str) s = s.substr(1); } auto [_, error_condition] = std::from_chars(s.data(), s.data() + s.size(), result); - if (error_condition != std::errc{}) { + if (error_condition == std::errc::result_out_of_range) { + if (s.length() >= 1 && s[0] == '-') { + // Saturate underflow, per strtoll's behavior. + return std::numeric_limits<T>::min(); + } else { + // Saturate overflow, per strtoll's behavior. + return std::numeric_limits<T>::max(); + } + } else if (error_condition != std::errc{}) { return 0; } return result; diff --git a/src/util/string.h b/src/util/string.h index 07c87cfcda..a3b8df8d78 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/util/syscall_sandbox.cpp b/src/util/syscall_sandbox.cpp index 6e1cc9b457..f513dba598 100644 --- a/src/util/syscall_sandbox.cpp +++ b/src/util/syscall_sandbox.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -595,10 +595,12 @@ public: allowed_syscalls.insert(__NR_readlink); // read value of a symbolic link allowed_syscalls.insert(__NR_rename); // change the name or location of a file allowed_syscalls.insert(__NR_rmdir); // delete a directory + allowed_syscalls.insert(__NR_sendfile); // transfer data between file descriptors allowed_syscalls.insert(__NR_stat); // get file status allowed_syscalls.insert(__NR_statfs); // get filesystem statistics allowed_syscalls.insert(__NR_statx); // get file status (extended) allowed_syscalls.insert(__NR_unlink); // delete a name and possibly the file it refers to + allowed_syscalls.insert(__NR_unlinkat); // delete relative to a directory file descriptor } void AllowFutex() diff --git a/src/util/syscall_sandbox.h b/src/util/syscall_sandbox.h index 0a0c964f94..f7a1cbdb55 100644 --- a/src/util/syscall_sandbox.h +++ b/src/util/syscall_sandbox.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/util/system.cpp b/src/util/system.cpp index 99d111b066..69811a751b 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -1,20 +1,16 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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 <util/system.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 #include <boost/process.hpp> #endif // ENABLE_EXTERNAL_SIGNER #include <chainparamsbase.h> +#include <fs.h> #include <sync.h> #include <util/check.h> #include <util/getuniquepath.h> @@ -71,10 +67,16 @@ #endif #include <boost/algorithm/string/replace.hpp> +#include <univalue.h> + +#include <fstream> +#include <map> +#include <memory> #include <optional> +#include <string> +#include <system_error> #include <thread> #include <typeinfo> -#include <univalue.h> // Application startup time (used for uptime calculation) const int64_t nStartupTime = GetTime(); @@ -151,7 +153,7 @@ bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes) } std::streampos GetFileSize(const char* path, std::streamsize max) { - std::ifstream file(path, std::ios::binary); + std::ifstream file{path, std::ios::binary}; file.ignore(max); return file.gcount(); } @@ -244,19 +246,6 @@ static std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, con return value; } -namespace { -fs::path StripRedundantLastElementsOfPath(const fs::path& path) -{ - auto result = path; - while (fs::PathToString(result.filename()) == ".") { - result = result.parent_path(); - } - - assert(fs::equivalent(result, path)); - return result; -} -} // namespace - // Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to // #include class definitions for all members. // For example, m_settings has an internal dependency on univalue. @@ -398,6 +387,13 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co return std::nullopt; } +fs::path ArgsManager::GetPathArg(std::string pathlike_arg) const +{ + auto result = fs::PathFromString(GetArg(pathlike_arg, "")).lexically_normal(); + // Remove trailing slash, if present. + return result.has_filename() ? result : result.parent_path(); +} + const fs::path& ArgsManager::GetBlocksDirPath() const { LOCK(cs_args); @@ -408,7 +404,7 @@ const fs::path& ArgsManager::GetBlocksDirPath() const if (!path.empty()) return path; if (IsArgSet("-blocksdir")) { - path = fs::system_complete(fs::PathFromString(GetArg("-blocksdir", ""))); + path = fs::absolute(GetPathArg("-blocksdir")); if (!fs::is_directory(path)) { path = ""; return path; @@ -420,7 +416,6 @@ const fs::path& ArgsManager::GetBlocksDirPath() const path /= fs::PathFromString(BaseParams().DataDir()); path /= "blocks"; fs::create_directories(path); - path = StripRedundantLastElementsOfPath(path); return path; } @@ -433,9 +428,9 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const // this function if (!path.empty()) return path; - std::string datadir = GetArg("-datadir", ""); + const fs::path datadir{GetPathArg("-datadir")}; if (!datadir.empty()) { - path = fs::system_complete(fs::PathFromString(datadir)); + path = fs::absolute(datadir); if (!fs::is_directory(path)) { path = ""; return path; @@ -443,15 +438,18 @@ const fs::path& ArgsManager::GetDataDir(bool net_specific) const } else { path = GetDefaultDataDir(); } - if (net_specific) - path /= fs::PathFromString(BaseParams().DataDir()); - if (fs::create_directories(path)) { - // This is the first run, create wallets subdirectory too + if (!fs::exists(path)) { fs::create_directories(path / "wallets"); } - path = StripRedundantLastElementsOfPath(path); + if (net_specific && !BaseParams().DataDir().empty()) { + path /= fs::PathFromString(BaseParams().DataDir()); + if (!fs::exists(path)) { + fs::create_directories(path / "wallets"); + } + } + return path; } @@ -812,8 +810,8 @@ fs::path GetDefaultDataDir() bool CheckDataDirOption() { - std::string datadir = gArgs.GetArg("-datadir", ""); - return datadir.empty() || fs::is_directory(fs::system_complete(fs::PathFromString(datadir))); + const fs::path datadir{gArgs.GetPathArg("-datadir")}; + return datadir.empty() || fs::is_directory(fs::absolute(datadir)); } fs::path GetConfigFile(const std::string& confPath) @@ -903,7 +901,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) } const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME); - fsbridge::ifstream stream(GetConfigFile(confPath)); + std::ifstream stream{GetConfigFile(confPath)}; // not ok to have a config file specified that cannot be opened if (IsArgSet("-conf") && !stream.good()) { @@ -950,7 +948,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) { - fsbridge::ifstream conf_file_stream(GetConfigFile(conf_file_name)); + std::ifstream conf_file_stream{GetConfigFile(conf_file_name)}; if (conf_file_stream.good()) { if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) { return false; @@ -1064,17 +1062,24 @@ void ArgsManager::LogArgs() const bool RenameOver(fs::path src, fs::path dest) { -#ifdef WIN32 +#ifdef __MINGW64__ + // This is a workaround for a bug in libstdc++ which + // implements std::filesystem::rename with _wrename function. + // This bug has been fixed in upstream: + // - GCC 10.3: 8dd1c1085587c9f8a21bb5e588dfe1e8cdbba79e + // - GCC 11.1: 1dfd95f0a0ca1d9e6cbc00e6cbfd1fa20a98f312 + // For more details see the commits mentioned above. return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(), MOVEFILE_REPLACE_EXISTING) != 0; #else - int rc = std::rename(src.c_str(), dest.c_str()); - return (rc == 0); -#endif /* WIN32 */ + std::error_code error; + fs::rename(src, dest, error); + return !error; +#endif } /** - * Ignores exceptions thrown by Boost's create_directories if the requested directory exists. + * Ignores exceptions thrown by create_directories if the requested directory exists. * Specifically handles case where path p exists, but it wasn't possible for the user to * write to the parent directory. */ @@ -1318,16 +1323,6 @@ void SetupEnvironment() SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); #endif - // The path locale is lazy initialized and to avoid deinitialization errors - // in multithreading environments, it is set explicitly by the main thread. - // A dummy locale is used to extract the internal default locale, used by - // fs::path, which is then used to explicitly imbue the path. - std::locale loc = fs::path::imbue(std::locale::classic()); -#ifndef WIN32 - fs::path::imbue(loc); -#else - fs::path::imbue(std::locale(loc, new std::codecvt_utf8_utf16<wchar_t>())); -#endif } bool SetupNetworking() diff --git a/src/util/system.h b/src/util/system.h index 37d976221b..a72ba3f3ed 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -69,7 +69,13 @@ void DirectoryCommit(const fs::path &dirname); bool TruncateFile(FILE *file, unsigned int length); int RaiseFileDescriptorLimit(int nMinFD); void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); + +/** + * Rename src to dest. + * @return true if the rename was successful. + */ [[nodiscard]] bool RenameOver(fs::path src, fs::path dest); + bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false); void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name); bool DirIsWritable(const fs::path& directory); @@ -265,6 +271,16 @@ protected: std::optional<const Command> GetCommand() const; /** + * Get a normalized path from a specified pathlike argument + * + * It is guaranteed that the returned path has no trailing slashes. + * + * @param pathlike_arg Pathlike argument to get a path from (e.g., "-datadir", "-blocksdir" or "-walletdir") + * @return Normalized path which is get from a specified pathlike argument + */ + fs::path GetPathArg(std::string pathlike_arg) const; + + /** * Get blocks directory path * * @return Blocks path which is network specific diff --git a/src/util/time.cpp b/src/util/time.cpp index eda710b12c..f7712f0dc8 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/util/time.h b/src/util/time.h index 4aee01967d..9d92b23725 100644 --- a/src/util/time.h +++ b/src/util/time.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/util/trace.h b/src/util/trace.h index bb901e05da..7a63f39c83 100644 --- a/src/util/trace.h +++ b/src/util/trace.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. diff --git a/src/util/translation.h b/src/util/translation.h index 62388b568c..aee601d9c1 100644 --- a/src/util/translation.h +++ b/src/util/translation.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. diff --git a/src/validation.cpp b/src/validation.cpp index 967c1f00f3..5b52638fc5 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -62,6 +62,25 @@ #include <boost/algorithm/string/replace.hpp> +using node::BLOCKFILE_CHUNK_SIZE; +using node::BlockManager; +using node::BlockMap; +using node::CBlockIndexWorkComparator; +using node::CCoinsStats; +using node::CoinStatsHashType; +using node::GetUTXOStats; +using node::OpenBlockFile; +using node::ReadBlockFromDisk; +using node::SnapshotMetadata; +using node::UNDOFILE_CHUNK_SIZE; +using node::UndoReadFromDisk; +using node::UnlinkPrunedFiles; +using node::fHavePruned; +using node::fImporting; +using node::fPruneMode; +using node::fReindex; +using node::nPruneTarget; + #define MICRO 0.000001 #define MILLI 0.001 @@ -133,23 +152,6 @@ arith_uint256 nMinimumChainWork; CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); -// Internal stuff from blockstorage ... -extern RecursiveMutex cs_LastBlockFile; -extern std::vector<CBlockFileInfo> vinfoBlockFile; -extern int nLastBlockFile; -extern bool fCheckForPruning; -extern std::set<CBlockIndex*> setDirtyBlockIndex; -extern std::set<int> setDirtyFileInfo; -void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false); -// ... TODO move fully to blockstorage - -CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const -{ - AssertLockHeld(cs_main); - BlockMap::const_iterator it = m_block_index.find(hash); - return it == m_block_index.end() ? nullptr : it->second; -} - CBlockIndex* CChainState::FindForkInGlobalIndex(const CBlockLocator& locator) const { AssertLockHeld(cs_main); @@ -284,8 +286,10 @@ bool CheckSequenceLocks(CBlockIndex* tip, static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& chainparams); static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache, size_t limit, std::chrono::seconds age) - EXCLUSIVE_LOCKS_REQUIRED(pool.cs, ::cs_main) + EXCLUSIVE_LOCKS_REQUIRED(::cs_main, pool.cs) { + AssertLockHeld(::cs_main); + AssertLockHeld(pool.cs); int expired = pool.Expire(GetTime<std::chrono::seconds>() - age); if (expired != 0) { LogPrint(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired); @@ -345,41 +349,59 @@ void CChainState::MaybeUpdateMempoolForReorg( // previously-confirmed transactions back to the mempool. // UpdateTransactionsFromBlock finds descendants of any transactions in // the disconnectpool that were added back and cleans up the mempool state. - m_mempool->UpdateTransactionsFromBlock(vHashUpdate); - - const auto check_final_and_mature = [this, flags=STANDARD_LOCKTIME_VERIFY_FLAGS](CTxMemPool::txiter it) + const uint64_t ancestor_count_limit = gArgs.GetIntArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); + const uint64_t ancestor_size_limit = gArgs.GetIntArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000; + m_mempool->UpdateTransactionsFromBlock(vHashUpdate, ancestor_size_limit, ancestor_count_limit); + + // Predicate to use for filtering transactions in removeForReorg. + // Checks whether the transaction is still final and, if it spends a coinbase output, mature. + // Also updates valid entries' cached LockPoints if needed. + // If false, the tx is still valid and its lockpoints are updated. + // If true, the tx would be invalid in the next block; remove this entry and all of its descendants. + const auto filter_final_and_mature = [this, flags=STANDARD_LOCKTIME_VERIFY_FLAGS](CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main) { - bool should_remove = false; AssertLockHeld(m_mempool->cs); AssertLockHeld(::cs_main); const CTransaction& tx = it->GetTx(); + + // The transaction must be final. + if (!CheckFinalTx(m_chain.Tip(), tx, flags)) return true; LockPoints lp = it->GetLockPoints(); const bool validLP{TestLockPointValidity(m_chain, lp)}; CCoinsViewMemPool view_mempool(&CoinsTip(), *m_mempool); - if (!CheckFinalTx(m_chain.Tip(), tx, flags) - || !CheckSequenceLocks(m_chain.Tip(), view_mempool, tx, flags, &lp, validLP)) { - // Note if CheckSequenceLocks fails the LockPoints may still be invalid - // So it's critical that we remove the tx and not depend on the LockPoints. - should_remove = true; - } else if (it->GetSpendsCoinbase()) { + // CheckSequenceLocks checks if the transaction will be final in the next block to be + // created on top of the new chain. We use useExistingLockPoints=false so that, instead of + // using the information in lp (which might now refer to a block that no longer exists in + // the chain), it will update lp to contain LockPoints relevant to the new chain. + if (!CheckSequenceLocks(m_chain.Tip(), view_mempool, tx, flags, &lp, validLP)) { + // If CheckSequenceLocks fails, remove the tx and don't depend on the LockPoints. + return true; + } else if (!validLP) { + // If CheckSequenceLocks succeeded, it also updated the LockPoints. + // Now update the mempool entry lockpoints as well. + m_mempool->mapTx.modify(it, [&lp](CTxMemPoolEntry& e) { e.UpdateLockPoints(lp); }); + } + + // If the transaction spends any coinbase outputs, it must be mature. + if (it->GetSpendsCoinbase()) { for (const CTxIn& txin : tx.vin) { auto it2 = m_mempool->mapTx.find(txin.prevout.hash); if (it2 != m_mempool->mapTx.end()) continue; - const Coin &coin = CoinsTip().AccessCoin(txin.prevout); + const Coin& coin{CoinsTip().AccessCoin(txin.prevout)}; assert(!coin.IsSpent()); const auto mempool_spend_height{m_chain.Tip()->nHeight + 1}; - if (coin.IsSpent() || (coin.IsCoinBase() && mempool_spend_height - coin.nHeight < COINBASE_MATURITY)) { - should_remove = true; - break; + if (coin.IsCoinBase() && mempool_spend_height - coin.nHeight < COINBASE_MATURITY) { + return true; } } } - return should_remove; + // Transaction is still valid and cached LockPoints are updated. + return false; }; // We also need to remove any now-immature transactions - m_mempool->removeForReorg(m_chain, check_final_and_mature); + m_mempool->removeForReorg(m_chain, filter_final_and_mature); // Re-limit mempool size, in case we added any transactions LimitMempoolSize( *m_mempool, @@ -601,15 +623,17 @@ private: // Submit all transactions to the mempool and call ConsensusScriptChecks to add to the script // cache - should only be called after successful validation of all transactions in the package. - // The package may end up partially-submitted after size limitting; returns true if all + // The package may end up partially-submitted after size limiting; returns true if all // transactions are successfully added to the mempool, false otherwise. - bool FinalizePackage(const ATMPArgs& args, std::vector<Workspace>& workspaces, PackageValidationState& package_state, - std::map<const uint256, const MempoolAcceptResult>& results) + bool SubmitPackage(const ATMPArgs& args, std::vector<Workspace>& workspaces, PackageValidationState& package_state, + std::map<const uint256, const MempoolAcceptResult>& results) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); // Compare a package's feerate against minimum allowed. - bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs) + bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_pool.cs) { + AssertLockHeld(::cs_main); + AssertLockHeld(m_pool.cs); CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size); if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) { return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee)); @@ -643,6 +667,8 @@ private: bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) { + AssertLockHeld(cs_main); + AssertLockHeld(m_pool.cs); const CTransactionRef& ptx = ws.m_ptx; const CTransaction& tx = *ws.m_ptx; const uint256& hash = ws.m_hash; @@ -943,6 +969,8 @@ bool MemPoolAccept::PackageMempoolChecks(const std::vector<CTransactionRef>& txn bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws) { + AssertLockHeld(cs_main); + AssertLockHeld(m_pool.cs); const CTransaction& tx = *ws.m_ptx; TxValidationState& state = ws.m_state; @@ -969,6 +997,8 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws) bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws) { + AssertLockHeld(cs_main); + AssertLockHeld(m_pool.cs); const CTransaction& tx = *ws.m_ptx; const uint256& hash = ws.m_hash; TxValidationState& state = ws.m_state; @@ -1001,6 +1031,8 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws) bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws) { + AssertLockHeld(cs_main); + AssertLockHeld(m_pool.cs); const CTransaction& tx = *ws.m_ptx; const uint256& hash = ws.m_hash; TxValidationState& state = ws.m_state; @@ -1043,12 +1075,17 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws) return true; } -bool MemPoolAccept::FinalizePackage(const ATMPArgs& args, std::vector<Workspace>& workspaces, - PackageValidationState& package_state, - std::map<const uint256, const MempoolAcceptResult>& results) +bool MemPoolAccept::SubmitPackage(const ATMPArgs& args, std::vector<Workspace>& workspaces, + PackageValidationState& package_state, + std::map<const uint256, const MempoolAcceptResult>& results) { AssertLockHeld(cs_main); AssertLockHeld(m_pool.cs); + // Sanity check: none of the transactions should be in the mempool, and none of the transactions + // should have a same-txid-different-witness equivalent in the mempool. + assert(std::all_of(workspaces.cbegin(), workspaces.cend(), [this](const auto& ws){ + return !m_pool.exists(GenTxid::Txid(ws.m_ptx->GetHash())); })); + bool all_submitted = true; // ConsensusScriptChecks adds to the script cache and is therefore consensus-critical; // CheckInputsFromMempoolAndCache asserts that transactions only spend coins available from the @@ -1058,18 +1095,24 @@ bool MemPoolAccept::FinalizePackage(const ATMPArgs& args, std::vector<Workspace> if (!ConsensusScriptChecks(args, ws)) { results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state)); // Since PolicyScriptChecks() passed, this should never fail. - all_submitted = Assume(false); + all_submitted = false; + package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR, + strprintf("BUG! PolicyScriptChecks succeeded but ConsensusScriptChecks failed: %s", + ws.m_ptx->GetHash().ToString())); } // Re-calculate mempool ancestors to call addUnchecked(). They may have changed since the // last calculation done in PreChecks, since package ancestors have already been submitted. - std::string err_string; + std::string unused_err_string; if(!m_pool.CalculateMemPoolAncestors(*ws.m_entry, ws.m_ancestors, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants, - m_limit_descendant_size, err_string)) { + m_limit_descendant_size, unused_err_string)) { results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state)); // Since PreChecks() and PackageMempoolChecks() both enforce limits, this should never fail. - all_submitted = Assume(false); + all_submitted = false; + package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR, + strprintf("BUG! Mempool ancestors or descendants were underestimated: %s", + ws.m_ptx->GetHash().ToString())); } // If we call LimitMempoolSize() for each individual Finalize(), the mempool will not take // the transaction's descendant feerate into account because it hasn't seen them yet. Also, @@ -1079,7 +1122,9 @@ bool MemPoolAccept::FinalizePackage(const ATMPArgs& args, std::vector<Workspace> if (!Finalize(args, ws)) { results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state)); // Since LimitMempoolSize() won't be called, this should never fail. - all_submitted = Assume(false); + all_submitted = false; + package_state.Invalid(PackageValidationResult::PCKG_MEMPOOL_ERROR, + strprintf("BUG! Adding to mempool failed: %s", ws.m_ptx->GetHash().ToString())); } } @@ -1088,7 +1133,6 @@ bool MemPoolAccept::FinalizePackage(const ATMPArgs& args, std::vector<Workspace> LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip(), gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetIntArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); - if (!all_submitted) return false; // Find the wtxids of the transactions that made it into the mempool. Allow partial submission, // but don't report success unless they all made it into the mempool. @@ -1193,8 +1237,8 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std:: if (args.m_test_accept) return PackageMempoolAcceptResult(package_state, std::move(results)); - if (!FinalizePackage(args, workspaces, package_state, results)) { - package_state.Invalid(PackageValidationResult::PCKG_TX, "submission failed"); + if (!SubmitPackage(args, workspaces, package_state, results)) { + // PackageValidationState filled in by SubmitPackage(). return PackageMempoolAcceptResult(package_state, std::move(results)); } @@ -1219,11 +1263,13 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, return PackageMempoolAcceptResult(package_state, {}); } - const auto& child = package[package.size() - 1]; + // IsChildWithParents() guarantees the package is > 1 transactions. + assert(package.size() > 1); // The package must be 1 child with all of its unconfirmed parents. The package is expected to // be sorted, so the last transaction is the child. + const auto& child = package.back(); std::unordered_set<uint256, SaltedTxidHasher> unconfirmed_parent_txids; - std::transform(package.cbegin(), package.end() - 1, + std::transform(package.cbegin(), package.cend() - 1, std::inserter(unconfirmed_parent_txids, unconfirmed_parent_txids.end()), [](const auto& tx) { return tx->GetHash(); }); @@ -1255,10 +1301,14 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, LOCK(m_pool.cs); std::map<const uint256, const MempoolAcceptResult> results; - // As node operators are free to set their mempool policies however they please, it's possible - // for package transaction(s) to already be in the mempool, and we don't want to reject the - // entire package in that case (as that could be a censorship vector). Filter the transactions - // that are already in mempool and add their information to results, since we already have them. + // Node operators are free to set their mempool policies however they please, nodes may receive + // transactions in different orders, and malicious counterparties may try to take advantage of + // policy differences to pin or delay propagation of transactions. As such, it's possible for + // some package transaction(s) to already be in the mempool, and we don't want to reject the + // entire package in that case (as that could be a censorship vector). De-duplicate the + // transactions that are already in the mempool, and only call AcceptMultipleTransactions() with + // the new transactions. This ensures we don't double-count transaction counts and sizes when + // checking ancestor/descendant limits, or double-count transaction fees for fee-related policy. std::vector<CTransactionRef> txns_new; for (const auto& tx : package) { const auto& wtxid = tx->GetWitnessHash(); @@ -1279,9 +1329,10 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, // transaction for the mempool one. Note that we are ignoring the validity of the // package transaction passed in. // TODO: allow witness replacement in packages. - auto iter = m_pool.GetIter(wtxid); + auto iter = m_pool.GetIter(txid); assert(iter != std::nullopt); - results.emplace(txid, MempoolAcceptResult::MempoolTx(iter.value()->GetTxSize(), iter.value()->GetFee())); + // Provide the wtxid of the mempool tx so that the caller can look it up in the mempool. + results.emplace(wtxid, MempoolAcceptResult::MempoolTxDifferentWitness(iter.value()->GetTx().GetWitnessHash())); } else { // Transaction does not already exist in the mempool. txns_new.push_back(tx); @@ -1303,8 +1354,9 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTransactionRef& tx, int64_t accept_time, bool bypass_limits, bool test_accept) - EXCLUSIVE_LOCKS_REQUIRED(cs_main) + EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); const CChainParams& chainparams{active_chainstate.m_params}; assert(active_chainstate.GetMempool() != nullptr); CTxMemPool& pool{*active_chainstate.GetMempool()}; @@ -1348,12 +1400,12 @@ PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTx }(); // Uncache coins pertaining to transactions that were not submitted to the mempool. - // Ensure the coins cache is still within limits. if (test_accept || result.m_state.IsInvalid()) { for (const COutPoint& hashTx : coins_to_uncache) { active_chainstate.CoinsTip().Uncache(hashTx); } } + // Ensure the coins cache is still within limits. BlockValidationState state_dummy; active_chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC); return result; @@ -1382,6 +1434,7 @@ CoinsViews::CoinsViews( void CoinsViews::InitCache() { + AssertLockHeld(::cs_main); m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview); } @@ -1412,6 +1465,7 @@ void CChainState::InitCoinsDB( void CChainState::InitCoinsCache(size_t cache_size_bytes) { + AssertLockHeld(::cs_main); assert(m_coins_views != nullptr); m_coinstip_cache_size_bytes = cache_size_bytes; m_coins_views->InitCache(); @@ -1485,6 +1539,7 @@ void CChainState::CheckForkWarningConditions() // Called both upon regular invalid block discovery *and* InvalidateBlock void CChainState::InvalidChainFound(CBlockIndex* pindexNew) { + AssertLockHeld(cs_main); if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) { m_chainman.m_best_invalid = pindexNew; } @@ -1507,10 +1562,11 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew) // which does its own setBlockIndexCandidates management. void CChainState::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) { + AssertLockHeld(cs_main); if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { pindex->nStatus |= BLOCK_FAILED_VALID; m_chainman.m_failed_blocks.insert(pindex); - setDirtyBlockIndex.insert(pindex); + m_blockman.m_dirty_blockindex.insert(pindex); setBlockIndexCandidates.erase(pindex); InvalidChainFound(pindex); } @@ -1748,8 +1804,9 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI error("DisconnectBlock(): transaction and undo data inconsistent"); return DISCONNECT_FAILED; } - for (unsigned int j = tx.vin.size(); j-- > 0;) { - const COutPoint &out = tx.vin[j].prevout; + for (unsigned int j = tx.vin.size(); j > 0;) { + --j; + const COutPoint& out = tx.vin[j].prevout; int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out); if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED; fClean = fClean && res != DISCONNECT_UNCLEAN; @@ -2009,9 +2066,8 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, // another edge case to deal with. // testnet3 has no blocks before the BIP34 height with indicated heights - // post BIP34 before approximately height 486,000,000 and presumably will - // be reset before it reaches block 1,983,702 and starts doing unnecessary - // BIP30 checking again. + // post BIP34 before approximately height 486,000,000. After block + // 1,983,702 testnet3 starts doing unnecessary BIP30 checking again. assert(pindex->pprev); CBlockIndex* pindexBIP34height = pindex->pprev->GetAncestor(m_params.GetConsensus().BIP34Height); //Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond. @@ -2144,13 +2200,13 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, if (fJustCheck) return true; - if (!WriteUndoDataForBlock(blockundo, state, pindex, m_params)) { + if (!m_blockman.WriteUndoDataForBlock(blockundo, state, pindex, m_params)) { return false; } if (!pindex->IsValid(BLOCK_VALID_SCRIPTS)) { pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); - setDirtyBlockIndex.insert(pindex); + m_blockman.m_dirty_blockindex.insert(pindex); } assert(pindex->phashBlock); @@ -2174,6 +2230,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, CoinsCacheSizeState CChainState::GetCoinsCacheSizeState() { + AssertLockHeld(::cs_main); return this->GetCoinsCacheSizeState( m_coinstip_cache_size_bytes, gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); @@ -2183,10 +2240,11 @@ CoinsCacheSizeState CChainState::GetCoinsCacheSizeState( size_t max_coins_cache_size_bytes, size_t max_mempool_size_bytes) { + AssertLockHeld(::cs_main); const int64_t nMempoolUsage = m_mempool ? m_mempool->DynamicMemoryUsage() : 0; int64_t cacheSize = CoinsTip().DynamicMemoryUsage(); int64_t nTotalSpace = - max_coins_cache_size_bytes + std::max<int64_t>(max_mempool_size_bytes - nMempoolUsage, 0); + max_coins_cache_size_bytes + std::max<int64_t>(int64_t(max_mempool_size_bytes) - nMempoolUsage, 0); //! No need to periodic flush if at least this much space still available. static constexpr int64_t MAX_BLOCK_COINSDB_USAGE_BYTES = 10 * 1024 * 1024; // 10MB @@ -2223,8 +2281,8 @@ bool CChainState::FlushStateToDisk( bool fDoFullFlush = false; CoinsCacheSizeState cache_state = GetCoinsCacheSizeState(); - LOCK(cs_LastBlockFile); - if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) { + LOCK(m_blockman.cs_LastBlockFile); + if (fPruneMode && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && !fReindex) { // make sure we don't prune above the blockfilterindexes bestblocks // pruning is height-based int last_prune = m_chain.Height(); // last height we can prune @@ -2240,7 +2298,7 @@ bool CChainState::FlushStateToDisk( LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", BCLog::BENCH); m_blockman.FindFilesToPrune(setFilesToPrune, m_params.PruneAfterHeight(), m_chain.Height(), last_prune, IsInitialBlockDownload()); - fCheckForPruning = false; + m_blockman.m_check_for_pruning = false; } if (!setFilesToPrune.empty()) { fFlushForPrune = true; @@ -2278,26 +2336,14 @@ bool CChainState::FlushStateToDisk( LOG_TIME_MILLIS_WITH_CATEGORY("write block and undo data to disk", BCLog::BENCH); // First make sure all block and undo data is flushed to disk. - FlushBlockFile(); + m_blockman.FlushBlockFile(); } // Then update all block file information (which may refer to block and undo files). { LOG_TIME_MILLIS_WITH_CATEGORY("write block index to disk", BCLog::BENCH); - std::vector<std::pair<int, const CBlockFileInfo*> > vFiles; - vFiles.reserve(setDirtyFileInfo.size()); - for (std::set<int>::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) { - vFiles.push_back(std::make_pair(*it, &vinfoBlockFile[*it])); - setDirtyFileInfo.erase(it++); - } - std::vector<const CBlockIndex*> vBlocks; - vBlocks.reserve(setDirtyBlockIndex.size()); - for (std::set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) { - vBlocks.push_back(*it); - setDirtyBlockIndex.erase(it++); - } - if (!m_blockman.m_block_tree_db->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { + if (!m_blockman.WriteBlockIndexDB()) { return AbortNode(state, "Failed to write to block index database"); } } @@ -2357,7 +2403,7 @@ void CChainState::ForceFlushStateToDisk() void CChainState::PruneAndFlush() { BlockValidationState state; - fCheckForPruning = true; + m_blockman.m_check_for_pruning = true; if (!this->FlushStateToDisk(state, FlushStateMode::NONE)) { LogPrintf("%s: failed to flush state (%s)\n", __func__, state.ToString()); } @@ -2403,6 +2449,7 @@ static void UpdateTipLog( void CChainState::UpdateTip(const CBlockIndex* pindexNew) { + AssertLockHeld(::cs_main); const auto& coins_tip = this->CoinsTip(); // The remainder of the function isn't relevant if we are not acting on @@ -2626,7 +2673,9 @@ bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew * Return the tip of the chain with the most work in it, that isn't * known to be invalid (it's however far from certain to be valid). */ -CBlockIndex* CChainState::FindMostWorkChain() { +CBlockIndex* CChainState::FindMostWorkChain() +{ + AssertLockHeld(::cs_main); do { CBlockIndex *pindexNew = nullptr; @@ -2824,17 +2873,19 @@ static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) { bool CChainState::ActivateBestChain(BlockValidationState& state, std::shared_ptr<const CBlock> pblock) { + AssertLockNotHeld(m_chainstate_mutex); + // Note that while we're often called here from ProcessNewBlock, this is // far from a guarantee. Things in the P2P/RPC will often end up calling // us in the middle of ProcessNewBlock - do not assume pblock is set // sanely for performance or correctness! - AssertLockNotHeld(cs_main); + AssertLockNotHeld(::cs_main); // ABC maintains a fair degree of expensive-to-calculate internal state // because this function periodically releases cs_main so that it does not lock up other threads for too long // during large connects - and to allow for e.g. the callback queue to drain - // we use m_cs_chainstate to enforce mutual exclusion so that only one caller may execute this function at a time - LOCK(m_cs_chainstate); + // we use m_chainstate_mutex to enforce mutual exclusion so that only one caller may execute this function at a time + LOCK(m_chainstate_mutex); CBlockIndex *pindexMostWork = nullptr; CBlockIndex *pindexNewTip = nullptr; @@ -2924,6 +2975,8 @@ bool CChainState::ActivateBestChain(BlockValidationState& state, std::shared_ptr bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) { + AssertLockNotHeld(m_chainstate_mutex); + AssertLockNotHeld(::cs_main); { LOCK(cs_main); if (pindex->nChainWork < m_chain.Tip()->nChainWork) { @@ -2953,6 +3006,9 @@ bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex) { + AssertLockNotHeld(m_chainstate_mutex); + AssertLockNotHeld(::cs_main); + // Genesis block can't be invalidated assert(pindex); if (pindex->nHeight == 0) return false; @@ -2964,7 +3020,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind // We do not allow ActivateBestChain() to run while InvalidateBlock() is // running, as that could cause the tip to change while we disconnect // blocks. - LOCK(m_cs_chainstate); + LOCK(m_chainstate_mutex); // We'll be acquiring and releasing cs_main below, to allow the validation // callbacks to run. However, we should keep the block index in a @@ -3027,14 +3083,14 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind // are no blocks that meet the "have data and are not invalid per // nStatus" criteria for inclusion in setBlockIndexCandidates). invalid_walk_tip->nStatus |= BLOCK_FAILED_VALID; - setDirtyBlockIndex.insert(invalid_walk_tip); + m_blockman.m_dirty_blockindex.insert(invalid_walk_tip); setBlockIndexCandidates.erase(invalid_walk_tip); setBlockIndexCandidates.insert(invalid_walk_tip->pprev); if (invalid_walk_tip->pprev == to_mark_failed && (to_mark_failed->nStatus & BLOCK_FAILED_VALID)) { // We only want to mark the last disconnected block as BLOCK_FAILED_VALID; its children // need to be BLOCK_FAILED_CHILD instead. to_mark_failed->nStatus = (to_mark_failed->nStatus ^ BLOCK_FAILED_VALID) | BLOCK_FAILED_CHILD; - setDirtyBlockIndex.insert(to_mark_failed); + m_blockman.m_dirty_blockindex.insert(to_mark_failed); } // Add any equal or more work headers to setBlockIndexCandidates @@ -3064,7 +3120,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind // Mark pindex (or the last disconnected block) as invalid, even when it never was in the main chain to_mark_failed->nStatus |= BLOCK_FAILED_VALID; - setDirtyBlockIndex.insert(to_mark_failed); + m_blockman.m_dirty_blockindex.insert(to_mark_failed); setBlockIndexCandidates.erase(to_mark_failed); m_chainman.m_failed_blocks.insert(to_mark_failed); @@ -3103,7 +3159,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { while (it != m_blockman.m_block_index.end()) { if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) { it->second->nStatus &= ~BLOCK_FAILED_MASK; - setDirtyBlockIndex.insert(it->second); + m_blockman.m_dirty_blockindex.insert(it->second); if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && setBlockIndexCandidates.value_comp()(m_chain.Tip(), it->second)) { setBlockIndexCandidates.insert(it->second); } @@ -3120,52 +3176,17 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { while (pindex != nullptr) { if (pindex->nStatus & BLOCK_FAILED_MASK) { pindex->nStatus &= ~BLOCK_FAILED_MASK; - setDirtyBlockIndex.insert(pindex); + m_blockman.m_dirty_blockindex.insert(pindex); m_chainman.m_failed_blocks.erase(pindex); } pindex = pindex->pprev; } } -CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block) -{ - AssertLockHeld(cs_main); - - // Check for duplicate - uint256 hash = block.GetHash(); - BlockMap::iterator it = m_block_index.find(hash); - if (it != m_block_index.end()) - return it->second; - - // Construct new block index object - CBlockIndex* pindexNew = new CBlockIndex(block); - // We assign the sequence id to blocks only when the full data is available, - // to avoid miners withholding blocks but broadcasting headers, to get a - // competitive advantage. - pindexNew->nSequenceId = 0; - BlockMap::iterator mi = m_block_index.insert(std::make_pair(hash, pindexNew)).first; - pindexNew->phashBlock = &((*mi).first); - BlockMap::iterator miPrev = m_block_index.find(block.hashPrevBlock); - if (miPrev != m_block_index.end()) - { - pindexNew->pprev = (*miPrev).second; - pindexNew->nHeight = pindexNew->pprev->nHeight + 1; - pindexNew->BuildSkip(); - } - pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime); - pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); - pindexNew->RaiseValidity(BLOCK_VALID_TREE); - if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork) - pindexBestHeader = pindexNew; - - setDirtyBlockIndex.insert(pindexNew); - - return pindexNew; -} - /** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos) { + AssertLockHeld(cs_main); pindexNew->nTx = block.vtx.size(); pindexNew->nChainTx = 0; pindexNew->nFile = pos.nFile; @@ -3176,7 +3197,7 @@ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pi pindexNew->nStatus |= BLOCK_OPT_WITNESS; } pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS); - setDirtyBlockIndex.insert(pindexNew); + m_blockman.m_dirty_blockindex.insert(pindexNew); if (pindexNew->pprev == nullptr || pindexNew->pprev->HaveTxsDownloaded()) { // If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS. @@ -3329,21 +3350,6 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc return commitment; } -CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data) -{ - const MapCheckpoints& checkpoints = data.mapCheckpoints; - - for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints)) - { - const uint256& hash = i.second; - CBlockIndex* pindex = LookupBlockIndex(hash); - if (pindex) { - return pindex; - } - } - return nullptr; -} - /** Context-dependent validity checks. * By "context", we mean only the previous block headers, but not the UTXO * set; UTXO-related validity checks are done in ConnectBlock(). @@ -3353,8 +3359,9 @@ CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data) * in ConnectBlock(). * Note that -reindex-chainstate skips the validation that happens here! */ -static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, BlockManager& blockman, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); assert(pindexPrev != nullptr); const int nHeight = pindexPrev->nHeight + 1; @@ -3553,7 +3560,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida CBlockIndex* invalid_walk = pindexPrev; while (invalid_walk != failedit) { invalid_walk->nStatus |= BLOCK_FAILED_CHILD; - setDirtyBlockIndex.insert(invalid_walk); + m_blockman.m_dirty_blockindex.insert(invalid_walk); invalid_walk = invalid_walk->pprev; } LogPrint(BCLog::VALIDATION, "%s: %s prev block invalid\n", __func__, hash.ToString()); @@ -3591,7 +3598,10 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& } if (NotifyHeaderTip(ActiveChainstate())) { if (ActiveChainstate().IsInitialBlockDownload() && ppindex && *ppindex) { - LogPrintf("Synchronizing blockheaders, height: %d (~%.2f%%)\n", (*ppindex)->nHeight, 100.0/((*ppindex)->nHeight+(GetAdjustedTime() - (*ppindex)->GetBlockTime()) / Params().GetConsensus().nPowTargetSpacing) * (*ppindex)->nHeight); + const CBlockIndex& last_accepted{**ppindex}; + const int64_t blocks_left{(GetTime() - last_accepted.GetBlockTime()) / chainparams.GetConsensus().nPowTargetSpacing}; + const double progress{100.0 * last_accepted.nHeight / (last_accepted.nHeight + blocks_left)}; + LogPrintf("Synchronizing blockheaders, height: %d (~%.2f%%)\n", last_accepted.nHeight, progress); } } return true; @@ -3624,7 +3634,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block // blocks which are too close in height to the tip. Apply this test // regardless of whether pruning is enabled; it should generally be safe to // not process unrequested blocks. - bool fTooFarAhead = (pindex->nHeight > int(m_chain.Height() + MIN_BLOCKS_TO_KEEP)); + bool fTooFarAhead{pindex->nHeight > m_chain.Height() + int(MIN_BLOCKS_TO_KEEP)}; // TODO: Decouple this function from the block download logic by removing fRequested // This requires some new chain data structure to efficiently look up if a @@ -3651,7 +3661,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block !ContextualCheckBlock(block, state, m_params.GetConsensus(), pindex->pprev)) { if (state.IsInvalid() && state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { pindex->nStatus |= BLOCK_FAILED_VALID; - setDirtyBlockIndex.insert(pindex); + m_blockman.m_dirty_blockindex.insert(pindex); } return error("%s: %s", __func__, state.ToString()); } @@ -3664,7 +3674,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block // Write block to history file if (fNewBlock) *fNewBlock = true; try { - FlatFilePos blockPos = SaveBlockToDisk(block, pindex->nHeight, m_chain, m_params, dbp); + FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, pindex->nHeight, m_chain, m_params, dbp)}; if (blockPos.IsNull()) { state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__)); return false; @@ -3722,6 +3732,7 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s MempoolAcceptResult ChainstateManager::ProcessTransaction(const CTransactionRef& tx, bool test_accept) { + AssertLockHeld(cs_main); CChainState& active_chainstate = ActiveChainstate(); if (!active_chainstate.GetMempool()) { TxValidationState state; @@ -3765,67 +3776,6 @@ bool TestBlockValidity(BlockValidationState& state, return true; } -/** - * BLOCK PRUNING CODE - */ - -void BlockManager::PruneOneBlockFile(const int fileNumber) -{ - AssertLockHeld(cs_main); - LOCK(cs_LastBlockFile); - - for (const auto& entry : m_block_index) { - CBlockIndex* pindex = entry.second; - if (pindex->nFile == fileNumber) { - pindex->nStatus &= ~BLOCK_HAVE_DATA; - pindex->nStatus &= ~BLOCK_HAVE_UNDO; - pindex->nFile = 0; - pindex->nDataPos = 0; - pindex->nUndoPos = 0; - setDirtyBlockIndex.insert(pindex); - - // Prune from m_blocks_unlinked -- any block we prune would have - // to be downloaded again in order to consider its chain, at which - // point it would be considered as a candidate for - // m_blocks_unlinked or setBlockIndexCandidates. - auto range = m_blocks_unlinked.equal_range(pindex->pprev); - while (range.first != range.second) { - std::multimap<CBlockIndex *, CBlockIndex *>::iterator _it = range.first; - range.first++; - if (_it->second == pindex) { - m_blocks_unlinked.erase(_it); - } - } - } - } - - vinfoBlockFile[fileNumber].SetNull(); - setDirtyFileInfo.insert(fileNumber); -} - -void BlockManager::FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height) -{ - assert(fPruneMode && nManualPruneHeight > 0); - - LOCK2(cs_main, cs_LastBlockFile); - if (chain_tip_height < 0) { - return; - } - - // last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip) - unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chain_tip_height - MIN_BLOCKS_TO_KEEP); - int count = 0; - for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { - if (vinfoBlockFile[fileNumber].nSize == 0 || vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) { - continue; - } - PruneOneBlockFile(fileNumber); - setFilesToPrune.insert(fileNumber); - count++; - } - LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", nLastBlockWeCanPrune, count); -} - /* This function is called from the RPC code for pruneblockchain */ void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight) { @@ -3836,259 +3786,6 @@ void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeigh } } -void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd) -{ - LOCK2(cs_main, cs_LastBlockFile); - if (chain_tip_height < 0 || nPruneTarget == 0) { - return; - } - if ((uint64_t)chain_tip_height <= nPruneAfterHeight) { - return; - } - - unsigned int nLastBlockWeCanPrune = std::min(prune_height, chain_tip_height - static_cast<int>(MIN_BLOCKS_TO_KEEP)); - uint64_t nCurrentUsage = CalculateCurrentUsage(); - // We don't check to prune until after we've allocated new space for files - // So we should leave a buffer under our target to account for another allocation - // before the next pruning. - uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE; - uint64_t nBytesToPrune; - int count = 0; - - if (nCurrentUsage + nBuffer >= nPruneTarget) { - // On a prune event, the chainstate DB is flushed. - // To avoid excessive prune events negating the benefit of high dbcache - // values, we should not prune too rapidly. - // So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon. - if (is_ibd) { - // Since this is only relevant during IBD, we use a fixed 10% - nBuffer += nPruneTarget / 10; - } - - for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { - nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize; - - if (vinfoBlockFile[fileNumber].nSize == 0) { - continue; - } - - if (nCurrentUsage + nBuffer < nPruneTarget) { // are we below our target? - break; - } - - // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning - if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) { - continue; - } - - PruneOneBlockFile(fileNumber); - // Queue up the files for removal - setFilesToPrune.insert(fileNumber); - nCurrentUsage -= nBytesToPrune; - count++; - } - } - - LogPrint(BCLog::PRUNE, "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n", - nPruneTarget/1024/1024, nCurrentUsage/1024/1024, - ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024, - nLastBlockWeCanPrune, count); -} - -CBlockIndex * BlockManager::InsertBlockIndex(const uint256& hash) -{ - AssertLockHeld(cs_main); - - if (hash.IsNull()) - return nullptr; - - // Return existing - BlockMap::iterator mi = m_block_index.find(hash); - if (mi != m_block_index.end()) - return (*mi).second; - - // Create new - CBlockIndex* pindexNew = new CBlockIndex(); - mi = m_block_index.insert(std::make_pair(hash, pindexNew)).first; - pindexNew->phashBlock = &((*mi).first); - - return pindexNew; -} - -bool BlockManager::LoadBlockIndex( - const Consensus::Params& consensus_params, - ChainstateManager& chainman) -{ - if (!m_block_tree_db->LoadBlockIndexGuts(consensus_params, [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); })) { - return false; - } - - // Calculate nChainWork - std::vector<std::pair<int, CBlockIndex*> > vSortedByHeight; - vSortedByHeight.reserve(m_block_index.size()); - for (const std::pair<const uint256, CBlockIndex*>& item : m_block_index) - { - CBlockIndex* pindex = item.second; - vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex)); - } - sort(vSortedByHeight.begin(), vSortedByHeight.end()); - - // Find start of assumed-valid region. - int first_assumed_valid_height = std::numeric_limits<int>::max(); - - for (const auto& [height, block] : vSortedByHeight) { - if (block->IsAssumedValid()) { - auto chainstates = chainman.GetAll(); - - // If we encounter an assumed-valid block index entry, ensure that we have - // one chainstate that tolerates assumed-valid entries and another that does - // not (i.e. the background validation chainstate), since assumed-valid - // entries should always be pending validation by a fully-validated chainstate. - auto any_chain = [&](auto fnc) { return std::any_of(chainstates.cbegin(), chainstates.cend(), fnc); }; - assert(any_chain([](auto chainstate) { return chainstate->reliesOnAssumedValid(); })); - assert(any_chain([](auto chainstate) { return !chainstate->reliesOnAssumedValid(); })); - - first_assumed_valid_height = height; - break; - } - } - - for (const std::pair<int, CBlockIndex*>& item : vSortedByHeight) - { - if (ShutdownRequested()) return false; - CBlockIndex* pindex = item.second; - pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); - pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime); - - // We can link the chain of blocks for which we've received transactions at some point, or - // blocks that are assumed-valid on the basis of snapshot load (see - // PopulateAndValidateSnapshot()). - // Pruned nodes may have deleted the block. - if (pindex->nTx > 0) { - if (pindex->pprev) { - if (pindex->pprev->nChainTx > 0) { - pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx; - } else { - pindex->nChainTx = 0; - m_blocks_unlinked.insert(std::make_pair(pindex->pprev, pindex)); - } - } else { - pindex->nChainTx = pindex->nTx; - } - } - if (!(pindex->nStatus & BLOCK_FAILED_MASK) && pindex->pprev && (pindex->pprev->nStatus & BLOCK_FAILED_MASK)) { - pindex->nStatus |= BLOCK_FAILED_CHILD; - setDirtyBlockIndex.insert(pindex); - } - if (pindex->IsAssumedValid() || - (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && - (pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))) { - - // Fill each chainstate's block candidate set. Only add assumed-valid - // blocks to the tip candidate set if the chainstate is allowed to rely on - // assumed-valid blocks. - // - // If all setBlockIndexCandidates contained the assumed-valid blocks, the - // background chainstate's ActivateBestChain() call would add assumed-valid - // blocks to the chain (based on how FindMostWorkChain() works). Obviously - // we don't want this since the purpose of the background validation chain - // is to validate assued-valid blocks. - // - // Note: This is considering all blocks whose height is greater or equal to - // the first assumed-valid block to be assumed-valid blocks, and excluding - // them from the background chainstate's setBlockIndexCandidates set. This - // does mean that some blocks which are not technically assumed-valid - // (later blocks on a fork beginning before the first assumed-valid block) - // might not get added to the the background chainstate, but this is ok, - // because they will still be attached to the active chainstate if they - // actually contain more work. - // - // Instad of this height-based approach, an earlier attempt was made at - // detecting "holistically" whether the block index under consideration - // relied on an assumed-valid ancestor, but this proved to be too slow to - // be practical. - for (CChainState* chainstate : chainman.GetAll()) { - if (chainstate->reliesOnAssumedValid() || - pindex->nHeight < first_assumed_valid_height) { - chainstate->setBlockIndexCandidates.insert(pindex); - } - } - } - if (pindex->nStatus & BLOCK_FAILED_MASK && (!chainman.m_best_invalid || pindex->nChainWork > chainman.m_best_invalid->nChainWork)) { - chainman.m_best_invalid = pindex; - } - if (pindex->pprev) - pindex->BuildSkip(); - if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == nullptr || CBlockIndexWorkComparator()(pindexBestHeader, pindex))) - pindexBestHeader = pindex; - } - - return true; -} - -void BlockManager::Unload() { - m_blocks_unlinked.clear(); - - for (const BlockMap::value_type& entry : m_block_index) { - delete entry.second; - } - - m_block_index.clear(); -} - -bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman) -{ - if (!LoadBlockIndex(::Params().GetConsensus(), chainman)) { - return false; - } - - // Load block file info - m_block_tree_db->ReadLastBlockFile(nLastBlockFile); - vinfoBlockFile.resize(nLastBlockFile + 1); - LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile); - for (int nFile = 0; nFile <= nLastBlockFile; nFile++) { - m_block_tree_db->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]); - } - LogPrintf("%s: last block file info: %s\n", __func__, vinfoBlockFile[nLastBlockFile].ToString()); - for (int nFile = nLastBlockFile + 1; true; nFile++) { - CBlockFileInfo info; - if (m_block_tree_db->ReadBlockFileInfo(nFile, info)) { - vinfoBlockFile.push_back(info); - } else { - break; - } - } - - // Check presence of blk files - LogPrintf("Checking all blk files are present...\n"); - std::set<int> setBlkDataFiles; - for (const std::pair<const uint256, CBlockIndex*>& item : m_block_index) { - CBlockIndex* pindex = item.second; - if (pindex->nStatus & BLOCK_HAVE_DATA) { - setBlkDataFiles.insert(pindex->nFile); - } - } - for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) - { - FlatFilePos pos(*it, 0); - if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) { - return false; - } - } - - // Check whether we have ever pruned block & undo files - m_block_tree_db->ReadFlag("prunedblockfiles", fHavePruned); - if (fHavePruned) - LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n"); - - // Check whether we need to continue reindexing - bool fReindexing = false; - m_block_tree_db->ReadReindexing(fReindexing); - if(fReindexing) fReindex = true; - - return true; -} - void CChainState::LoadMempool(const ArgsManager& args) { if (!m_mempool) return; @@ -4249,6 +3946,7 @@ bool CVerifyDB::VerifyDB( /** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */ bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs) { + AssertLockHeld(cs_main); // TODO: merge with ConnectBlock CBlock block; if (!ReadBlockFromDisk(block, pindex, m_params.GetConsensus())) { @@ -4352,7 +4050,9 @@ bool CChainState::NeedsRedownload() const return false; } -void CChainState::UnloadBlockIndex() { +void CChainState::UnloadBlockIndex() +{ + AssertLockHeld(::cs_main); nBlockSequenceId = 1; setBlockIndexCandidates.clear(); } @@ -4366,10 +4066,6 @@ void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman) chainman.Unload(); pindexBestHeader = nullptr; if (mempool) mempool->clear(); - vinfoBlockFile.clear(); - nLastBlockFile = 0; - setDirtyBlockIndex.clear(); - setDirtyFileInfo.clear(); g_versionbitscache.Clear(); for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { warningcache[b].clear(); @@ -4413,9 +4109,10 @@ bool CChainState::LoadGenesisBlock() try { const CBlock& block = m_params.GenesisBlock(); - FlatFilePos blockPos = SaveBlockToDisk(block, 0, m_chain, m_params, nullptr); - if (blockPos.IsNull()) + FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, 0, m_chain, m_params, nullptr)}; + if (blockPos.IsNull()) { return error("%s: writing genesis block to disk failed", __func__); + } CBlockIndex *pindex = m_blockman.AddToBlockIndex(block); ReceivedBlockTransactions(block, pindex, blockPos); } catch (const std::runtime_error& e) { @@ -4427,6 +4124,7 @@ bool CChainState::LoadGenesisBlock() void CChainState::LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp) { + AssertLockNotHeld(m_chainstate_mutex); // Map of disk positions for blocks with unknown parent (only used for reindex) static std::multimap<uint256, FlatFilePos> mapBlocksUnknownParent; int64_t nStart = GetTimeMillis(); @@ -4447,7 +4145,7 @@ void CChainState::LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp) // locate a header unsigned char buf[CMessageHeader::MESSAGE_START_SIZE]; blkdat.FindByte(m_params.MessageStart()[0]); - nRewind = blkdat.GetPos()+1; + nRewind = blkdat.GetPos() + 1; blkdat >> buf; if (memcmp(buf, m_params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE)) { continue; @@ -4767,6 +4465,7 @@ void CChainState::CheckBlockIndex() std::string CChainState::ToString() { + AssertLockHeld(::cs_main); CBlockIndex* tip = m_chain.Tip(); return strprintf("Chainstate [%s] @ height %d (%s)", m_from_snapshot_blockhash ? "snapshot" : "ibd", @@ -4775,6 +4474,7 @@ std::string CChainState::ToString() bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size) { + AssertLockHeld(::cs_main); if (coinstip_size == m_coinstip_cache_size_bytes && coinsdb_size == m_coinsdb_cache_size_bytes) { // Cache sizes are unchanged, no need to continue. @@ -4831,7 +4531,8 @@ bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mocka } uint64_t num; file >> num; - while (num--) { + while (num) { + --num; CTransactionRef tx; int64_t nTime; int64_t nFeeDelta; @@ -4998,6 +4699,7 @@ std::vector<CChainState*> ChainstateManager::GetAll() CChainState& ChainstateManager::InitializeChainstate( CTxMemPool* mempool, const std::optional<uint256>& snapshot_blockhash) { + AssertLockHeld(::cs_main); bool is_snapshot = snapshot_blockhash.has_value(); std::unique_ptr<CChainState>& to_modify = is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate; @@ -5253,7 +4955,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( // about the snapshot_chainstate. CCoinsViewDB* snapshot_coinsdb = WITH_LOCK(::cs_main, return &snapshot_chainstate.CoinsDB()); - if (!GetUTXOStats(snapshot_coinsdb, WITH_LOCK(::cs_main, return std::ref(m_blockman)), stats, breakpoint_fnc)) { + if (!GetUTXOStats(snapshot_coinsdb, m_blockman, stats, breakpoint_fnc)) { LogPrintf("[snapshot] failed to generate coins stats\n"); return false; } @@ -5303,7 +5005,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( index->nStatus |= BLOCK_OPT_WITNESS; } - setDirtyBlockIndex.insert(index); + m_blockman.m_dirty_blockindex.insert(index); // Changes to the block index will be flushed to disk after this call // returns in `ActivateSnapshot()`, when `MaybeRebalanceCaches()` is // called, since we've added a snapshot chainstate and therefore will @@ -5335,6 +5037,7 @@ bool ChainstateManager::IsSnapshotActive() const void ChainstateManager::Unload() { + AssertLockHeld(::cs_main); for (CChainState* chainstate : this->GetAll()) { chainstate->m_chain.SetTip(nullptr); chainstate->UnloadBlockIndex(); @@ -5356,6 +5059,7 @@ void ChainstateManager::Reset() void ChainstateManager::MaybeRebalanceCaches() { + AssertLockHeld(::cs_main); if (m_ibd_chainstate && !m_snapshot_chainstate) { LogPrintf("[snapshot] allocating all cache to the IBD chainstate\n"); // Allocate everything to the IBD chainstate. diff --git a/src/validation.h b/src/validation.h index 160fffd048..968f62aa9a 100644 --- a/src/validation.h +++ b/src/validation.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -15,6 +15,7 @@ #include <chain.h> #include <consensus/amount.h> #include <fs.h> +#include <node/blockstorage.h> #include <policy/feerate.h> #include <policy/packages.h> #include <script/script_error.h> @@ -40,15 +41,16 @@ class CChainState; class CBlockTreeDB; class CChainParams; -struct CCheckpointData; class CTxMemPool; class ChainstateManager; -class SnapshotMetadata; struct ChainTxData; struct DisconnectedBlockTransactions; struct PrecomputedTransactionData; struct LockPoints; struct AssumeutxoData; +namespace node { +class SnapshotMetadata; +} // namespace node /** Default for -minrelaytxfee, minimum relay fee for transactions */ static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000; @@ -107,7 +109,6 @@ enum class SynchronizationState { }; extern RecursiveMutex cs_main; -typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap; extern Mutex g_best_block_mutex; extern std::condition_variable g_best_block_cv; /** Used to notify getblocktemplate RPC of new tips. */ @@ -162,8 +163,12 @@ struct MempoolAcceptResult { VALID, //!> Fully validated, valid. INVALID, //!> Invalid. MEMPOOL_ENTRY, //!> Valid, transaction was already in the mempool. + DIFFERENT_WITNESS, //!> Not validated. A same-txid-different-witness tx (see m_other_wtxid) already exists in the mempool and was not replaced. }; + /** Result type. Present in all MempoolAcceptResults. */ const ResultType m_result_type; + + /** Contains information about why the transaction failed. */ const TxValidationState m_state; // The following fields are only present when m_result_type = ResultType::VALID or MEMPOOL_ENTRY @@ -174,6 +179,10 @@ struct MempoolAcceptResult { /** Raw base fees in satoshis. */ const std::optional<CAmount> m_base_fees; + // The following field is only present when m_result_type = ResultType::DIFFERENT_WITNESS + /** The wtxid of the transaction in the mempool which has the same txid but different witness. */ + const std::optional<uint256> m_other_wtxid; + static MempoolAcceptResult Failure(TxValidationState state) { return MempoolAcceptResult(state); } @@ -186,6 +195,10 @@ struct MempoolAcceptResult { return MempoolAcceptResult(vsize, fees); } + static MempoolAcceptResult MempoolTxDifferentWitness(const uint256& other_wtxid) { + return MempoolAcceptResult(other_wtxid); + } + // Private constructors. Use static methods MempoolAcceptResult::Success, etc. to construct. private: /** Constructor for failure case */ @@ -202,6 +215,10 @@ private: /** Constructor for already-in-mempool case. It wouldn't replace any transactions. */ explicit MempoolAcceptResult(int64_t vsize, CAmount fees) : m_result_type(ResultType::MEMPOOL_ENTRY), m_vsize{vsize}, m_base_fees(fees) {} + + /** Constructor for witness-swapped case. */ + explicit MempoolAcceptResult(const uint256& other_wtxid) + : m_result_type(ResultType::DIFFERENT_WITNESS), m_other_wtxid(other_wtxid) {} }; /** @@ -211,7 +228,7 @@ struct PackageMempoolAcceptResult { const PackageValidationState m_state; /** - * Map from (w)txid to finished MempoolAcceptResults. The client is responsible + * Map from wtxid to finished MempoolAcceptResults. The client is responsible * for keeping track of the transaction objects themselves. If a result is not * present, it means validation was unfinished for that transaction. If there * was a package-wide error (see result in m_state), m_tx_results will be empty. @@ -381,85 +398,6 @@ enum class FlushStateMode { ALWAYS }; -struct CBlockIndexWorkComparator -{ - bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const; -}; - -/** - * Maintains a tree of blocks (stored in `m_block_index`) which is consulted - * to determine where the most-work tip is. - * - * This data is used mostly in `CChainState` - information about, e.g., - * candidate tips is not maintained here. - */ -class BlockManager -{ - friend CChainState; - -private: - /* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */ - void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height); - - /** - * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target. - * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new - * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex - * (which in this case means the blockchain must be re-downloaded.) - * - * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set. - * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.) - * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest). - * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip. - * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files. - * A db flag records the fact that at least some block files have been pruned. - * - * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned - */ - void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd); - -public: - BlockMap m_block_index GUARDED_BY(cs_main); - - /** - * All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions. - * Pruned nodes may have entries where B is missing data. - */ - std::multimap<CBlockIndex*, CBlockIndex*> m_blocks_unlinked; - - std::unique_ptr<CBlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main); - - bool LoadBlockIndexDB(ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - - /** - * Load the blocktree off disk and into memory. Populate certain metadata - * per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral - * collections like setDirtyBlockIndex. - */ - bool LoadBlockIndex( - const Consensus::Params& consensus_params, - ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - /** Clear all data members. */ - void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - /** Create a new block index entry for a given block hash */ - CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - //! Mark one block file as pruned (modify associated database entries) - void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - CBlockIndex* LookupBlockIndex(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - //! Returns last CBlockIndex* that is a checkpoint - CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - ~BlockManager() { - Unload(); - } -}; - /** * A convenience class for constructing the CCoinsView* hierarchy used * to facilitate access to the UTXO set. @@ -533,10 +471,11 @@ protected: arith_uint256 nLastPreciousChainwork = 0; /** - * the ChainState CriticalSection - * A lock that must be held when modifying this ChainState - held in ActivateBestChain() + * The ChainState Mutex + * A lock that must be held when modifying this ChainState - held in ActivateBestChain() and + * InvalidateBlock() */ - RecursiveMutex m_cs_chainstate; + Mutex m_chainstate_mutex; /** * Whether this chainstate is undergoing initial block download. @@ -556,7 +495,7 @@ protected: public: //! Reference to a BlockManager instance which itself is shared across all //! CChainState instances. - BlockManager& m_blockman; + node::BlockManager& m_blockman; /** Chain parameters for this chainstate */ const CChainParams& m_params; @@ -568,7 +507,7 @@ public: explicit CChainState( CTxMemPool* mempool, - BlockManager& blockman, + node::BlockManager& blockman, ChainstateManager& chainman, std::optional<uint256> from_snapshot_blockhash = std::nullopt); @@ -590,7 +529,9 @@ public: //! @returns whether or not the CoinsViews object has been fully initialized and we can //! safely flush this object to disk. - bool CanFlushToDisk() const EXCLUSIVE_LOCKS_REQUIRED(cs_main) { + bool CanFlushToDisk() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) + { + AssertLockHeld(::cs_main); return m_coins_views && m_coins_views->m_cacheview; } @@ -615,18 +556,20 @@ public: * chainstates) and as good as our current tip or better. Entries may be failed, * though, and pruning nodes may be missing the data for the block. */ - std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates; + std::set<CBlockIndex*, node::CBlockIndexWorkComparator> setBlockIndexCandidates; //! @returns A reference to the in-memory cache of the UTXO set. - CCoinsViewCache& CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(cs_main) + CCoinsViewCache& CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); assert(m_coins_views->m_cacheview); return *m_coins_views->m_cacheview.get(); } //! @returns A reference to the on-disk UTXO set database. - CCoinsViewDB& CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(cs_main) + CCoinsViewDB& CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); return m_coins_views->m_dbview; } @@ -638,8 +581,9 @@ public: //! @returns A reference to a wrapped view of the in-memory UTXO set that //! handles disk read errors gracefully. - CCoinsViewErrorCatcher& CoinsErrorCatcher() EXCLUSIVE_LOCKS_REQUIRED(cs_main) + CCoinsViewErrorCatcher& CoinsErrorCatcher() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); return m_coins_views->m_catcherview; } @@ -658,7 +602,8 @@ public: EXCLUSIVE_LOCKS_REQUIRED(::cs_main); /** Import blocks from an external file */ - void LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp = nullptr); + void LoadExternalBlockFile(FILE* fileIn, FlatFilePos* dbp = nullptr) + EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex); /** * Update the on-disk chain state. @@ -700,7 +645,9 @@ public: */ bool ActivateBestChain( BlockValidationState& state, - std::shared_ptr<const CBlock> pblock = nullptr) LOCKS_EXCLUDED(cs_main); + std::shared_ptr<const CBlock> pblock = nullptr) + EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) + LOCKS_EXCLUDED(::cs_main); bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -718,9 +665,15 @@ public: * * May not be called in a validationinterface callback. */ - bool PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); + bool PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) + EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) + LOCKS_EXCLUDED(::cs_main); + /** Mark a block as invalid. */ - bool InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main); + bool InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex) + EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) + LOCKS_EXCLUDED(::cs_main); + /** Remove invalidity status from a block and its descendants. */ void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -883,13 +836,13 @@ private: bool m_snapshot_validated{false}; CBlockIndex* m_best_invalid; - friend bool BlockManager::LoadBlockIndex(const Consensus::Params&, ChainstateManager&); + friend bool node::BlockManager::LoadBlockIndex(const Consensus::Params&, ChainstateManager&); //! Internal helper for ActivateSnapshot(). [[nodiscard]] bool PopulateAndValidateSnapshot( CChainState& snapshot_chainstate, CAutoFile& coins_file, - const SnapshotMetadata& metadata); + const node::SnapshotMetadata& metadata); /** * If a block header hasn't already been seen, call CheckBlockHeader on it, ensure @@ -906,7 +859,7 @@ public: std::thread m_load_block; //! A single BlockManager instance is shared across each constructed //! chainstate to avoid duplicating block metadata. - BlockManager m_blockman GUARDED_BY(::cs_main); + node::BlockManager m_blockman; /** * In order to efficiently track invalidity of headers, we keep the set of @@ -966,7 +919,7 @@ public: //! - Move the new chainstate to `m_snapshot_chainstate` and make it our //! ChainstateActive(). [[nodiscard]] bool ActivateSnapshot( - CAutoFile& coins_file, const SnapshotMetadata& metadata, bool in_memory); + CAutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory); //! The most-work chain. CChainState& ActiveChainstate() const; @@ -974,8 +927,9 @@ public: int ActiveHeight() const { return ActiveChain().Height(); } CBlockIndex* ActiveTip() const { return ActiveChain().Tip(); } - BlockMap& BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) + node::BlockMap& BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + AssertLockHeld(::cs_main); return m_blockman.m_block_index; } diff --git a/src/versionbits.cpp b/src/versionbits.cpp index 94c3c9559f..7a297c2bbb 100644 --- a/src/versionbits.cpp +++ b/src/versionbits.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-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. @@ -98,29 +98,38 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* return state; } -BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const +BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params, std::vector<bool>* signalling_blocks) const { BIP9Stats stats = {}; stats.period = Period(params); stats.threshold = Threshold(params); - if (pindex == nullptr) - return stats; + if (pindex == nullptr) return stats; - // Find beginning of period - const CBlockIndex* pindexEndOfPrevPeriod = pindex->GetAncestor(pindex->nHeight - ((pindex->nHeight + 1) % stats.period)); - stats.elapsed = pindex->nHeight - pindexEndOfPrevPeriod->nHeight; + // Find how many blocks are in the current period + int blocks_in_period = 1 + (pindex->nHeight % stats.period); + + // Reset signalling_blocks + if (signalling_blocks) { + signalling_blocks->assign(blocks_in_period, false); + } // Count from current block to beginning of period + int elapsed = 0; int count = 0; const CBlockIndex* currentIndex = pindex; - while (pindexEndOfPrevPeriod->nHeight != currentIndex->nHeight){ - if (Condition(currentIndex, params)) - count++; + do { + ++elapsed; + --blocks_in_period; + if (Condition(currentIndex, params)) { + ++count; + if (signalling_blocks) signalling_blocks->at(blocks_in_period) = true; + } currentIndex = currentIndex->pprev; - } + } while(blocks_in_period > 0); + stats.elapsed = elapsed; stats.count = count; stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count); @@ -196,9 +205,9 @@ ThresholdState VersionBitsCache::State(const CBlockIndex* pindexPrev, const Cons return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]); } -BIP9Stats VersionBitsCache::Statistics(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos) +BIP9Stats VersionBitsCache::Statistics(const CBlockIndex* pindex, const Consensus::Params& params, Consensus::DeploymentPos pos, std::vector<bool>* signalling_blocks) { - return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindexPrev, params); + return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindex, params, signalling_blocks); } int VersionBitsCache::StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos) diff --git a/src/versionbits.h b/src/versionbits.h index 0b2f4a0258..1b3fa11e61 100644 --- a/src/versionbits.h +++ b/src/versionbits.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2019 The Bitcoin Core developers +// Copyright (c) 2016-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. @@ -64,8 +64,10 @@ protected: virtual int Threshold(const Consensus::Params& params) const =0; public: - /** Returns the numerical statistics of an in-progress BIP9 softfork in the current period */ - BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params) const; + /** Returns the numerical statistics of an in-progress BIP9 softfork in the period including pindex + * If provided, signalling_blocks is set to true/false based on whether each block in the period signalled + */ + BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params, std::vector<bool>* signalling_blocks = nullptr) const; /** Returns the state for pindex A based on parent pindexPrev B. Applies any state transition if conditions are present. * Caches state from first block of period. */ ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const; @@ -82,8 +84,10 @@ private: ThresholdConditionCache m_caches[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] GUARDED_BY(m_mutex); public: - /** Get the numerical statistics for a given deployment for the signalling period that includes the block after pindexPrev. */ - static BIP9Stats Statistics(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos); + /** Get the numerical statistics for a given deployment for the signalling period that includes pindex. + * If provided, signalling_blocks is set to true/false based on whether each block in the period signalled + */ + static BIP9Stats Statistics(const CBlockIndex* pindex, const Consensus::Params& params, Consensus::DeploymentPos pos, std::vector<bool>* signalling_blocks = nullptr); static uint32_t Mask(const Consensus::Params& params, Consensus::DeploymentPos pos); diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index 74fc10ab25..49f0abf9e7 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -1,8 +1,9 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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 <fs.h> #include <wallet/bdb.h> #include <wallet/db.h> @@ -15,6 +16,7 @@ #include <sys/stat.h> #endif +namespace wallet { namespace { //! Make sure database has a unique fileid within the environment. If it @@ -619,12 +621,12 @@ bool BerkeleyDatabase::Backup(const std::string& strDest) const pathDest /= fs::PathFromString(strFile); try { - if (fs::equivalent(pathSrc, pathDest)) { + if (fs::exists(pathDest) && fs::equivalent(pathSrc, pathDest)) { LogPrintf("cannot backup to wallet source file %s\n", fs::PathToString(pathDest)); return false; } - fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists); + fs::copy_file(pathSrc, pathDest, fs::copy_options::overwrite_existing); LogPrintf("copied %s to %s\n", strFile, fs::PathToString(pathDest)); return true; } catch (const fs::filesystem_error& e) { @@ -680,10 +682,10 @@ bool BerkeleyBatch::ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& // Convert to streams ssKey.SetType(SER_DISK); ssKey.clear(); - ssKey.write((char*)datKey.get_data(), datKey.get_size()); + ssKey.write({BytePtr(datKey.get_data()), datKey.get_size()}); ssValue.SetType(SER_DISK); ssValue.clear(); - ssValue.write((char*)datValue.get_data(), datValue.get_size()); + ssValue.write({BytePtr(datValue.get_data()), datValue.get_size()}); return true; } @@ -755,7 +757,7 @@ bool BerkeleyBatch::ReadKey(CDataStream&& key, CDataStream& value) SafeDbt datValue; int ret = pdb->get(activeTxn, datKey, datValue, 0); if (ret == 0 && datValue.get_data() != nullptr) { - value.write((char*)datValue.get_data(), datValue.get_size()); + value.write({BytePtr(datValue.get_data()), datValue.get_size()}); return true; } return false; @@ -846,3 +848,4 @@ std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, con status = DatabaseStatus::SUCCESS; return db; } +} // namespace wallet diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index 7d0f80518a..b924890d81 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -31,6 +31,7 @@ struct bilingual_str; +namespace wallet { static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100; static const bool DEFAULT_WALLET_PRIVDB = true; @@ -229,5 +230,6 @@ bool BerkeleyDatabaseSanityCheck(); //! Return object giving access to Berkeley database at specified path. std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); +} // namespace wallet #endif // BITCOIN_WALLET_BDB_H diff --git a/src/wallet/coincontrol.cpp b/src/wallet/coincontrol.cpp index 598c5f082c..3b3c1f8da4 100644 --- a/src/wallet/coincontrol.cpp +++ b/src/wallet/coincontrol.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -6,7 +6,9 @@ #include <util/system.h> +namespace wallet { CCoinControl::CCoinControl() { m_avoid_partial_spends = gArgs.GetBoolArg("-avoidpartialspends", DEFAULT_AVOIDPARTIALSPENDS); } +} // namespace wallet diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h index edd81e590f..65a5c83366 100644 --- a/src/wallet/coincontrol.h +++ b/src/wallet/coincontrol.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2019 The Bitcoin Core developers +// Copyright (c) 2011-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. @@ -18,6 +18,7 @@ #include <map> #include <set> +namespace wallet { const int DEFAULT_MIN_DEPTH = 0; const int DEFAULT_MAX_DEPTH = 9999999; @@ -114,9 +115,29 @@ public: vOutpoints.assign(setSelected.begin(), setSelected.end()); } + void SetInputWeight(const COutPoint& outpoint, int64_t weight) + { + m_input_weights[outpoint] = weight; + } + + bool HasInputWeight(const COutPoint& outpoint) const + { + return m_input_weights.count(outpoint) > 0; + } + + int64_t GetInputWeight(const COutPoint& outpoint) const + { + auto it = m_input_weights.find(outpoint); + assert(it != m_input_weights.end()); + return it->second; + } + private: std::set<COutPoint> setSelected; std::map<COutPoint, CTxOut> m_external_txouts; + //! Map of COutPoints to the maximum weight for that input + std::map<COutPoint, int64_t> m_input_weights; }; +} // namespace wallet #endif // BITCOIN_WALLET_COINCONTROL_H diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp index 25874c601c..23faad027f 100644 --- a/src/wallet/coinselection.cpp +++ b/src/wallet/coinselection.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -13,6 +13,7 @@ #include <numeric> #include <optional> +namespace wallet { // Descending order comparator struct { bool operator()(const OutputGroup& a, const OutputGroup& b) const @@ -429,3 +430,4 @@ bool SelectionResult::operator<(SelectionResult other) const // As this operator is only used in std::min_element, we want the result that has more inputs when waste are equal. return *m_waste < *other.m_waste || (*m_waste == *other.m_waste && m_selected_inputs.size() > other.m_selected_inputs.size()); } +} // namespace wallet diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h index 637afcdb2b..496a026999 100644 --- a/src/wallet/coinselection.h +++ b/src/wallet/coinselection.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -12,6 +12,7 @@ #include <optional> +namespace wallet { //! target minimum change amount static constexpr CAmount MIN_CHANGE{COIN / 100}; //! final minimum change amount after paying for fees @@ -249,5 +250,6 @@ std::optional<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& ut // Original coin selection algorithm as a fallback std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups, const CAmount& nTargetValue); +} // namespace wallet #endif // BITCOIN_WALLET_COINSELECTION_H diff --git a/src/wallet/context.cpp b/src/wallet/context.cpp index 09b2f30467..800aa5bf9c 100644 --- a/src/wallet/context.cpp +++ b/src/wallet/context.cpp @@ -4,5 +4,7 @@ #include <wallet/context.h> +namespace wallet { WalletContext::WalletContext() {} WalletContext::~WalletContext() {} +} // namespace wallet diff --git a/src/wallet/context.h b/src/wallet/context.h index dbd172e88e..57a6ed77f7 100644 --- a/src/wallet/context.h +++ b/src/wallet/context.h @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -13,12 +13,13 @@ #include <vector> class ArgsManager; -class CWallet; namespace interfaces { class Chain; class Wallet; } // namespace interfaces +namespace wallet { +class CWallet; using LoadWalletFn = std::function<void(std::unique_ptr<interfaces::Wallet> wallet)>; //! WalletContext struct containing references to state shared between CWallet @@ -46,5 +47,6 @@ struct WalletContext { WalletContext(); ~WalletContext(); }; +} // namespace wallet #endif // BITCOIN_WALLET_CONTEXT_H diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index 251778e401..cd414b3d44 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -10,6 +10,7 @@ #include <vector> +namespace wallet { int CCrypter::BytesToKeySHA512AES(const std::vector<unsigned char>& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const { // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc @@ -136,3 +137,4 @@ bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned ch key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed()); return key.VerifyPubKey(vchPubKey); } +} // namespace wallet diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index f7325541a9..4d325c7557 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -10,6 +10,7 @@ #include <script/signingprovider.h> +namespace wallet { const unsigned int WALLET_CRYPTO_KEY_SIZE = 32; const unsigned int WALLET_CRYPTO_SALT_SIZE = 8; const unsigned int WALLET_CRYPTO_IV_SIZE = 16; @@ -105,5 +106,6 @@ public: bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext); bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext); bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key); +} // namespace wallet #endif // BITCOIN_WALLET_CRYPTER_H diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 305f6c31fc..0ed2658129 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -8,17 +8,22 @@ #include <logging.h> #include <wallet/db.h> +#include <exception> +#include <fstream> #include <string> +#include <system_error> +#include <vector> +namespace wallet { std::vector<fs::path> ListDatabases(const fs::path& wallet_dir) { std::vector<fs::path> paths; - boost::system::error_code ec; + std::error_code ec; for (auto it = fs::recursive_directory_iterator(wallet_dir, ec); it != fs::recursive_directory_iterator(); it.increment(ec)) { if (ec) { if (fs::is_directory(*it)) { - it.no_push(); + it.disable_recursion_pending(); LogPrintf("%s: %s %s -- skipping.\n", __func__, ec.message(), fs::PathToString(it->path())); } else { LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(it->path())); @@ -29,11 +34,11 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir) try { const fs::path path{it->path().lexically_relative(wallet_dir)}; - if (it->status().type() == fs::directory_file && + if (it->status().type() == fs::file_type::directory && (IsBDBFile(BDBDataFile(it->path())) || IsSQLiteFile(SQLiteDataFile(it->path())))) { // Found a directory which contains wallet.dat btree file, add it as a wallet. paths.emplace_back(path); - } else if (it.level() == 0 && it->symlink_status().type() == fs::regular_file && IsBDBFile(it->path())) { + } else if (it.depth() == 0 && it->symlink_status().type() == fs::file_type::regular && IsBDBFile(it->path())) { if (it->path().filename() == "wallet.dat") { // Found top-level wallet.dat btree file, add top level directory "" // as a wallet. @@ -48,7 +53,7 @@ std::vector<fs::path> ListDatabases(const fs::path& wallet_dir) } } catch (const std::exception& e) { LogPrintf("%s: Error scanning %s: %s\n", __func__, fs::PathToString(it->path()), e.what()); - it.no_push(); + it.disable_recursion_pending(); } } @@ -80,12 +85,12 @@ bool IsBDBFile(const fs::path& path) // A Berkeley DB Btree file has at least 4K. // This check also prevents opening lock files. - boost::system::error_code ec; + std::error_code ec; auto size = fs::file_size(path, ec); if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(path)); if (size < 4096) return false; - fsbridge::ifstream file(path, std::ios::binary); + std::ifstream file{path, std::ios::binary}; if (!file.is_open()) return false; file.seekg(12, std::ios::beg); // Magic bytes start at offset 12 @@ -104,12 +109,12 @@ bool IsSQLiteFile(const fs::path& path) if (!fs::exists(path)) return false; // A SQLite Database file is at least 512 bytes. - boost::system::error_code ec; + std::error_code ec; auto size = fs::file_size(path, ec); if (ec) LogPrintf("%s: %s %s\n", __func__, ec.message(), fs::PathToString(path)); if (size < 512) return false; - fsbridge::ifstream file(path, std::ios::binary); + std::ifstream file{path, std::ios::binary}; if (!file.is_open()) return false; // Magic is at beginning and is 16 bytes long @@ -132,3 +137,4 @@ bool IsSQLiteFile(const fs::path& path) // Check the application id matches our network magic return memcmp(Params().MessageStart(), app_id, 4) == 0; } +} // namespace wallet diff --git a/src/wallet/db.h b/src/wallet/db.h index 3336099eb9..5825b00e3a 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -18,6 +18,7 @@ struct bilingual_str; +namespace wallet { void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename); /** RAII class that provides access to a WalletDatabase */ @@ -232,5 +233,6 @@ fs::path BDBDataFile(const fs::path& path); fs::path SQLiteDataFile(const fs::path& path); bool IsBDBFile(const fs::path& path); bool IsSQLiteFile(const fs::path& path); +} // namespace wallet #endif // BITCOIN_WALLET_DB_H diff --git a/src/wallet/dump.cpp b/src/wallet/dump.cpp index e50b4ca5f7..6d8508fc72 100644 --- a/src/wallet/dump.cpp +++ b/src/wallet/dump.cpp @@ -1,12 +1,21 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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 <wallet/dump.h> +#include <fs.h> #include <util/translation.h> #include <wallet/wallet.h> +#include <algorithm> +#include <fstream> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +namespace wallet { static const std::string DUMP_MAGIC = "BITCOIN_CORE_WALLET_DUMP"; uint32_t DUMP_VERSION = 1; @@ -25,7 +34,7 @@ bool DumpWallet(CWallet& wallet, bilingual_str& error) error = strprintf(_("File %s already exists. If you are sure this is what you want, move it out of the way first."), fs::PathToString(path)); return false; } - fsbridge::ofstream dump_file; + std::ofstream dump_file; dump_file.open(path); if (dump_file.fail()) { error = strprintf(_("Unable to open %s for writing"), fs::PathToString(path)); @@ -46,12 +55,12 @@ bool DumpWallet(CWallet& wallet, bilingual_str& error) // Write out a magic string with version std::string line = strprintf("%s,%u\n", DUMP_MAGIC, DUMP_VERSION); dump_file.write(line.data(), line.size()); - hasher.write(line.data(), line.size()); + hasher.write(MakeByteSpan(line)); // Write out the file format line = strprintf("%s,%s\n", "format", db.Format()); dump_file.write(line.data(), line.size()); - hasher.write(line.data(), line.size()); + hasher.write(MakeByteSpan(line)); if (ret) { @@ -72,7 +81,7 @@ bool DumpWallet(CWallet& wallet, bilingual_str& error) std::string value_str = HexStr(ss_value); line = strprintf("%s,%s\n", key_str, value_str); dump_file.write(line.data(), line.size()); - hasher.write(line.data(), line.size()); + hasher.write(MakeByteSpan(line)); } } @@ -120,7 +129,7 @@ bool CreateFromDump(const std::string& name, const fs::path& wallet_path, biling error = strprintf(_("Dump file %s does not exist."), fs::PathToString(dump_path)); return false; } - fsbridge::ifstream dump_file(dump_path); + std::ifstream dump_file{dump_path}; // Compute the checksum CHashWriter hasher(0, 0); @@ -149,7 +158,7 @@ bool CreateFromDump(const std::string& name, const fs::path& wallet_path, biling return false; } std::string magic_hasher_line = strprintf("%s,%s\n", magic_key, version_value); - hasher.write(magic_hasher_line.data(), magic_hasher_line.size()); + hasher.write(MakeByteSpan(magic_hasher_line)); // Get the stored file format std::string format_key; @@ -180,7 +189,7 @@ bool CreateFromDump(const std::string& name, const fs::path& wallet_path, biling warnings.push_back(strprintf(_("Warning: Dumpfile wallet format \"%s\" does not match command line specified format \"%s\"."), format_value, file_format)); } std::string format_hasher_line = strprintf("%s,%s\n", format_key, format_value); - hasher.write(format_hasher_line.data(), format_hasher_line.size()); + hasher.write(MakeByteSpan(format_hasher_line)); DatabaseOptions options; DatabaseStatus status; @@ -214,12 +223,17 @@ bool CreateFromDump(const std::string& name, const fs::path& wallet_path, biling if (key == "checksum") { std::vector<unsigned char> parsed_checksum = ParseHex(value); + if (parsed_checksum.size() != checksum.size()) { + error = Untranslated("Error: Checksum is not the correct size"); + ret = false; + break; + } std::copy(parsed_checksum.begin(), parsed_checksum.end(), checksum.begin()); break; } std::string line = strprintf("%s,%s\n", key, value); - hasher.write(line.data(), line.size()); + hasher.write(MakeByteSpan(line)); if (key.empty() || value.empty()) { continue; @@ -279,3 +293,4 @@ bool CreateFromDump(const std::string& name, const fs::path& wallet_path, biling return ret; } +} // namespace wallet diff --git a/src/wallet/dump.h b/src/wallet/dump.h index d0a4f5ef1d..a879c4db35 100644 --- a/src/wallet/dump.h +++ b/src/wallet/dump.h @@ -7,11 +7,15 @@ #include <fs.h> -class CWallet; +#include <string> +#include <vector> struct bilingual_str; +namespace wallet { +class CWallet; bool DumpWallet(CWallet& wallet, bilingual_str& error); bool CreateFromDump(const std::string& name, const fs::path& wallet_path, bilingual_str& error, std::vector<bilingual_str>& warnings); +} // namespace wallet #endif // BITCOIN_WALLET_DUMP_H diff --git a/src/wallet/external_signer_scriptpubkeyman.cpp b/src/wallet/external_signer_scriptpubkeyman.cpp index 6a73efb472..9d5f58b784 100644 --- a/src/wallet/external_signer_scriptpubkeyman.cpp +++ b/src/wallet/external_signer_scriptpubkeyman.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -13,6 +13,7 @@ #include <utility> #include <vector> +namespace wallet { bool ExternalSignerScriptPubKeyMan::SetupDescriptor(std::unique_ptr<Descriptor> desc) { LOCK(cs_desc_man); @@ -82,3 +83,4 @@ TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransact if (finalize) FinalizePSBT(psbt); // This won't work in a multisig setup return TransactionError::OK; } +} // namespace wallet diff --git a/src/wallet/external_signer_scriptpubkeyman.h b/src/wallet/external_signer_scriptpubkeyman.h index 53d65d9e46..9918979a81 100644 --- a/src/wallet/external_signer_scriptpubkeyman.h +++ b/src/wallet/external_signer_scriptpubkeyman.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -9,6 +9,7 @@ #include <memory> +namespace wallet { class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan { public: @@ -30,4 +31,5 @@ class ExternalSignerScriptPubKeyMan : public DescriptorScriptPubKeyMan TransactionError FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, bool bip32derivs = false, int* n_signed = nullptr, bool finalize = true) const override; }; +} // namespace wallet #endif // BITCOIN_WALLET_EXTERNAL_SIGNER_SCRIPTPUBKEYMAN_H diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index f2de68295e..3552c14160 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -16,6 +16,7 @@ #include <wallet/spend.h> #include <wallet/wallet.h> +namespace wallet { //! Check whether transaction has descendant in wallet or mempool, or has been //! 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) @@ -276,13 +277,10 @@ Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransacti // mark the original tx as bumped bumped_txid = tx->GetHash(); if (!wallet.MarkReplaced(oldWtx.GetHash(), bumped_txid)) { - // TODO: see if JSON-RPC has a standard way of returning a response - // along with an exception. It would be good to return information about - // wtxBumped to the caller even if marking the original transaction - // replaced does not succeed for some reason. errors.push_back(Untranslated("Created new bumpfee transaction but could not mark the original transaction as replaced")); } return Result::OK; } } // namespace feebumper +} // namespace wallet diff --git a/src/wallet/feebumper.h b/src/wallet/feebumper.h index 50577c9d3e..191878a137 100644 --- a/src/wallet/feebumper.h +++ b/src/wallet/feebumper.h @@ -7,13 +7,15 @@ #include <primitives/transaction.h> -class CWallet; -class CWalletTx; class uint256; -class CCoinControl; enum class FeeEstimateMode; struct bilingual_str; +namespace wallet { +class CCoinControl; +class CWallet; +class CWalletTx; + namespace feebumper { enum class Result @@ -54,5 +56,6 @@ Result CommitTransaction(CWallet& wallet, uint256& bumped_txid); } // namespace feebumper +} // namespace wallet #endif // BITCOIN_WALLET_FEEBUMPER_H diff --git a/src/wallet/fees.cpp b/src/wallet/fees.cpp index 429101e774..6f81fa30a1 100644 --- a/src/wallet/fees.cpp +++ b/src/wallet/fees.cpp @@ -9,6 +9,7 @@ #include <wallet/wallet.h> +namespace wallet { CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes) { return GetRequiredFeeRate(wallet).GetFee(nTxBytes); @@ -90,3 +91,4 @@ CFeeRate GetDiscardRate(const CWallet& wallet) discard_rate = std::max(discard_rate, wallet.chain().relayDustFee()); return discard_rate; } +} // namespace wallet diff --git a/src/wallet/fees.h b/src/wallet/fees.h index d6d625d9c1..af7f759553 100644 --- a/src/wallet/fees.h +++ b/src/wallet/fees.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -8,11 +8,13 @@ #include <consensus/amount.h> -class CCoinControl; class CFeeRate; -class CWallet; struct FeeCalculation; +namespace wallet { +class CCoinControl; +class CWallet; + /** * Return the minimum required absolute fee for this size * based on the required fee rate @@ -41,5 +43,6 @@ CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_contr * Return the maximum feerate for discarding change. */ CFeeRate GetDiscardRate(const CWallet& wallet); +} // namespace wallet #endif // BITCOIN_WALLET_FEES_H diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 4ff049170e..7a83dbc35d 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -23,6 +23,9 @@ #include <wallet/wallet.h> #include <walletinitinterface.h> +using node::NodeContext; + +namespace wallet { class WalletInit : public WalletInitInterface { public: @@ -39,13 +42,14 @@ public: void Construct(NodeContext& node) const override; }; -const WalletInitInterface& g_wallet_init_interface = WalletInit(); - void WalletInit::AddWalletOptions(ArgsManager& argsman) const { argsman.AddArg("-addresstype", strprintf("What type of addresses to use (\"legacy\", \"p2sh-segwit\", \"bech32\", or \"bech32m\", default: \"%s\")", FormatOutputType(DEFAULT_ADDRESS_TYPE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-avoidpartialspends", strprintf("Group outputs by address, selecting many (possibly all) or none, instead of selecting on a per-output basis. Privacy is improved as addresses are mostly swept with fewer transactions and outputs are aggregated in clean change addresses. It may result in higher fees due to less optimal coin selection caused by this added limitation and possibly a larger-than-necessary number of inputs being used. Always enabled for wallets with \"avoid_reuse\" enabled, otherwise default: %u.", DEFAULT_AVOIDPARTIALSPENDS), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); - argsman.AddArg("-changetype", "What type of change to use (\"legacy\", \"p2sh-segwit\", \"bech32\", or \"bech32m\"). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); + argsman.AddArg("-changetype", + "What type of change to use (\"legacy\", \"p2sh-segwit\", \"bech32\", or \"bech32m\"). Default is \"legacy\" when " + "-addresstype=legacy, else it is an implementation detail.", + ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-consolidatefeerate=<amt>", strprintf("The maximum feerate (in %s/kvB) at which transaction building may use more inputs than strictly necessary so that the wallet's UTXO pool can be reduced (default: %s).", CURRENCY_UNIT, FormatMoney(DEFAULT_CONSOLIDATE_FEERATE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kvB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). " @@ -130,7 +134,10 @@ void WalletInit::Construct(NodeContext& node) const LogPrintf("Wallet disabled!\n"); return; } - auto wallet_client = node.init->makeWalletClient(*node.chain); - node.wallet_client = wallet_client.get(); - node.chain_clients.emplace_back(std::move(wallet_client)); + auto wallet_loader = node.init->makeWalletLoader(*node.chain); + node.wallet_loader = wallet_loader.get(); + node.chain_clients.emplace_back(std::move(wallet_loader)); } +} // namespace wallet + +const WalletInitInterface& g_wallet_init_interface = wallet::WalletInit(); diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index bba909b807..9083c304b2 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -40,7 +40,7 @@ using interfaces::MakeHandler; using interfaces::Wallet; using interfaces::WalletAddress; using interfaces::WalletBalances; -using interfaces::WalletClient; +using interfaces::WalletLoader; using interfaces::WalletOrderForm; using interfaces::WalletTx; using interfaces::WalletTxOut; @@ -90,7 +90,6 @@ WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx) result.depth_in_main_chain = wallet.GetTxDepthInMainChain(wtx); result.time_received = wtx.nTimeReceived; result.lock_time = wtx.tx->nLockTime; - result.is_final = wallet.chain().checkFinalTx(*wtx.tx); result.is_trusted = CachedTxIsTrusted(wallet, wtx); result.is_abandoned = wtx.isAbandoned(); result.is_coinbase = wtx.IsCoinBase(); @@ -461,6 +460,11 @@ public: bool canGetAddresses() override { return m_wallet->CanGetAddresses(); } bool hasExternalSigner() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER); } bool privateKeysDisabled() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); } + bool taprootEnabled() override { + if (m_wallet->IsLegacy()) return false; + auto spk_man = m_wallet->GetScriptPubKeyMan(OutputType::BECH32M, /*internal=*/false); + return spk_man != nullptr; + } OutputType getDefaultAddressType() override { return m_wallet->m_default_address_type; } CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; } void remove() override @@ -505,15 +509,15 @@ public: std::shared_ptr<CWallet> m_wallet; }; -class WalletClientImpl : public WalletClient +class WalletLoaderImpl : public WalletLoader { public: - WalletClientImpl(Chain& chain, ArgsManager& args) + WalletLoaderImpl(Chain& chain, ArgsManager& args) { m_context.chain = &chain; m_context.args = &args; } - ~WalletClientImpl() override { UnloadWallets(m_context); } + ~WalletLoaderImpl() override { UnloadWallets(m_context); } //! ChainClient methods void registerRpcs() override @@ -534,7 +538,7 @@ public: void stop() override { return StopWallets(m_context); } void setMockTime(int64_t time) override { return SetMockTime(time); } - //! WalletClient methods + //! 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 { std::shared_ptr<CWallet> wallet; @@ -552,7 +556,7 @@ public: options.require_existing = true; return MakeWallet(m_context, LoadWallet(m_context, name, true /* load_on_start */, options, status, error, warnings)); } - std::unique_ptr<Wallet> restoreWallet(const std::string& backup_file, const std::string& wallet_name, bilingual_str& error, std::vector<bilingual_str>& warnings) override + std::unique_ptr<Wallet> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, bilingual_str& error, std::vector<bilingual_str>& warnings) override { DatabaseStatus status; @@ -593,10 +597,10 @@ public: } // namespace wallet namespace interfaces { -std::unique_ptr<Wallet> MakeWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet) { return wallet ? std::make_unique<wallet::WalletImpl>(context, wallet) : nullptr; } +std::unique_ptr<Wallet> MakeWallet(wallet::WalletContext& context, const std::shared_ptr<wallet::CWallet>& wallet) { return wallet ? std::make_unique<wallet::WalletImpl>(context, wallet) : nullptr; } -std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args) +std::unique_ptr<WalletLoader> MakeWalletLoader(Chain& chain, ArgsManager& args) { - return std::make_unique<wallet::WalletClientImpl>(chain, args); + return std::make_unique<wallet::WalletLoaderImpl>(chain, args); } } // namespace interfaces diff --git a/src/wallet/ismine.h b/src/wallet/ismine.h index 8605547cf2..4ef4ef98ac 100644 --- a/src/wallet/ismine.h +++ b/src/wallet/ismine.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2019 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -12,9 +12,11 @@ #include <cstdint> #include <type_traits> -class CWallet; class CScript; +namespace wallet { +class CWallet; + /** * IsMine() return codes, which depend on ScriptPubKeyMan implementation. * Not every ScriptPubKeyMan covers all types, please refer to @@ -66,5 +68,6 @@ struct CachableAmount m_value[filter] = value; } }; +} // namespace wallet #endif // BITCOIN_WALLET_ISMINE_H diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 7ef5a0cf55..633d8c5450 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -19,20 +19,25 @@ #include <univalue.h> +#include <system_error> + +namespace wallet { bool VerifyWallets(WalletContext& context) { interfaces::Chain& chain = *context.chain; ArgsManager& args = *Assert(context.args); if (args.IsArgSet("-walletdir")) { - fs::path wallet_dir = fs::PathFromString(args.GetArg("-walletdir", "")); - boost::system::error_code error; + const fs::path wallet_dir{args.GetPathArg("-walletdir")}; + std::error_code error; // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory + // It also lets the fs::exists and fs::is_directory checks below pass on windows, since they return false + // if a path has trailing slashes, and it strips trailing slashes. fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error); - if (error || !fs::exists(wallet_dir)) { + if (error || !fs::exists(canonical_wallet_dir)) { chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), fs::PathToString(wallet_dir))); return false; - } else if (!fs::is_directory(wallet_dir)) { + } else if (!fs::is_directory(canonical_wallet_dir)) { chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), fs::PathToString(wallet_dir))); return false; // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version @@ -169,3 +174,4 @@ void UnloadWallets(WalletContext& context) UnloadWallet(std::move(wallet)); } } +} // namespace wallet diff --git a/src/wallet/load.h b/src/wallet/load.h index e207bc2e09..5c2bbdabe4 100644 --- a/src/wallet/load.h +++ b/src/wallet/load.h @@ -11,12 +11,14 @@ class ArgsManager; class CScheduler; -struct WalletContext; namespace interfaces { class Chain; } // namespace interfaces +namespace wallet { +struct WalletContext; + //! Responsible for reading and validating the -wallet arguments and verifying the wallet database. bool VerifyWallets(WalletContext& context); @@ -34,5 +36,6 @@ void StopWallets(WalletContext& context); //! Close all wallets. void UnloadWallets(WalletContext& context); +} // namespace wallet #endif // BITCOIN_WALLET_LOAD_H diff --git a/src/wallet/receive.cpp b/src/wallet/receive.cpp index 2fb274b55f..1a6f06213c 100644 --- a/src/wallet/receive.cpp +++ b/src/wallet/receive.cpp @@ -8,6 +8,7 @@ #include <wallet/transaction.h> #include <wallet/wallet.h> +namespace wallet { isminetype InputIsMine(const CWallet& wallet, const CTxIn &txin) { AssertLockHeld(wallet.cs_wallet); @@ -278,8 +279,6 @@ bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminef bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<uint256>& trusted_parents) { AssertLockHeld(wallet.cs_wallet); - // Quick answer in most cases - if (!wallet.chain().checkFinalTx(*wtx.tx)) return false; int nDepth = wallet.GetTxDepthInMainChain(wtx); if (nDepth >= 1) return true; if (nDepth < 0) return false; @@ -473,3 +472,4 @@ std::set< std::set<CTxDestination> > GetAddressGroupings(const CWallet& wallet) return ret; } +} // namespace wallet diff --git a/src/wallet/receive.h b/src/wallet/receive.h index f659955fc6..d7705b5262 100644 --- a/src/wallet/receive.h +++ b/src/wallet/receive.h @@ -10,6 +10,7 @@ #include <wallet/transaction.h> #include <wallet/wallet.h> +namespace wallet { isminetype InputIsMine(const CWallet& wallet, const CTxIn& txin) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); /** Returns whether all of the inputs match the filter */ @@ -60,5 +61,6 @@ Balance GetBalance(const CWallet& wallet, int min_depth = 0, bool avoid_reuse = std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet); std::set<std::set<CTxDestination>> GetAddressGroupings(const CWallet& wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); +} // namespace wallet #endif // BITCOIN_WALLET_RECEIVE_H diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp index c7400cafe7..51587a64a3 100644 --- a/src/wallet/rpc/addresses.cpp +++ b/src/wallet/rpc/addresses.cpp @@ -13,6 +13,7 @@ #include <univalue.h> +namespace wallet { RPCHelpMan getnewaddress() { return RPCHelpMan{"getnewaddress", @@ -359,7 +360,12 @@ RPCHelpMan keypoolrefill() RPCHelpMan newkeypool() { return RPCHelpMan{"newkeypool", - "\nEntirely clears and refills the keypool."+ + "\nEntirely clears and refills the keypool.\n" + "WARNING: On non-HD wallets, this will require a new backup immediately, to include the new keys.\n" + "When restoring a backup of an HD wallet created before the newkeypool command is run, funds received to\n" + "new addresses may not appear automatically. They have not been lost, but the wallet may not find them.\n" + "This can be fixed by running the newkeypool command on the backup and then rescanning, so the wallet\n" + "re-generates the required keys." + HELP_REQUIRING_PASSPHRASE, {}, RPCResult{RPCResult::Type::NONE, "", ""}, @@ -797,3 +803,4 @@ RPCHelpMan walletdisplayaddress() }; } #endif // ENABLE_EXTERNAL_SIGNER +} // namespace wallet diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index 1d6499edf0..228564fae4 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -1,10 +1,11 @@ -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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 <chain.h> #include <clientversion.h> #include <core_io.h> +#include <fs.h> #include <interfaces/chain.h> #include <key_io.h> #include <merkleblock.h> @@ -20,8 +21,10 @@ #include <wallet/rpc/util.h> #include <wallet/wallet.h> -#include <stdint.h> +#include <cstdint> +#include <fstream> #include <tuple> +#include <string> #include <boost/algorithm/string.hpp> @@ -31,6 +34,7 @@ using interfaces::FoundBlock; +namespace wallet { std::string static EncodeDumpString(const std::string &str) { std::stringstream ret; for (const unsigned char c : str) { @@ -520,7 +524,7 @@ RPCHelpMan importwallet() EnsureWalletIsUnlocked(*pwallet); - fsbridge::ifstream file; + std::ifstream file; file.open(fs::u8path(request.params[0].get_str()), std::ios::in | std::ios::ate); if (!file.is_open()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); @@ -728,7 +732,7 @@ RPCHelpMan dumpwallet() throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.u8string() + " already exists. If you are sure this is what you want, move it out of the way first"); } - fsbridge::ofstream file; + std::ofstream file; file.open(filepath); if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); @@ -1887,7 +1891,7 @@ RPCHelpMan restorewallet() bilingual_str error; std::vector<bilingual_str> warnings; - const std::shared_ptr<CWallet> wallet = RestoreWallet(context, fs::PathToString(backup_file), wallet_name, load_on_start, status, error, warnings); + const std::shared_ptr<CWallet> wallet = RestoreWallet(context, backup_file, wallet_name, load_on_start, status, error, warnings); HandleWalletError(wallet, status, error); @@ -1900,3 +1904,4 @@ RPCHelpMan restorewallet() }, }; } +} // namespace wallet diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index f3294b4570..035541babd 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -15,6 +15,7 @@ #include <univalue.h> +namespace wallet { static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) { std::set<CTxDestination> address_set; @@ -59,8 +60,8 @@ static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool b if (depth < min_depth // Coinbase with less than 1 confirmation is no longer in the main chain || (wtx.IsCoinBase() && (depth < 1 || !include_coinbase)) - || (wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase) - || !wallet.chain().checkFinalTx(*wtx.tx)) { + || (wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase)) + { continue; } @@ -731,3 +732,4 @@ RPCHelpMan listunspent() }, }; } +} // namespace wallet diff --git a/src/wallet/rpc/encrypt.cpp b/src/wallet/rpc/encrypt.cpp index e659f434a3..2b6a2a198d 100644 --- a/src/wallet/rpc/encrypt.cpp +++ b/src/wallet/rpc/encrypt.cpp @@ -7,6 +7,7 @@ #include <wallet/wallet.h> +namespace wallet { RPCHelpMan walletpassphrase() { return RPCHelpMan{"walletpassphrase", @@ -246,3 +247,4 @@ RPCHelpMan encryptwallet() }, }; } +} // namespace wallet diff --git a/src/wallet/rpc/signmessage.cpp b/src/wallet/rpc/signmessage.cpp index bb8d7fc13f..438d290030 100644 --- a/src/wallet/rpc/signmessage.cpp +++ b/src/wallet/rpc/signmessage.cpp @@ -10,6 +10,7 @@ #include <univalue.h> +namespace wallet { RPCHelpMan signmessage() { return RPCHelpMan{"signmessage", @@ -66,3 +67,4 @@ RPCHelpMan signmessage() }, }; } +} // namespace wallet diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index 978174b340..433b5a1815 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <consensus/validation.h> #include <core_io.h> #include <key_io.h> #include <policy/policy.h> @@ -19,6 +20,7 @@ #include <univalue.h> +namespace wallet { static void ParseRecipients(const UniValue& address_amounts, const UniValue& subtract_fee_outputs, std::vector<CRecipient> &recipients) { std::set<CTxDestination> destinations; int i = 0; @@ -428,6 +430,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, {"replaceable", UniValueType(UniValue::VBOOL)}, {"conf_target", UniValueType(UniValue::VNUM)}, {"estimate_mode", UniValueType(UniValue::VSTR)}, + {"input_weights", UniValueType(UniValue::VARR)}, }, true, true); @@ -547,6 +550,37 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, } } + if (options.exists("input_weights")) { + for (const UniValue& input : options["input_weights"].get_array().getValues()) { + uint256 txid = ParseHashO(input, "txid"); + + const UniValue& vout_v = find_value(input, "vout"); + if (!vout_v.isNum()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); + } + int vout = vout_v.get_int(); + if (vout < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); + } + + const UniValue& weight_v = find_value(input, "weight"); + if (!weight_v.isNum()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing weight key"); + } + int64_t weight = weight_v.get_int64(); + const int64_t min_input_weight = GetTransactionInputWeight(CTxIn()); + CHECK_NONFATAL(min_input_weight == 165); + if (weight < min_input_weight) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, weight cannot be less than 165 (41 bytes (size of outpoint + sequence + empty scriptSig) * 4 (witness scaling factor)) + 1 (empty witness)"); + } + if (weight > MAX_STANDARD_TX_WEIGHT) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, weight cannot be greater than the maximum standard tx weight of %d", MAX_STANDARD_TX_WEIGHT)); + } + + coinControl.SetInputWeight(COutPoint(txid, vout), weight); + } + } + if (tx.vout.size() == 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output"); @@ -584,6 +618,23 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, } } +static void SetOptionsInputWeights(const UniValue& inputs, UniValue& options) +{ + if (options.exists("input_weights")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Input weights should be specified in inputs rather than in options."); + } + if (inputs.size() == 0) { + return; + } + UniValue weights(UniValue::VARR); + for (const UniValue& input : inputs.getValues()) { + if (input.exists("weight")) { + weights.push_back(input); + } + } + options.pushKV("input_weights", weights); +} + RPCHelpMan fundrawtransaction() { return RPCHelpMan{"fundrawtransaction", @@ -625,6 +676,17 @@ RPCHelpMan fundrawtransaction() {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."}, }, }, + {"input_weights", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Inputs and their corresponding weights", + { + {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, + {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output index"}, + {"weight", RPCArg::Type::NUM, RPCArg::Optional::NO, "The maximum weight for this input, " + "including the weight of the outpoint and sequence number. " + "Note that serialized signature sizes are not guaranteed to be consistent, " + "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures." + "Remember to convert serialized sizes to weight units when necessary."}, + }, + }, }, FundTxDoc()), "options"}, @@ -1006,6 +1068,11 @@ RPCHelpMan send() {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, {"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO, "The sequence number"}, + {"weight", RPCArg::Type::NUM, RPCArg::DefaultHint{"Calculated from wallet and solving data"}, "The maximum weight for this input, " + "including the weight of the outpoint and sequence number. " + "Note that signature sizes are not guaranteed to be consistent, " + "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures." + "Remember to convert serialized sizes to weight units when necessary."}, }, }, {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, @@ -1109,6 +1176,7 @@ RPCHelpMan send() // Automatically select coins, unless at least one is manually selected. Can // be overridden by options.add_inputs. coin_control.m_add_inputs = rawTx.vin.size() == 0; + SetOptionsInputWeights(options["inputs"], options); FundTransaction(*pwallet, rawTx, fee, change_position, options, coin_control, /* override_min_fee */ false); bool add_to_wallet = true; @@ -1249,6 +1317,11 @@ RPCHelpMan walletcreatefundedpsbt() {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'locktime' and 'options.replaceable' arguments"}, "The sequence number"}, + {"weight", RPCArg::Type::NUM, RPCArg::DefaultHint{"Calculated from wallet and solving data"}, "The maximum weight for this input, " + "including the weight of the outpoint and sequence number. " + "Note that signature sizes are not guaranteed to be consistent, " + "so the maximum DER signatures size of 73 bytes should be used when considering ECDSA signatures." + "Remember to convert serialized sizes to weight units when necessary."}, }, }, }, @@ -1329,10 +1402,12 @@ RPCHelpMan walletcreatefundedpsbt() }, true ); + UniValue options = request.params[3]; + CAmount fee; int change_position; bool rbf{wallet.m_signal_rbf}; - const UniValue &replaceable_arg = request.params[3]["replaceable"]; + const UniValue &replaceable_arg = options["replaceable"]; if (!replaceable_arg.isNull()) { RPCTypeCheckArgument(replaceable_arg, UniValue::VBOOL); rbf = replaceable_arg.isTrue(); @@ -1342,7 +1417,8 @@ RPCHelpMan walletcreatefundedpsbt() // Automatically select coins, unless at least one is manually selected. Can // be overridden by options.add_inputs. coin_control.m_add_inputs = rawTx.vin.size() == 0; - FundTransaction(wallet, rawTx, fee, change_position, request.params[3], coin_control, /* override_min_fee */ true); + SetOptionsInputWeights(request.params[0], options); + FundTransaction(wallet, rawTx, fee, change_position, options, coin_control, /* override_min_fee */ true); // Make a blank psbt PartiallySignedTransaction psbtx(rawTx); @@ -1367,3 +1443,4 @@ RPCHelpMan walletcreatefundedpsbt() }, }; } +} // namespace wallet diff --git a/src/wallet/rpc/transactions.cpp b/src/wallet/rpc/transactions.cpp index 8a1c0885ac..eef2c13ee1 100644 --- a/src/wallet/rpc/transactions.cpp +++ b/src/wallet/rpc/transactions.cpp @@ -13,6 +13,7 @@ using interfaces::FoundBlock; +namespace wallet { static void WalletTxToJSON(const CWallet& wallet, const CWalletTx& wtx, UniValue& entry) { interfaces::Chain& chain = wallet.chain(); @@ -113,8 +114,8 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons // Coinbase with less than 1 confirmation is no longer in the main chain if ((wtx.IsCoinBase() && (nDepth < 1 || !include_coinbase)) - || (wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase) - || !wallet.chain().checkFinalTx(*wtx.tx)) { + || (wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase)) + { continue; } @@ -958,3 +959,4 @@ RPCHelpMan abortrescan() }, }; } +} // namespace wallet diff --git a/src/wallet/rpc/util.cpp b/src/wallet/rpc/util.cpp index 9a40a67ee5..59683c5fd8 100644 --- a/src/wallet/rpc/util.cpp +++ b/src/wallet/rpc/util.cpp @@ -12,6 +12,7 @@ #include <univalue.h> +namespace wallet { static const std::string WALLET_ENDPOINT_BASE = "/wallet/"; const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"}; @@ -147,4 +148,5 @@ void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& st } throw JSONRPCError(code, error.original); } -}
\ No newline at end of file +} +} // namespace wallet diff --git a/src/wallet/rpc/util.h b/src/wallet/rpc/util.h index 5b00d2abcb..7b810eb06e 100644 --- a/src/wallet/rpc/util.h +++ b/src/wallet/rpc/util.h @@ -10,12 +10,14 @@ #include <string> #include <vector> +class JSONRPCRequest; +class UniValue; struct bilingual_str; + +namespace wallet { class CWallet; -enum class DatabaseStatus; -class JSONRPCRequest; class LegacyScriptPubKeyMan; -class UniValue; +enum class DatabaseStatus; struct WalletContext; extern const std::string HELP_REQUIRING_PASSPHRASE; @@ -39,5 +41,6 @@ bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wal std::string LabelFromValue(const UniValue& value); void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& status, bilingual_str& error); +} // namespace wallet #endif // BITCOIN_WALLET_RPC_UTIL_H diff --git a/src/wallet/rpc/wallet.cpp b/src/wallet/rpc/wallet.cpp index 738f8258bc..883a3c102b 100644 --- a/src/wallet/rpc/wallet.cpp +++ b/src/wallet/rpc/wallet.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -18,6 +18,7 @@ #include <univalue.h> +namespace wallet { /** Checks if a CKey is in the given CWallet compressed or otherwise*/ bool HaveKey(const SigningProvider& wallet, const CKey& key) { @@ -56,6 +57,7 @@ static RPCHelpMan getwalletinfo() {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"}, }}, {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"}, + {RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"}, }}, }, RPCExamples{ @@ -116,6 +118,7 @@ static RPCHelpMan getwalletinfo() obj.pushKV("scanning", false); } obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)); + obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)); return obj; }, }; @@ -729,3 +732,4 @@ static const CRPCCommand commands[] = // clang-format on return commands; } +} // namespace wallet diff --git a/src/wallet/rpc/wallet.h b/src/wallet/rpc/wallet.h index cdc9a8cc92..423fc892b2 100644 --- a/src/wallet/rpc/wallet.h +++ b/src/wallet/rpc/wallet.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. @@ -9,6 +9,8 @@ class CRPCCommand; +namespace wallet { Span<const CRPCCommand> GetWalletRPCCommands(); +} // namespace wallet #endif // BITCOIN_WALLET_RPC_WALLET_H diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp index 241d77c9de..1ecc96fe0e 100644 --- a/src/wallet/salvage.cpp +++ b/src/wallet/salvage.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -11,6 +11,7 @@ #include <wallet/wallet.h> #include <wallet/walletdb.h> +namespace wallet { /* End of headers, beginning of key/value data */ static const char *HEADER_END = "HEADER=END"; /* End of key/value data */ @@ -165,3 +166,4 @@ bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::v return fSuccess; } +} // namespace wallet diff --git a/src/wallet/salvage.h b/src/wallet/salvage.h index 5a8538f942..332aceb262 100644 --- a/src/wallet/salvage.h +++ b/src/wallet/salvage.h @@ -11,6 +11,8 @@ struct bilingual_str; +namespace wallet { bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::vector<bilingual_str>& warnings); +} // namespace wallet #endif // BITCOIN_WALLET_SALVAGE_H diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index a9e2624188..7218ed11dc 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -17,6 +17,7 @@ #include <optional> +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; @@ -2359,3 +2360,4 @@ bool DescriptorScriptPubKeyMan::CanUpdateToWalletDescriptor(const WalletDescript return true; } +} // namespace wallet diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index dda31d2c0b..6eda133771 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020 The Bitcoin Core developers +// Copyright (c) 2019-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. @@ -25,6 +25,7 @@ enum class OutputType; struct bilingual_str; +namespace wallet { // Wallet storage things that ScriptPubKeyMans need in order to be able to store things to the wallet database. // It provides access to things that are part of the entire wallet and not specific to a ScriptPubKeyMan such as // wallet flags, wallet version, encryption keys, encryption status, and the database itself. This allows a @@ -631,5 +632,6 @@ public: void UpgradeDescriptorCache(); }; +} // namespace wallet #endif // BITCOIN_WALLET_SCRIPTPUBKEYMAN_H diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 5d9cc7bf6b..3d8ae2da69 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -21,6 +21,7 @@ using interfaces::FoundBlock; +namespace wallet { static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100}; int GetTxSpendSize(const CWallet& wallet, const CWalletTx& wtx, unsigned int out, bool use_max_sig) @@ -104,10 +105,6 @@ void AvailableCoins(const CWallet& wallet, std::vector<COutput>& vCoins, const C const uint256& wtxid = entry.first; const CWalletTx& wtx = entry.second; - if (!wallet.chain().checkFinalTx(*wtx.tx)) { - continue; - } - if (wallet.IsTxImmatureCoinBase(wtx)) continue; @@ -454,15 +451,17 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec } input_bytes = GetTxSpendSize(wallet, wtx, outpoint.n, false); txout = wtx.tx->vout.at(outpoint.n); - } - if (input_bytes == -1) { - // The input is external. We either did not find the tx in mapWallet, or we did but couldn't compute the input size with wallet data + } else { + // The input is external. We did not find the tx in mapWallet. if (!coin_control.GetExternalOutput(outpoint, txout)) { - // Not ours, and we don't have solving data. return std::nullopt; } input_bytes = CalculateMaximumSignedInputSize(txout, &coin_control.m_external_provider, /* use_max_sig */ true); } + // If available, override calculated size with coin control specified size + if (coin_control.HasInputWeight(outpoint)) { + input_bytes = GetVirtualTransactionSize(coin_control.GetInputWeight(outpoint), 0, 0); + } CInputCoin coin(outpoint, txout, input_bytes); if (coin.m_input_bytes == -1) { @@ -665,8 +664,6 @@ static bool CreateTransactionInternal( } // Create change script that will be used if we need change - // TODO: pass in scriptChange instead of reservedest so - // change transaction isn't always pay-to-bitcoin-address CScript scriptChange; // coin control: send change to custom address @@ -799,7 +796,7 @@ static bool CreateTransactionInternal( // to avoid conflicting with other possible uses of nSequence, // and in the spirit of "smallest possible change from prior // behavior." - const uint32_t nSequence = coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : (CTxIn::SEQUENCE_FINAL - 1); + const uint32_t nSequence{coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : CTxIn::MAX_SEQUENCE_NONFINAL}; for (const auto& coin : selected_coins) { txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence)); } @@ -1030,3 +1027,4 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet, return true; } +} // namespace wallet diff --git a/src/wallet/spend.h b/src/wallet/spend.h index 268bcfc033..4453fb2762 100644 --- a/src/wallet/spend.h +++ b/src/wallet/spend.h @@ -10,6 +10,7 @@ #include <wallet/transaction.h> #include <wallet/wallet.h> +namespace wallet { /** Get the marginal bytes if spending the specified output from this transaction */ int GetTxSpendSize(const CWallet& wallet, const CWalletTx& wtx, unsigned int out, bool use_max_sig = false); @@ -142,5 +143,6 @@ bool CreateTransaction(CWallet& wallet, const std::vector<CRecipient>& vecSend, * calling CreateTransaction(); */ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl); +} // namespace wallet #endif // BITCOIN_WALLET_SPEND_H diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index c493b96248..2b2181e70b 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -20,6 +20,7 @@ #include <utility> #include <vector> +namespace wallet { static constexpr int32_t WALLET_SCHEMA_VERSION = 0; static Mutex g_sqlite_mutex; @@ -394,9 +395,9 @@ bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value) return false; } // Leftmost column in result is index 0 - const char* data = reinterpret_cast<const char*>(sqlite3_column_blob(m_read_stmt, 0)); - int data_size = sqlite3_column_bytes(m_read_stmt, 0); - value.write(data, data_size); + const std::byte* data{BytePtr(sqlite3_column_blob(m_read_stmt, 0))}; + size_t data_size(sqlite3_column_bytes(m_read_stmt, 0)); + value.write({data, data_size}); sqlite3_clear_bindings(m_read_stmt); sqlite3_reset(m_read_stmt); @@ -511,12 +512,12 @@ bool SQLiteBatch::ReadAtCursor(CDataStream& key, CDataStream& value, bool& compl } // Leftmost column in result is index 0 - const char* key_data = reinterpret_cast<const char*>(sqlite3_column_blob(m_cursor_stmt, 0)); - int key_data_size = sqlite3_column_bytes(m_cursor_stmt, 0); - key.write(key_data, key_data_size); - const char* value_data = reinterpret_cast<const char*>(sqlite3_column_blob(m_cursor_stmt, 1)); - int value_data_size = sqlite3_column_bytes(m_cursor_stmt, 1); - value.write(value_data, value_data_size); + const std::byte* key_data{BytePtr(sqlite3_column_blob(m_cursor_stmt, 0))}; + size_t key_data_size(sqlite3_column_bytes(m_cursor_stmt, 0)); + key.write({key_data, key_data_size}); + const std::byte* value_data{BytePtr(sqlite3_column_blob(m_cursor_stmt, 1))}; + size_t value_data_size(sqlite3_column_bytes(m_cursor_stmt, 1)); + value.write({value_data, value_data_size}); return true; } @@ -578,3 +579,4 @@ std::string SQLiteDatabaseVersion() { return std::string(sqlite3_libversion()); } +} // namespace wallet diff --git a/src/wallet/sqlite.h b/src/wallet/sqlite.h index 70ab4f797a..3ed598d0d2 100644 --- a/src/wallet/sqlite.h +++ b/src/wallet/sqlite.h @@ -10,6 +10,8 @@ #include <sqlite3.h> struct bilingual_str; + +namespace wallet { class SQLiteDatabase; /** RAII class that provides access to a WalletDatabase */ @@ -116,5 +118,6 @@ public: std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); std::string SQLiteDatabaseVersion(); +} // namespace wallet #endif // BITCOIN_WALLET_SQLITE_H diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index a1fa871ccb..b9f12158ca 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -18,6 +18,7 @@ #include <boost/test/unit_test.hpp> #include <random> +namespace wallet { BOOST_FIXTURE_TEST_SUITE(coinselector_tests, WalletTestingSetup) // how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles @@ -807,3 +808,4 @@ BOOST_AUTO_TEST_CASE(waste_test) } BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/test/db_tests.cpp b/src/wallet/test/db_tests.cpp index dba3f35025..35ae3707f8 100644 --- a/src/wallet/test/db_tests.cpp +++ b/src/wallet/test/db_tests.cpp @@ -1,16 +1,18 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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 <memory> - #include <boost/test/unit_test.hpp> #include <fs.h> #include <test/util/setup_common.h> #include <wallet/bdb.h> +#include <fstream> +#include <memory> +#include <string> +namespace wallet { BOOST_FIXTURE_TEST_SUITE(db_tests, BasicTestingSetup) static std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& path, std::string& database_filename) @@ -25,7 +27,7 @@ BOOST_AUTO_TEST_CASE(getwalletenv_file) std::string test_name = "test_name.dat"; const fs::path datadir = gArgs.GetDataDirNet(); fs::path file_path = datadir / test_name; - fs::ofstream f(file_path); + std::ofstream f{file_path}; f.close(); std::string filename; @@ -77,3 +79,4 @@ BOOST_AUTO_TEST_CASE(getwalletenv_g_dbenvs_free_instance) } BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp index 0601c492cd..1c16da25bd 100644 --- a/src/wallet/test/fuzz/notifications.cpp +++ b/src/wallet/test/fuzz/notifications.cpp @@ -18,6 +18,7 @@ #include <string> #include <vector> +namespace wallet { namespace { const TestingSetup* g_setup; @@ -168,3 +169,4 @@ FUZZ_TARGET_INIT(wallet_notifications, initialize_setup) } } } // namespace +} // namespace wallet diff --git a/src/wallet/test/init_test_fixture.cpp b/src/wallet/test/init_test_fixture.cpp index 170675c035..be38cebafd 100644 --- a/src/wallet/test/init_test_fixture.cpp +++ b/src/wallet/test/init_test_fixture.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -7,11 +7,15 @@ #include <util/check.h> #include <util/system.h> +#include <fstream> +#include <string> + #include <wallet/test/init_test_fixture.h> +namespace wallet { InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) { - m_wallet_client = MakeWalletClient(*m_node.chain, *Assert(m_node.args)); + m_wallet_loader = MakeWalletLoader(*m_node.chain, *Assert(m_node.args)); std::string sep; sep += fs::path::preferred_separator; @@ -23,8 +27,8 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainNam m_walletdir_path_cases["custom"] = m_datadir / "my_wallets"; m_walletdir_path_cases["nonexistent"] = m_datadir / "path_does_not_exist"; m_walletdir_path_cases["file"] = m_datadir / "not_a_directory.dat"; - m_walletdir_path_cases["trailing"] = m_datadir / "wallets" / sep; - m_walletdir_path_cases["trailing2"] = m_datadir / "wallets" / sep / sep; + m_walletdir_path_cases["trailing"] = m_datadir / ("wallets" + sep); + m_walletdir_path_cases["trailing2"] = m_datadir / ("wallets" + sep + sep); fs::current_path(m_datadir); m_walletdir_path_cases["relative"] = "wallets"; @@ -32,7 +36,7 @@ InitWalletDirTestingSetup::InitWalletDirTestingSetup(const std::string& chainNam fs::create_directories(m_walletdir_path_cases["default"]); fs::create_directories(m_walletdir_path_cases["custom"]); fs::create_directories(m_walletdir_path_cases["relative"]); - fs::ofstream f(m_walletdir_path_cases["file"]); + std::ofstream f{m_walletdir_path_cases["file"]}; f.close(); } @@ -48,3 +52,4 @@ void InitWalletDirTestingSetup::SetWalletDir(const fs::path& walletdir_path) { gArgs.ForceSetArg("-walletdir", fs::PathToString(walletdir_path)); } +} // namespace wallet diff --git a/src/wallet/test/init_test_fixture.h b/src/wallet/test/init_test_fixture.h index 37ae907de5..df5819fd1d 100644 --- a/src/wallet/test/init_test_fixture.h +++ b/src/wallet/test/init_test_fixture.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -11,6 +11,7 @@ #include <test/util/setup_common.h> +namespace wallet { struct InitWalletDirTestingSetup: public BasicTestingSetup { explicit InitWalletDirTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); ~InitWalletDirTestingSetup(); @@ -19,7 +20,8 @@ struct InitWalletDirTestingSetup: public BasicTestingSetup { fs::path m_datadir; fs::path m_cwd; std::map<std::string, fs::path> m_walletdir_path_cases; - std::unique_ptr<interfaces::WalletClient> m_wallet_client; + std::unique_ptr<interfaces::WalletLoader> m_wallet_loader; }; #endif // BITCOIN_WALLET_TEST_INIT_TEST_FIXTURE_H +} // namespace wallet diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp index 222c2bf4b7..7fdecc5642 100644 --- a/src/wallet/test/init_tests.cpp +++ b/src/wallet/test/init_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. @@ -10,14 +10,15 @@ #include <util/system.h> #include <wallet/test/init_test_fixture.h> +namespace wallet { BOOST_FIXTURE_TEST_SUITE(init_tests, InitWalletDirTestingSetup) BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default) { SetWalletDir(m_walletdir_path_cases["default"]); - bool result = m_wallet_client->verify(); + bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } @@ -25,9 +26,9 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default) BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom) { SetWalletDir(m_walletdir_path_cases["custom"]); - bool result = m_wallet_client->verify(); + bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } @@ -37,7 +38,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_does_not_exist) SetWalletDir(m_walletdir_path_cases["nonexistent"]); { ASSERT_DEBUG_LOG("does not exist"); - bool result = m_wallet_client->verify(); + bool result = m_wallet_loader->verify(); BOOST_CHECK(result == false); } } @@ -47,7 +48,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_directory) SetWalletDir(m_walletdir_path_cases["file"]); { ASSERT_DEBUG_LOG("is not a directory"); - bool result = m_wallet_client->verify(); + bool result = m_wallet_loader->verify(); BOOST_CHECK(result == false); } } @@ -57,7 +58,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_relative) SetWalletDir(m_walletdir_path_cases["relative"]); { ASSERT_DEBUG_LOG("is a relative path"); - bool result = m_wallet_client->verify(); + bool result = m_wallet_loader->verify(); BOOST_CHECK(result == false); } } @@ -65,9 +66,9 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_is_not_relative) BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing) { SetWalletDir(m_walletdir_path_cases["trailing"]); - bool result = m_wallet_client->verify(); + bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } @@ -75,11 +76,12 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing) BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2) { SetWalletDir(m_walletdir_path_cases["trailing2"]); - bool result = m_wallet_client->verify(); + bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp index dda202d55e..dd5cd0af46 100644 --- a/src/wallet/test/ismine_tests.cpp +++ b/src/wallet/test/ismine_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -13,6 +13,7 @@ #include <boost/test/unit_test.hpp> +namespace wallet { BOOST_FIXTURE_TEST_SUITE(ismine_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(ismine_standard) @@ -417,3 +418,4 @@ BOOST_AUTO_TEST_CASE(ismine_standard) } BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp index 7bc2bb5583..b953f402a2 100644 --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -11,6 +11,7 @@ #include <test/util/setup_common.h> #include <wallet/test/wallet_test_fixture.h> +namespace wallet { BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup) static void import_descriptor(CWallet& wallet, const std::string& descriptor) @@ -145,3 +146,4 @@ BOOST_AUTO_TEST_CASE(parse_hd_keypath) } BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/test/scriptpubkeyman_tests.cpp b/src/wallet/test/scriptpubkeyman_tests.cpp index 0e78855ced..a524b85ccb 100644 --- a/src/wallet/test/scriptpubkeyman_tests.cpp +++ b/src/wallet/test/scriptpubkeyman_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020 The Bitcoin Core developers +// Copyright (c) 2020-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. @@ -10,6 +10,7 @@ #include <boost/test/unit_test.hpp> +namespace wallet { BOOST_FIXTURE_TEST_SUITE(scriptpubkeyman_tests, BasicTestingSetup) // Test LegacyScriptPubKeyMan::CanProvide behavior, making sure it returns true @@ -39,3 +40,4 @@ BOOST_AUTO_TEST_CASE(CanProvide) } BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp index 926f28686d..334bd5b8bc 100644 --- a/src/wallet/test/spend_tests.cpp +++ b/src/wallet/test/spend_tests.cpp @@ -12,6 +12,7 @@ #include <boost/test/unit_test.hpp> +namespace wallet { BOOST_FIXTURE_TEST_SUITE(spend_tests, WalletTestingSetup) BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup) @@ -62,4 +63,56 @@ BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup) BOOST_CHECK_EQUAL(fee, check_tx(fee + 123)); } +static void TestFillInputToWeight(int64_t additional_weight, std::vector<int64_t> expected_stack_sizes) +{ + static const int64_t EMPTY_INPUT_WEIGHT = GetTransactionInputWeight(CTxIn()); + + CTxIn input; + int64_t target_weight = EMPTY_INPUT_WEIGHT + additional_weight; + BOOST_CHECK(FillInputToWeight(input, target_weight)); + BOOST_CHECK_EQUAL(GetTransactionInputWeight(input), target_weight); + BOOST_CHECK_EQUAL(input.scriptWitness.stack.size(), expected_stack_sizes.size()); + for (unsigned int i = 0; i < expected_stack_sizes.size(); ++i) { + BOOST_CHECK_EQUAL(input.scriptWitness.stack[i].size(), expected_stack_sizes[i]); + } +} + +BOOST_FIXTURE_TEST_CASE(FillInputToWeightTest, BasicTestingSetup) +{ + { + // Less than or equal minimum of 165 should not add any witness data + CTxIn input; + BOOST_CHECK(!FillInputToWeight(input, -1)); + BOOST_CHECK_EQUAL(GetTransactionInputWeight(input), 165); + BOOST_CHECK_EQUAL(input.scriptWitness.stack.size(), 0); + BOOST_CHECK(!FillInputToWeight(input, 0)); + BOOST_CHECK_EQUAL(GetTransactionInputWeight(input), 165); + BOOST_CHECK_EQUAL(input.scriptWitness.stack.size(), 0); + BOOST_CHECK(!FillInputToWeight(input, 164)); + BOOST_CHECK_EQUAL(GetTransactionInputWeight(input), 165); + BOOST_CHECK_EQUAL(input.scriptWitness.stack.size(), 0); + BOOST_CHECK(FillInputToWeight(input, 165)); + BOOST_CHECK_EQUAL(GetTransactionInputWeight(input), 165); + BOOST_CHECK_EQUAL(input.scriptWitness.stack.size(), 0); + } + + // Make sure we can add at least one weight + TestFillInputToWeight(1, {0}); + + // 1 byte compact size uint boundary + TestFillInputToWeight(252, {251}); + TestFillInputToWeight(253, {83, 168}); + TestFillInputToWeight(262, {86, 174}); + TestFillInputToWeight(263, {260}); + + // 3 byte compact size uint boundary + TestFillInputToWeight(65535, {65532}); + TestFillInputToWeight(65536, {21842, 43688}); + TestFillInputToWeight(65545, {21845, 43694}); + TestFillInputToWeight(65546, {65541}); + + // Note: We don't test the next boundary because of memory allocation constraints. +} + BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp index 93a3404d2c..aa3121511d 100644 --- a/src/wallet/test/util.cpp +++ b/src/wallet/test/util.cpp @@ -15,6 +15,7 @@ #include <memory> +namespace wallet { std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, ArgsManager& args, const CKey& key) { auto wallet = std::make_unique<CWallet>(&chain, "", args, CreateMockWalletDatabase()); @@ -44,3 +45,4 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc BOOST_CHECK(result.last_failed_block.IsNull()); return wallet; } +} // namespace wallet diff --git a/src/wallet/test/util.h b/src/wallet/test/util.h index 3adb82b85f..712d0251cd 100644 --- a/src/wallet/test/util.h +++ b/src/wallet/test/util.h @@ -10,11 +10,14 @@ class ArgsManager; class CChain; class CKey; -class CWallet; namespace interfaces { class Chain; } // namespace interfaces +namespace wallet { +class CWallet; + std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, ArgsManager& args, const CKey& key); +} // namespace wallet #endif // BITCOIN_WALLET_TEST_UTIL_H diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp index 5b421840e0..166e27bab9 100644 --- a/src/wallet/test/wallet_crypto_tests.cpp +++ b/src/wallet/test/wallet_crypto_tests.cpp @@ -10,6 +10,7 @@ #include <boost/test/unit_test.hpp> +namespace wallet { BOOST_FIXTURE_TEST_SUITE(wallet_crypto_tests, BasicTestingSetup) class TestCrypter @@ -124,3 +125,4 @@ BOOST_AUTO_TEST_CASE(decrypt) { } BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp index 762702522e..cb006dea3a 100644 --- a/src/wallet/test/wallet_test_fixture.cpp +++ b/src/wallet/test/wallet_test_fixture.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. @@ -6,16 +6,18 @@ #include <scheduler.h> +namespace wallet { WalletTestingSetup::WalletTestingSetup(const std::string& chainName) : TestingSetup(chainName), m_wallet(m_node.chain.get(), "", m_args, CreateMockWalletDatabase()) { m_wallet.LoadWallet(); m_chain_notifications_handler = m_node.chain->handleNotifications({ &m_wallet, [](CWallet*) {} }); - m_wallet_client->registerRpcs(); + m_wallet_loader->registerRpcs(); } WalletTestingSetup::~WalletTestingSetup() { if (m_node.scheduler) m_node.scheduler->stop(); } +} // namespace wallet diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h index 8bf2d36227..d4b855b145 100644 --- a/src/wallet/test/wallet_test_fixture.h +++ b/src/wallet/test/wallet_test_fixture.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. @@ -15,15 +15,17 @@ #include <memory> +namespace wallet { /** Testing setup and teardown for wallet. */ struct WalletTestingSetup : public TestingSetup { explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN); ~WalletTestingSetup(); - std::unique_ptr<interfaces::WalletClient> m_wallet_client = interfaces::MakeWalletClient(*m_node.chain, *Assert(m_node.args)); + std::unique_ptr<interfaces::WalletLoader> m_wallet_loader = interfaces::MakeWalletLoader(*m_node.chain, *Assert(m_node.args)); CWallet m_wallet; std::unique_ptr<interfaces::Handler> m_chain_notifications_handler; }; +} // namespace wallet #endif // BITCOIN_WALLET_TEST_WALLET_TEST_FIXTURE_H diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 8cb3cede9b..7693c9c0e8 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2020 The Bitcoin Core developers +// Copyright (c) 2012-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. @@ -30,6 +30,10 @@ #include <boost/test/unit_test.hpp> #include <univalue.h> +using node::MAX_BLOCKFILE_SIZE; +using node::UnlinkPrunedFiles; + +namespace wallet { RPCHelpMan importmulti(); RPCHelpMan dumpwallet(); RPCHelpMan importwallet(); @@ -92,7 +96,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) { // Cap last block file size, and mine new block in a new block file. CBlockIndex* oldTip = m_node.chainman->ActiveChain().Tip(); - GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE; + WITH_LOCK(::cs_main, m_node.chainman->m_blockman.GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE); CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CBlockIndex* newTip = m_node.chainman->ActiveChain().Tip(); @@ -136,11 +140,13 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) } // Prune the older block file. + int file_number; { LOCK(cs_main); - Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(oldTip->GetBlockPos().nFile); + file_number = oldTip->GetBlockPos().nFile; + Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(file_number); } - UnlinkPrunedFiles({oldTip->GetBlockPos().nFile}); + UnlinkPrunedFiles({file_number}); // Verify ScanForWalletTransactions only picks transactions in the new block // file. @@ -165,9 +171,10 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup) // Prune the remaining block file. { LOCK(cs_main); - Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(newTip->GetBlockPos().nFile); + file_number = newTip->GetBlockPos().nFile; + Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(file_number); } - UnlinkPrunedFiles({newTip->GetBlockPos().nFile}); + UnlinkPrunedFiles({file_number}); // Verify ScanForWalletTransactions scans no blocks. { @@ -193,16 +200,18 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) { // Cap last block file size, and mine new block in a new block file. CBlockIndex* oldTip = m_node.chainman->ActiveChain().Tip(); - GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE; + WITH_LOCK(::cs_main, m_node.chainman->m_blockman.GetBlockFileInfo(oldTip->GetBlockPos().nFile)->nSize = MAX_BLOCKFILE_SIZE); CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CBlockIndex* newTip = m_node.chainman->ActiveChain().Tip(); // Prune the older block file. + int file_number; { LOCK(cs_main); - Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(oldTip->GetBlockPos().nFile); + file_number = oldTip->GetBlockPos().nFile; + Assert(m_node.chainman)->m_blockman.PruneOneBlockFile(file_number); } - UnlinkPrunedFiles({oldTip->GetBlockPos().nFile}); + UnlinkPrunedFiles({file_number}); // Verify importmulti RPC returns failure for a key whose creation time is // before the missing block, and success for a key whose creation time is @@ -289,7 +298,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) request.params.setArray(); request.params.push_back(backup_file); - ::dumpwallet().HandleRequest(request); + wallet::dumpwallet().HandleRequest(request); RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt); } @@ -308,7 +317,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) request.params.push_back(backup_file); AddWallet(context, wallet); wallet->SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash()); - ::importwallet().HandleRequest(request); + wallet::importwallet().HandleRequest(request); RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt); BOOST_CHECK_EQUAL(wallet->mapWallet.size(), 3U); @@ -417,7 +426,7 @@ BOOST_AUTO_TEST_CASE(LoadReceiveRequests) // Test some watch-only LegacyScriptPubKeyMan methods by the procedure of loading (LoadWatchOnly), // checking (HaveWatchOnly), getting (GetWatchPubKey) and removing (RemoveWatchOnly) a -// given PubKey, resp. its corresponding P2PK Script. Results of the the impact on +// given PubKey, resp. its corresponding P2PK Script. Results of the impact on // the address -> PubKey map is dependent on whether the PubKey is a point on the curve static void TestWatchOnlyPubKey(LegacyScriptPubKeyMan* spk_man, const CPubKey& add_pubkey) { @@ -816,38 +825,34 @@ BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup) context.args = &gArgs; context.chain = m_node.chain.get(); auto wallet = TestLoadWallet(context); - AddKey(*wallet, coinbaseKey); + CKey key; + key.MakeNewKey(true); + AddKey(*wallet, key); - // rescan to ensure coinbase transactions from test fixture are picked up by the wallet - { - WalletRescanReserver reserver(*wallet); - reserver.reserve(); - wallet->ScanForWalletTransactions(m_node.chain->getBlockHash(0), 0, /* max height= */ {}, reserver, /* update= */ true); - } - // create one more block to get the first block coinbase to maturity + std::string error; m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); - // spend first coinbase tx - auto spend_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); - CreateAndProcessBlock({spend_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); + auto block_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey())); + CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); SyncWithValidationInterfaceQueue(); { - auto spend_tx_hash = spend_tx.GetHash(); + auto block_hash = block_tx.GetHash(); auto prev_hash = m_coinbase_txns[0]->GetHash(); LOCK(wallet->cs_wallet); BOOST_CHECK(wallet->HasWalletSpend(prev_hash)); - BOOST_CHECK_EQUAL(wallet->mapWallet.count(spend_tx_hash), 1u); + BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 1u); - std::vector<uint256> vHashIn{spend_tx_hash}, vHashOut; + 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_EQUAL(wallet->mapWallet.count(spend_tx_hash), 0u); + BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 0u); } TestUnloadWallet(std::move(wallet)); } BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/test/wallet_transaction_tests.cpp b/src/wallet/test/wallet_transaction_tests.cpp index 5ef2904f66..9f56248614 100644 --- a/src/wallet/test/wallet_transaction_tests.cpp +++ b/src/wallet/test/wallet_transaction_tests.cpp @@ -8,6 +8,7 @@ #include <boost/test/unit_test.hpp> +namespace wallet { BOOST_FIXTURE_TEST_SUITE(wallet_transaction_tests, WalletTestingSetup) BOOST_AUTO_TEST_CASE(roundtrip) @@ -22,3 +23,4 @@ BOOST_AUTO_TEST_CASE(roundtrip) } BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/test/walletdb_tests.cpp b/src/wallet/test/walletdb_tests.cpp index 558121ae42..e251a3a0e4 100644 --- a/src/wallet/test/walletdb_tests.cpp +++ b/src/wallet/test/walletdb_tests.cpp @@ -9,6 +9,7 @@ #include <boost/test/unit_test.hpp> +namespace wallet { BOOST_FIXTURE_TEST_SUITE(walletdb_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(walletdb_readkeyvalue) @@ -27,3 +28,4 @@ BOOST_AUTO_TEST_CASE(walletdb_readkeyvalue) } BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/transaction.cpp b/src/wallet/transaction.cpp index a926c0ecc1..a46846c1d4 100644 --- a/src/wallet/transaction.cpp +++ b/src/wallet/transaction.cpp @@ -4,6 +4,7 @@ #include <wallet/transaction.h> +namespace wallet { bool CWalletTx::IsEquivalentTo(const CWalletTx& _tx) const { CMutableTransaction tx1 {*this->tx}; @@ -23,3 +24,4 @@ int64_t CWalletTx::GetTxTime() const int64_t n = nTimeSmart; return n ? n : nTimeReceived; } +} // namespace wallet diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index 52d72cccf3..00f9c9f154 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -19,6 +19,7 @@ #include <variant> #include <vector> +namespace wallet { //! State of transaction confirmed in a block. struct TxStateConfirmed { uint256 confirmed_block_hash; @@ -303,5 +304,6 @@ public: CWalletTx(CWalletTx const &) = delete; void operator=(CWalletTx const &x) = delete; }; +} // namespace wallet #endif // BITCOIN_WALLET_TRANSACTION_H diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index decdbc7090..7e694d1987 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -48,6 +48,7 @@ using interfaces::FoundBlock; +namespace wallet { const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS{ {WALLET_FLAG_AVOID_REUSE, "You need to rescan the blockchain in order to correctly mark used " @@ -357,12 +358,12 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string& return wallet; } -std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const std::string& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings) +std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings) { DatabaseOptions options; options.require_existing = true; - if (!fs::exists(fs::u8path(backup_file))) { + if (!fs::exists(backup_file)) { error = Untranslated("Backup file does not exist"); status = DatabaseStatus::FAILED_INVALID_BACKUP_FILE; return nullptr; @@ -377,7 +378,7 @@ std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const std::string } auto wallet_file = wallet_path / "wallet.dat"; - fs::copy_file(backup_file, wallet_file, fs::copy_option::fail_if_exists); + fs::copy_file(backup_file, wallet_file, fs::copy_options::none); auto wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings); @@ -951,9 +952,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const wtx.nOrderPos = IncOrderPosNext(&batch); wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx)); wtx.nTimeSmart = ComputeTimeSmart(wtx, rescanning_old_block); - if (IsFromMe(*tx.get())) { - AddToSpends(hash); - } + AddToSpends(hash, &batch); } if (!fInsertedNew) @@ -1506,6 +1505,49 @@ bool DummySignInput(const SigningProvider& provider, CTxIn &tx_in, const CTxOut return true; } +bool FillInputToWeight(CTxIn& txin, int64_t target_weight) +{ + assert(txin.scriptSig.empty()); + assert(txin.scriptWitness.IsNull()); + + int64_t txin_weight = GetTransactionInputWeight(txin); + + // Do nothing if the weight that should be added is less than the weight that already exists + if (target_weight < txin_weight) { + return false; + } + if (target_weight == txin_weight) { + return true; + } + + // Subtract current txin weight, which should include empty witness stack + int64_t add_weight = target_weight - txin_weight; + assert(add_weight > 0); + + // We will want to subtract the size of the Compact Size UInt that will also be serialized. + // However doing so when the size is near a boundary can result in a problem where it is not + // possible to have a stack element size and combination to exactly equal a target. + // To avoid this possibility, if the weight to add is less than 10 bytes greater than + // a boundary, the size will be split so that 2/3rds will be in one stack element, and + // the remaining 1/3rd in another. Using 3rds allows us to avoid additional boundaries. + // 10 bytes is used because that accounts for the maximum size. This does not need to be super precise. + if ((add_weight >= 253 && add_weight < 263) + || (add_weight > std::numeric_limits<uint16_t>::max() && add_weight <= std::numeric_limits<uint16_t>::max() + 10) + || (add_weight > std::numeric_limits<uint32_t>::max() && add_weight <= std::numeric_limits<uint32_t>::max() + 10)) { + int64_t first_weight = add_weight / 3; + add_weight -= first_weight; + + first_weight -= GetSizeOfCompactSize(first_weight); + txin.scriptWitness.stack.emplace(txin.scriptWitness.stack.end(), first_weight, 0); + } + + add_weight -= GetSizeOfCompactSize(add_weight); + txin.scriptWitness.stack.emplace(txin.scriptWitness.stack.end(), add_weight, 0); + assert(GetTransactionInputWeight(txin) == target_weight); + + return true; +} + // Helper for producing a bunch of max-sized low-S low-R signatures (eg 71 bytes) bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, const CCoinControl* coin_control) const { @@ -1514,6 +1556,14 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> for (const auto& txout : txouts) { CTxIn& txin = txNew.vin[nIn]; + // If weight was provided, fill the input to that weight + if (coin_control && coin_control->HasInputWeight(txin.prevout)) { + if (!FillInputToWeight(txin, coin_control->GetInputWeight(txin.prevout))) { + return false; + } + nIn++; + continue; + } // Use max sig if watch only inputs were used or if this particular input is an external input // to ensure a sufficient fee is attained for the requested feerate. const bool use_max_sig = coin_control && (coin_control->fAllowWatchOnly || coin_control->IsExternalSelected(txin.prevout)); @@ -1967,29 +2017,58 @@ OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& chang return *change_type; } - // if m_default_address_type is legacy, use legacy address as change (even - // if some of the outputs are P2WPKH or P2WSH). + // if m_default_address_type is legacy, use legacy address as change. if (m_default_address_type == OutputType::LEGACY) { return OutputType::LEGACY; } - // if any destination is P2WPKH or P2WSH, use P2WPKH for the change - // output. + bool any_tr{false}; + bool any_wpkh{false}; + bool any_sh{false}; + bool any_pkh{false}; + for (const auto& recipient : vecSend) { - // Check if any destination contains a witness program: - int witnessversion = 0; - std::vector<unsigned char> witnessprogram; - if (recipient.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) { - if (GetScriptPubKeyMan(OutputType::BECH32M, true)) { - return OutputType::BECH32M; - } else if (GetScriptPubKeyMan(OutputType::BECH32, true)) { - return OutputType::BECH32; - } else { - return m_default_address_type; - } - } + std::vector<std::vector<uint8_t>> dummy; + const TxoutType type{Solver(recipient.scriptPubKey, dummy)}; + if (type == TxoutType::WITNESS_V1_TAPROOT) { + any_tr = true; + } else if (type == TxoutType::WITNESS_V0_KEYHASH) { + any_wpkh = true; + } else if (type == TxoutType::SCRIPTHASH) { + any_sh = true; + } else if (type == TxoutType::PUBKEYHASH) { + any_pkh = true; + } + } + + const bool has_bech32m_spkman(GetScriptPubKeyMan(OutputType::BECH32M, /*internal=*/true)); + if (has_bech32m_spkman && any_tr) { + // Currently tr is the only type supported by the BECH32M spkman + return OutputType::BECH32M; + } + const bool has_bech32_spkman(GetScriptPubKeyMan(OutputType::BECH32, /*internal=*/true)); + if (has_bech32_spkman && any_wpkh) { + // Currently wpkh is the only type supported by the BECH32 spkman + return OutputType::BECH32; + } + const bool has_p2sh_segwit_spkman(GetScriptPubKeyMan(OutputType::P2SH_SEGWIT, /*internal=*/true)); + if (has_p2sh_segwit_spkman && any_sh) { + // Currently sh_wpkh is the only type supported by the P2SH_SEGWIT spkman + // As of 2021 about 80% of all SH are wrapping WPKH, so use that + return OutputType::P2SH_SEGWIT; + } + const bool has_legacy_spkman(GetScriptPubKeyMan(OutputType::LEGACY, /*internal=*/true)); + if (has_legacy_spkman && any_pkh) { + // Currently pkh is the only type supported by the LEGACY spkman + return OutputType::LEGACY; } + if (has_bech32m_spkman) { + return OutputType::BECH32M; + } + if (has_bech32_spkman) { + return OutputType::BECH32; + } // else use m_default_address_type for change return m_default_address_type; } @@ -2572,9 +2651,9 @@ std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, cons // 4. For backwards compatibility, the name of a data file in -walletdir. const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name)); fs::file_type path_type = fs::symlink_status(wallet_path).type(); - if (!(path_type == fs::file_not_found || path_type == fs::directory_file || - (path_type == fs::symlink_file && fs::is_directory(wallet_path)) || - (path_type == fs::regular_file && fs::PathFromString(name).filename() == fs::PathFromString(name)))) { + if (!(path_type == fs::file_type::not_found || path_type == fs::file_type::directory || + (path_type == fs::file_type::symlink && fs::is_directory(wallet_path)) || + (path_type == fs::file_type::regular && fs::PathFromString(name).filename() == fs::PathFromString(name)))) { error_string = Untranslated(strprintf( "Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and " "database/log.?????????? files can be stored, a location where such a directory could be created, " @@ -3404,3 +3483,4 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat return spk_man; } +} // namespace wallet diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index e2a2aebeb5..e2c5c69c91 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -7,6 +7,7 @@ #define BITCOIN_WALLET_WALLET_H #include <consensus/amount.h> +#include <fs.h> #include <interfaces/chain.h> #include <interfaces/handler.h> #include <outputtype.h> @@ -40,15 +41,20 @@ #include <boost/signals2/signal.hpp> -struct WalletContext; using LoadWalletFn = std::function<void(std::unique_ptr<interfaces::Wallet> wallet)>; +class CScript; +enum class FeeEstimateMode; +struct FeeCalculation; struct bilingual_str; +namespace wallet { +struct WalletContext; + //! Explicitly unload and delete the wallet. //! Blocks the current thread after signaling the unload intent so that all -//! wallet clients release the wallet. +//! wallet pointer owners release the wallet. //! Note that, when blocking is not required, the wallet is implicitly unloaded //! by the shared pointer deleter. void UnloadWallet(std::shared_ptr<CWallet>&& wallet); @@ -60,7 +66,7 @@ std::vector<std::shared_ptr<CWallet>> GetWallets(WalletContext& context); std::shared_ptr<CWallet> GetWallet(WalletContext& context, const std::string& name); std::shared_ptr<CWallet> LoadWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings); std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings); -std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const std::string& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings); +std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings); std::unique_ptr<interfaces::Handler> HandleLoadWallet(WalletContext& context, LoadWalletFn load_wallet); std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); @@ -107,10 +113,7 @@ static constexpr size_t DUMMY_NESTED_P2WPKH_INPUT_SIZE = 91; class CCoinControl; class COutput; -class CScript; class CWalletTx; -struct FeeCalculation; -enum class FeeEstimateMode; class ReserveDestination; //! Default for -addresstype @@ -937,4 +940,7 @@ bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_nam bool DummySignInput(const SigningProvider& provider, CTxIn &tx_in, const CTxOut &txout, bool use_max_sig); +bool FillInputToWeight(CTxIn& txin, int64_t target_weight); +} // namespace wallet + #endif // BITCOIN_WALLET_WALLET_H diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f392649bd9..c11d4b562d 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -26,6 +26,7 @@ #include <optional> #include <string> +namespace wallet { namespace DBKeys { const std::string ACENTRY{"acentry"}; const std::string ACTIVEEXTERNALSPK{"activeexternalspk"}; @@ -1104,7 +1105,7 @@ std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const Databas { bool exists; try { - exists = fs::symlink_status(path).type() != fs::file_not_found; + exists = fs::symlink_status(path).type() != fs::file_type::not_found; } catch (const fs::filesystem_error& e) { error = Untranslated(strprintf("Failed to access database path '%s': %s", fs::PathToString(path), fsbridge::get_filesystem_error_message(e))); status = DatabaseStatus::FAILED_BAD_PATH; @@ -1194,3 +1195,4 @@ std::unique_ptr<WalletDatabase> CreateMockWalletDatabase() return std::make_unique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), ""); #endif } +} // namespace wallet diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 9c752623b3..7d38832aa5 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. @@ -15,6 +15,18 @@ #include <string> #include <vector> +class CScript; +class uint160; +class uint256; +struct CBlockLocator; + +namespace wallet { +class CKeyPool; +class CMasterKey; +class CWallet; +class CWalletTx; +struct WalletContext; + /** * Overview of wallet database classes: * @@ -29,16 +41,6 @@ static const bool DEFAULT_FLUSHWALLET = true; -struct CBlockLocator; -struct WalletContext; -class CKeyPool; -class CMasterKey; -class CScript; -class CWallet; -class CWalletTx; -class uint160; -class uint256; - /** Error statuses for the wallet database */ enum class DBErrors { @@ -297,5 +299,6 @@ std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase(); /** Return object for accessing temporary in-memory database. */ std::unique_ptr<WalletDatabase> CreateMockWalletDatabase(); +} // namespace wallet #endif // BITCOIN_WALLET_WALLETDB_H diff --git a/src/wallet/wallettool.cpp b/src/wallet/wallettool.cpp index d3207fe460..9cd18dd0a5 100644 --- a/src/wallet/wallettool.cpp +++ b/src/wallet/wallettool.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. @@ -16,6 +16,7 @@ #include <wallet/wallet.h> #include <wallet/walletutil.h> +namespace wallet { namespace WalletTool { // The standard wallet deleter function blocks on the validation interface @@ -219,3 +220,4 @@ bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command) return true; } } // namespace WalletTool +} // namespace wallet diff --git a/src/wallet/wallettool.h b/src/wallet/wallettool.h index 09be1dac2c..9e0fe2b0ec 100644 --- a/src/wallet/wallettool.h +++ b/src/wallet/wallettool.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2020 The Bitcoin Core developers +// Copyright (c) 2016-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. @@ -9,10 +9,12 @@ class ArgsManager; +namespace wallet { namespace WalletTool { bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command); } // namespace WalletTool +} // namespace wallet #endif // BITCOIN_WALLET_WALLETTOOL_H diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index 7f813432b3..df1b10a634 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -7,12 +7,13 @@ #include <logging.h> #include <util/system.h> +namespace wallet { fs::path GetWalletDir() { fs::path path; if (gArgs.IsArgSet("-walletdir")) { - path = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + path = gArgs.GetPathArg("-walletdir"); if (!fs::is_directory(path)) { // If the path specified doesn't exist, we return the deliberately // invalid empty string. @@ -42,3 +43,4 @@ WalletFeature GetClosestWalletFeature(int version) } return static_cast<WalletFeature>(0); } +} // namespace wallet diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h index c75e1759bc..788d41ceb7 100644 --- a/src/wallet/walletutil.h +++ b/src/wallet/walletutil.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020 The Bitcoin Core developers +// Copyright (c) 2017-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. @@ -10,6 +10,7 @@ #include <vector> +namespace wallet { /** (client) version numbers for particular wallet features */ enum WalletFeature { @@ -103,5 +104,6 @@ public: WalletDescriptor() {} WalletDescriptor(std::shared_ptr<Descriptor> descriptor, uint64_t creation_time, int32_t range_start, int32_t range_end, int32_t next_index) : descriptor(descriptor), creation_time(creation_time), range_start(range_start), range_end(range_end), next_index(next_index) {} }; +} // namespace wallet #endif // BITCOIN_WALLET_WALLETUTIL_H diff --git a/src/walletinitinterface.h b/src/walletinitinterface.h index 660b0eed5d..7624c2b16d 100644 --- a/src/walletinitinterface.h +++ b/src/walletinitinterface.h @@ -7,7 +7,9 @@ class ArgsManager; +namespace node { struct NodeContext; +} // namespace node class WalletInitInterface { public: @@ -18,7 +20,7 @@ public: /** Check wallet parameter interaction */ virtual bool ParameterInteraction() const = 0; /** Add wallets that should be opened to list of chain clients. */ - virtual void Construct(NodeContext& node) const = 0; + virtual void Construct(node::NodeContext& node) const = 0; virtual ~WalletInitInterface() {} }; diff --git a/src/warnings.h b/src/warnings.h index 7ab0a93e3f..b21e2ea2b8 100644 --- a/src/warnings.h +++ b/src/warnings.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2020 The Bitcoin Core developers +// Copyright (c) 2009-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. diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h index 49c1c2a07d..fa3944e32b 100644 --- a/src/zmq/zmqabstractnotifier.h +++ b/src/zmq/zmqabstractnotifier.h @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 56f4c98317..2c6f24a239 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2015-2020 The Bitcoin Core developers +// Copyright (c) 2015-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. @@ -23,6 +23,8 @@ #include <string> #include <utility> +using node::ReadBlockFromDisk; + static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers; static const char *MSG_HASHBLOCK = "hashblock"; @@ -207,9 +209,10 @@ bool CZMQPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) { uint256 hash = pindex->GetBlockHash(); LogPrint(BCLog::ZMQ, "zmq: Publish hashblock %s to %s\n", hash.GetHex(), this->address); - char data[32]; - for (unsigned int i = 0; i < 32; i++) + uint8_t data[32]; + for (unsigned int i = 0; i < 32; i++) { data[31 - i] = hash.begin()[i]; + } return SendZmqMessage(MSG_HASHBLOCK, data, 32); } @@ -217,9 +220,10 @@ bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &t { uint256 hash = transaction.GetHash(); LogPrint(BCLog::ZMQ, "zmq: Publish hashtx %s to %s\n", hash.GetHex(), this->address); - char data[32]; - for (unsigned int i = 0; i < 32; i++) + uint8_t data[32]; + for (unsigned int i = 0; i < 32; i++) { data[31 - i] = hash.begin()[i]; + } return SendZmqMessage(MSG_HASHTX, data, 32); } diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp index 81859f924f..f9f8b5a9dc 100644 --- a/src/zmq/zmqrpc.cpp +++ b/src/zmq/zmqrpc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2020 The Bitcoin Core developers +// Copyright (c) 2018-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. diff --git a/src/zmq/zmqrpc.h b/src/zmq/zmqrpc.h index 8538adf9d3..ea5d190869 100644 --- a/src/zmq/zmqrpc.h +++ b/src/zmq/zmqrpc.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-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. diff --git a/src/zmq/zmqutil.cpp b/src/zmq/zmqutil.cpp index b0f12388e5..f0568634d4 100644 --- a/src/zmq/zmqutil.cpp +++ b/src/zmq/zmqutil.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-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. diff --git a/src/zmq/zmqutil.h b/src/zmq/zmqutil.h index 90c0b00edb..334b51aa91 100644 --- a/src/zmq/zmqutil.h +++ b/src/zmq/zmqutil.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Bitcoin Core developers +// Copyright (c) 2014-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. |