diff options
Diffstat (limited to 'src')
85 files changed, 1407 insertions, 843 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index bf26cc9674..6364e00d1e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,7 @@ noinst_PROGRAMS = TESTS = BENCHMARKS = -BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/$(MINISKETCH_INCLUDE_DIR_INT) -I$(srcdir)/secp256k1/include -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) +BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/$(MINISKETCH_INCLUDE_DIR_INT) -I$(srcdir)/secp256k1/include -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) $(LEVELDB_CPPFLAGS) LIBBITCOIN_NODE=libbitcoin_node.a LIBBITCOIN_COMMON=libbitcoin_common.a @@ -349,7 +349,7 @@ libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.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_node_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libbitcoin_node_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) libbitcoin_node_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_node_a_SOURCES = \ addrdb.cpp \ @@ -452,7 +452,7 @@ endif # wallet: shared between bitcoind and bitcoin-qt, but only linked # when wallet enabled -libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BDB_CPPFLAGS) $(SQLITE_CFLAGS) +libbitcoin_wallet_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(BDB_CPPFLAGS) $(SQLITE_CFLAGS) libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_a_SOURCES = \ wallet/coincontrol.cpp \ @@ -491,7 +491,7 @@ if USE_BDB libbitcoin_wallet_a_SOURCES += wallet/bdb.cpp wallet/salvage.cpp endif -libbitcoin_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_wallet_tool_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) libbitcoin_wallet_tool_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_wallet_tool_a_SOURCES = \ wallet/wallettool.cpp \ @@ -655,7 +655,7 @@ libbitcoin_common_a_SOURCES = \ $(BITCOIN_CORE_H) # util: shared between all executables. -libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ support/lockedpool.cpp \ @@ -833,7 +833,7 @@ bitcoin_util_LDADD = \ # bitcoin-chainstate binary # bitcoin_chainstate_SOURCES = bitcoin-chainstate.cpp -bitcoin_chainstate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +bitcoin_chainstate_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) bitcoin_chainstate_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) # $(LIBTOOL_APP_LDFLAGS) deliberately omitted here so that we can test linking diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index a23d872250..3ed643d932 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -51,7 +51,7 @@ bench_bench_bitcoin_SOURCES = \ 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_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ bench_bench_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) bench_bench_bitcoin_LDADD = \ $(LIBTEST_UTIL) \ diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index b4acc47aa1..602a118259 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -295,7 +295,7 @@ BITCOIN_QT_RC = qt/res/bitcoin-qt-res.rc BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS -DQT_USE_QSTRINGBUILDER qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ - $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS) + $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS) $(BOOST_CPPFLAGS) qt_libbitcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS) diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index fa822f2954..89c659d4b9 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -27,7 +27,7 @@ TEST_QT_H = \ qt/test/wallettests.h qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ - $(QT_INCLUDES) $(QT_TEST_INCLUDES) + $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(BOOST_CPPFLAGS) qt_test_test_bitcoin_qt_SOURCES = \ init/bitcoin-qt.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 8a2386a2b4..5f2e535e85 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -174,7 +174,8 @@ BITCOIN_TESTS += \ wallet/test/availablecoins_tests.cpp \ wallet/test/init_tests.cpp \ wallet/test/ismine_tests.cpp \ - wallet/test/scriptpubkeyman_tests.cpp + wallet/test/scriptpubkeyman_tests.cpp \ + wallet/test/walletload_tests.cpp FUZZ_SUITE_LD_COMMON +=\ $(SQLITE_LIBS) \ @@ -202,7 +203,7 @@ BITCOIN_TEST_SUITE += \ endif # ENABLE_WALLET test_test_bitcoin_SOURCES = $(BITCOIN_TEST_SUITE) $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) -test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(EVENT_CFLAGS) +test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(BOOST_CPPFLAGS) $(EVENT_CFLAGS) test_test_bitcoin_LDADD = $(LIBTEST_UTIL) if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) @@ -222,7 +223,7 @@ FUZZ_SUITE_LD_COMMON += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif if ENABLE_FUZZ_BINARY -test_fuzz_fuzz_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +test_fuzz_fuzz_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) test_fuzz_fuzz_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_fuzz_LDADD = $(FUZZ_SUITE_LD_COMMON) test_fuzz_fuzz_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) $(PTHREAD_FLAGS) $(RUNTIME_LDFLAGS) diff --git a/src/Makefile.test_fuzz.include b/src/Makefile.test_fuzz.include index b43816636f..11b5c12062 100644 --- a/src/Makefile.test_fuzz.include +++ b/src/Makefile.test_fuzz.include @@ -13,7 +13,7 @@ TEST_FUZZ_H = \ test/fuzz/mempool_utils.h \ test/fuzz/util.h -libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libtest_fuzz_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) libtest_fuzz_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libtest_fuzz_a_SOURCES = \ test/fuzz/fuzz.cpp \ diff --git a/src/Makefile.test_util.include b/src/Makefile.test_util.include index 9306bb6fcc..ada789f1b0 100644 --- a/src/Makefile.test_util.include +++ b/src/Makefile.test_util.include @@ -20,7 +20,7 @@ TEST_UTIL_H = \ test/util/validation.h \ test/util/wallet.h -libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +libtest_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) libtest_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libtest_util_a_SOURCES = \ test/util/blockfilter.cpp \ diff --git a/src/addrdb.cpp b/src/addrdb.cpp index 31f8eadf98..7106d819b0 100644 --- a/src/addrdb.cpp +++ b/src/addrdb.cpp @@ -187,11 +187,11 @@ std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, con auto check_addrman = std::clamp<int32_t>(args.GetIntArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000); addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman); - int64_t nStart = GetTimeMillis(); + const auto start{SteadyClock::now()}; const auto path_addr{args.GetDataDirNet() / "peers.dat"}; try { DeserializeFileDB(path_addr, *addrman, CLIENT_VERSION); - LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->size(), GetTimeMillis() - nStart); + LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); } catch (const DbNotFoundError&) { // Addrman can be in an inconsistent state after failure, reset it addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman); diff --git a/src/banman.cpp b/src/banman.cpp index 508383d9f2..3cd646c148 100644 --- a/src/banman.cpp +++ b/src/banman.cpp @@ -31,12 +31,12 @@ void BanMan::LoadBanlist() if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…").translated); - int64_t n_start = GetTimeMillis(); + const auto start{SteadyClock::now()}; if (m_ban_db.Read(m_banned)) { SweepBanned(); // sweep out unused entries LogPrint(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(), - GetTimeMillis() - n_start); + Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); } else { LogPrintf("Recreating the banlist database\n"); m_banned = {}; @@ -58,13 +58,13 @@ void BanMan::DumpBanlist() SetBannedSetDirty(false); } - int64_t n_start = GetTimeMillis(); + const auto start{SteadyClock::now()}; 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); + Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); } void BanMan::ClearBanned() diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index f3bd543de8..d972b71a65 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -104,7 +104,7 @@ int main(int argc, char* argv[]) } } - for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) { + for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) { BlockValidationState state; if (!chainstate->ActivateBestChain(state, nullptr)) { std::cerr << "Failed to connect best block (" << state.ToString() << ")" << std::endl; @@ -253,7 +253,7 @@ epilogue: GetMainSignals().FlushBackgroundCallbacks(); { LOCK(cs_main); - for (CChainState* chainstate : chainman.GetAll()) { + for (Chainstate* chainstate : chainman.GetAll()) { if (chainstate->CanFlushToDisk()) { chainstate->ForceFlushStateToDisk(); chainstate->ResetCoinsViews(); diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index c2bb89b8cf..d49dc72abf 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -15,7 +15,6 @@ #include <key_io.h> #include <fs.h> #include <policy/policy.h> -#include <policy/rbf.h> #include <primitives/transaction.h> #include <script/script.h> #include <script/sign.h> diff --git a/src/chainparams.cpp b/src/chainparams.cpp index dd7b93234d..c6d4eee7b9 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -93,8 +93,8 @@ public: consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021 consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 709632; // Approximately November 12th, 2021 - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000002927cdceccbd5209e81e80db"); - consensus.defaultAssumeValid = uint256S("0x000000000000000000052d314a259755ca65944e68df6b12a067ea8f1f5a7091"); // 724466 + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000003404ba0801921119f903495e"); + consensus.defaultAssumeValid = uint256S("0x00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd"); // 751565 /** * The message start string is designed to be unlikely to occur in normal data. @@ -107,7 +107,7 @@ public: pchMessageStart[3] = 0xd9; nDefaultPort = 8333; nPruneAfterHeight = 100000; - m_assumed_blockchain_size = 460; + m_assumed_blockchain_size = 496; m_assumed_chain_state_size = 6; genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN); @@ -168,10 +168,10 @@ public: }; chainTxData = ChainTxData{ - // Data from RPC: getchaintxstats 4096 000000000000000000052d314a259755ca65944e68df6b12a067ea8f1f5a7091 - /* nTime */ 1645542140, - /* nTxCount */ 712531200, - /* dTxRate */ 2.891036496010309, + // Data from RPC: getchaintxstats 4096 00000000000000000009c97098b5295f7e5f183ac811fb5d1534040adb93cabd + .nTime = 1661697692, + .nTxCount = 760120522, + .dTxRate = 2.925802860942233, }; } }; @@ -213,8 +213,8 @@ public: consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021 consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay - consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000064728c7be6fe4b2f961"); - consensus.defaultAssumeValid = uint256S("0x00000000000163cfb1f97c4e4098a3692c8053ad9cab5ad9c86b338b5c00b8b7"); // 2143398 + consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000076f6e7cbd0beade5d20"); + consensus.defaultAssumeValid = uint256S("0x0000000000000004877fa2d36316398528de4f347df2f8a96f76613a298ce060"); // 2344474 pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; @@ -222,7 +222,7 @@ public: pchMessageStart[3] = 0x07; nDefaultPort = 18333; nPruneAfterHeight = 1000; - m_assumed_blockchain_size = 40; + m_assumed_blockchain_size = 42; m_assumed_chain_state_size = 2; genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN); @@ -264,10 +264,10 @@ public: }; chainTxData = ChainTxData{ - // Data from RPC: getchaintxstats 4096 00000000d18cfe81cbeea665076807789bd8f831d557632e635bc6e3c003069e - /* nTime */ 1645635119, - /* nTxCount */ 62226341, - /* dTxRate */ 0.07717997442177152, + // Data from RPC: getchaintxstats 4096 0000000000000004877fa2d36316398528de4f347df2f8a96f76613a298ce060 + .nTime = 1661705221, + .nTxCount = 63531852, + .dTxRate = 0.1079119341520164, }; } }; @@ -289,15 +289,15 @@ public: vSeeds.emplace_back("178.128.221.177"); vSeeds.emplace_back("v7ajjeirttkbnt32wpy3c6w3emwnfr3fkla7hpxcfokr3ysd3kqtzmqd.onion:38333"); - consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000000de26b0e471"); - consensus.defaultAssumeValid = uint256S("0x00000112852484b5fe3451572368f93cfd2723279af3464e478aee35115256ef"); // 78788 + consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000001291fc22898"); + consensus.defaultAssumeValid = uint256S("0x000000d1a0e224fa4679d2fb2187ba55431c284fa1b74cbc8cfda866fd4d2c09"); // 105495 m_assumed_blockchain_size = 1; m_assumed_chain_state_size = 0; chainTxData = ChainTxData{ - // Data from RPC: getchaintxstats 4096 0000003d9144c56ac110ae04a0c271a0acce2f14f426b39fdf0d938c96d2eb09 - /* nTime */ 1645631279, - /* nTxCount */ 1257429, - /* dTxRate */ 0.1389638742514995, + // Data from RPC: getchaintxstats 4096 000000d1a0e224fa4679d2fb2187ba55431c284fa1b74cbc8cfda866fd4d2c09 + .nTime = 1661702566, + .nTxCount = 1903567, + .dTxRate = 0.02336701143027275, }; } else { const auto signet_challenge = args.GetArgs("-signetchallenge"); diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h index 5b5c76d51d..f065647d49 100644 --- a/src/chainparamsseeds.h +++ b/src/chainparamsseeds.h @@ -861,17 +861,91 @@ static const uint8_t chainparams_seed_main[] = { }; static const uint8_t chainparams_seed_test[] = { - 0x04,0x20,0xdf,0x55,0xaa,0x83,0xd5,0xc5,0xb8,0xe7,0x75,0x78,0xd4,0x29,0x51,0x4b,0x26,0x1c,0x23,0xdf,0x28,0x4d,0x29,0x85,0x07,0xb5,0xe2,0x29,0x69,0x3e,0x25,0xbb,0x61,0xcf,0x47,0x9d, - 0x04,0x20,0x0a,0xdd,0xa2,0x48,0xb5,0x56,0xa3,0x1f,0xca,0x3c,0x4c,0x9e,0xca,0x6e,0xb3,0xd5,0x5e,0x68,0xf6,0x28,0x31,0x57,0x24,0xfb,0x9d,0x2b,0x55,0x4f,0xd7,0x90,0x62,0xd3,0x47,0x9d, - 0x04,0x20,0x2d,0x04,0xa1,0x4a,0xd4,0x7c,0x7b,0x16,0x2e,0xb7,0xd2,0xa1,0x08,0xc5,0xd2,0xbd,0x53,0x87,0x34,0xdc,0x38,0x26,0xca,0x56,0xf2,0xac,0xc5,0x62,0x70,0x72,0x3f,0x63,0x47,0x9d, - 0x04,0x20,0x30,0x57,0x85,0xe0,0x02,0x4a,0xd1,0x31,0xeb,0x16,0x1b,0x1d,0xa8,0x43,0x0b,0xb4,0xc6,0xac,0x7d,0x46,0x24,0x0b,0x55,0x9d,0x16,0xe6,0x46,0x03,0x72,0xfe,0xd4,0xef,0x47,0x9d, - 0x04,0x20,0x36,0x6c,0xf1,0xd2,0xbb,0xda,0xff,0x8c,0x93,0x61,0x10,0xf2,0x9d,0xa1,0xa4,0x0a,0x30,0x9b,0x0c,0x69,0x6d,0xaa,0xd4,0x9c,0xfd,0xb5,0x5b,0x5e,0x30,0x9f,0xf3,0x13,0x47,0x9d, - 0x04,0x20,0x3e,0xe2,0xf3,0xe5,0xc5,0xbe,0x61,0xdd,0x4c,0x3e,0xdb,0x0d,0xd2,0xf9,0x42,0xe3,0x31,0xb2,0xa8,0x51,0x31,0xf6,0xce,0xc2,0x38,0x20,0x27,0x39,0x73,0x68,0x5a,0x42,0x47,0x9d, - 0x04,0x20,0x51,0x79,0x05,0x9c,0x8a,0xdf,0x03,0xb5,0x1b,0x17,0xc3,0x86,0xb6,0x54,0xcc,0xe0,0x6e,0x58,0xa6,0x41,0x4c,0xcc,0x0c,0x60,0x08,0xa6,0x0f,0x1d,0x11,0xd8,0x29,0xa6,0x47,0x9d, + 0x04,0x20,0xd7,0x13,0xfe,0x00,0xf0,0xf1,0x07,0xcb,0x30,0xb1,0x31,0xc7,0x68,0xbb,0x05,0xca,0x18,0xb5,0x1d,0xb1,0x0f,0xf2,0x7e,0x66,0xdb,0xaa,0xf4,0x05,0xaf,0x37,0x0a,0x62,0x47,0x9d, + 0x04,0x20,0xd1,0x71,0xfe,0x4c,0x9e,0xe9,0x99,0xb1,0x6c,0xd5,0xdd,0x3a,0xc3,0xd8,0x74,0x1d,0x42,0x32,0x9f,0xca,0xe9,0x47,0x9e,0x18,0x74,0x43,0x22,0xb9,0xa5,0x31,0xb9,0x66,0x47,0x9d, + 0x04,0x20,0xd2,0xe4,0xd1,0x40,0x65,0x5d,0x95,0xaf,0xe8,0x67,0xc0,0xe3,0x72,0xfd,0x0a,0x2e,0x35,0xb7,0xbd,0xac,0x67,0x78,0x36,0xe1,0xb8,0xba,0x30,0xcf,0x2e,0x05,0xdd,0x9d,0x47,0x9d, + 0x04,0x20,0xde,0xdd,0xe8,0x01,0x03,0x98,0x3f,0x2d,0x3d,0x8b,0x99,0x27,0xea,0xe1,0xa3,0xde,0xff,0x50,0x30,0xc2,0x41,0x4e,0x7e,0x72,0x24,0x3d,0xad,0x78,0x3c,0xab,0x12,0x67,0x47,0x9d, + 0x04,0x20,0xdb,0x9d,0xe0,0xc8,0x5d,0x65,0x4b,0xe0,0x7b,0x0f,0x63,0x80,0x85,0x21,0x73,0x07,0x94,0x0f,0xb0,0x23,0x38,0xec,0x78,0xb6,0x07,0xa1,0xd2,0xb0,0x82,0xf8,0x20,0xea,0x47,0x9d, + 0x04,0x20,0xdb,0xc9,0xb2,0xe1,0x4b,0x43,0xf1,0xc9,0x3d,0xea,0x51,0x9a,0x71,0x6b,0x4a,0x15,0xe7,0x3e,0xfe,0x8b,0x24,0x7a,0xaa,0xff,0x53,0xf7,0xfc,0x10,0xc6,0xcc,0x14,0x88,0x47,0x9d, + 0x04,0x20,0xe5,0x38,0xc1,0x67,0x52,0x2d,0x6f,0x2f,0xbe,0xc2,0xb3,0x45,0x2b,0x19,0x8c,0x10,0xf3,0x09,0xe5,0x37,0xfe,0x66,0x57,0x6f,0x7a,0x4d,0x78,0xf8,0x50,0x41,0xd6,0x90,0x47,0x9d, + 0x04,0x20,0xed,0x76,0x8d,0x28,0xb0,0x44,0x2c,0xff,0xf4,0xd9,0x6a,0x5c,0xf9,0xca,0x5f,0x81,0xa2,0x23,0x48,0x82,0x24,0x2e,0xfc,0xbe,0x0a,0x1e,0xf9,0x02,0x43,0x31,0x37,0xf5,0x47,0x9d, + 0x04,0x20,0xee,0x57,0x1b,0xab,0xd0,0xd7,0x27,0xca,0xe7,0xaa,0xe2,0x09,0xf3,0x4e,0x80,0x90,0xd2,0x0a,0x9d,0xc4,0x59,0xd0,0xdc,0xa1,0x97,0x09,0x4e,0x2f,0xfe,0x9f,0xa8,0x0a,0x47,0x9d, + 0x04,0x20,0xf7,0xe5,0xb0,0x17,0xdc,0x21,0xed,0xfb,0xb6,0xf5,0xe6,0xb4,0x0b,0xb3,0xf3,0x6c,0xb8,0x3f,0x2a,0x93,0x89,0x66,0x2f,0x05,0x30,0xdf,0xfa,0xdf,0xf2,0x1b,0x52,0x78,0x47,0x9d, + 0x04,0x20,0xf0,0x38,0xe6,0xe3,0xbb,0x4d,0x17,0x56,0xd0,0xae,0xf6,0xf4,0xa9,0x99,0x96,0xa9,0xe8,0xfc,0xfb,0x76,0x08,0xed,0x7f,0xb7,0xf0,0xa0,0xd3,0x8d,0xea,0x18,0x87,0x8c,0x47,0x9d, + 0x04,0x20,0xf1,0x67,0x83,0x6d,0xa7,0x17,0xa6,0xdd,0x1f,0x19,0x5c,0xbd,0x92,0x8e,0x45,0x0c,0x5c,0x2c,0x9d,0x57,0x98,0xe1,0x46,0x40,0x3d,0x87,0x30,0x02,0x9f,0x1d,0x88,0xde,0x47,0x9d, + 0x04,0x20,0xff,0x7b,0xca,0x5b,0xa3,0x4c,0x68,0x7d,0xf1,0x3d,0x18,0xef,0xb4,0x3e,0x39,0x34,0x0d,0x9c,0x3c,0x49,0x9b,0xe7,0x67,0x2c,0x78,0x61,0x42,0x67,0x62,0xd0,0x15,0xb5,0x47,0x9d, + 0x04,0x20,0xff,0xbc,0xb7,0x65,0x60,0x0d,0xc1,0x04,0xbc,0x30,0x95,0x67,0xe9,0x37,0x62,0xf7,0x5b,0xe3,0x2a,0xd6,0x3b,0xaf,0x8a,0x98,0xc9,0xfb,0x4b,0x66,0xb2,0xdc,0x13,0xc0,0x47,0x9d, + 0x04,0x20,0xf8,0x57,0x5e,0x80,0x2d,0xc4,0xc6,0x5e,0x7f,0x15,0x09,0xee,0xcc,0x29,0xf1,0x65,0x53,0x1c,0x41,0xc1,0xf7,0x51,0xa4,0xb0,0x76,0x86,0xe3,0x10,0x24,0x4d,0xd2,0x11,0x47,0x9d, + 0x04,0x20,0xfd,0x74,0x90,0x71,0x06,0xbf,0x2b,0xdc,0x69,0x31,0xf2,0x63,0x1f,0x18,0x17,0x71,0xd2,0x75,0xe4,0xf5,0x35,0x89,0xc0,0x55,0x71,0x05,0xc4,0x77,0x64,0xbf,0x20,0x36,0x47,0x9d, + 0x04,0x20,0xfe,0x4c,0x16,0x4f,0x37,0x75,0xb4,0xe2,0x54,0x7d,0x00,0x21,0x39,0x3a,0x2c,0xb7,0xe8,0x9a,0xf3,0x2f,0x8a,0xf6,0xe4,0x6b,0x7d,0xea,0x18,0xc3,0xc3,0x86,0x57,0xc5,0x47,0x9d, + 0x04,0x20,0x00,0xe5,0x30,0x05,0x39,0xf9,0x05,0xac,0x6d,0x33,0xe5,0xb4,0x3a,0xd1,0x8c,0x75,0xb3,0x5f,0x9b,0xcc,0xd1,0x76,0xa0,0x24,0x84,0x49,0x4b,0x40,0x67,0xee,0x4d,0x93,0x47,0x9d, + 0x04,0x20,0x01,0x25,0x8f,0x4c,0xb4,0x28,0x06,0xaa,0x4f,0xc5,0x5d,0x34,0x19,0x40,0xcd,0xb6,0xb9,0xad,0x52,0x3a,0xc3,0x52,0x05,0x9a,0x97,0x5e,0x69,0x9a,0x2a,0x66,0xde,0x48,0x47,0x9d, + 0x04,0x20,0x02,0xee,0xed,0xe8,0x3d,0x20,0xd1,0xb0,0xb7,0x44,0xd6,0xb9,0x08,0x9b,0x13,0x35,0xee,0xf4,0x0b,0x8a,0x6e,0x10,0xfa,0xbc,0x75,0x14,0xcb,0x28,0xd4,0x40,0x44,0x3a,0x47,0x9d, + 0x04,0x20,0x03,0x88,0x08,0xcf,0x7c,0xa3,0x1c,0xe6,0xd4,0x7a,0x50,0x61,0x1d,0x84,0x5c,0x95,0x89,0x4f,0x03,0x8c,0x91,0xf4,0x67,0xf2,0x4a,0xc4,0x2a,0x44,0x6e,0x47,0xc8,0xae,0x47,0x9d, + 0x04,0x20,0x03,0xe3,0x9a,0xa7,0xe7,0x30,0xa7,0x21,0x93,0x8c,0x52,0x76,0x4b,0x43,0x7d,0x35,0x70,0xa9,0x3d,0x35,0x54,0x11,0x83,0x1b,0xe1,0x7b,0x6d,0xd9,0xaa,0xb2,0x26,0x9b,0x47,0x9d, + 0x04,0x20,0x05,0x9e,0xaf,0x67,0x77,0x31,0xef,0xe7,0x65,0xd4,0x3b,0x86,0x2c,0x0c,0x10,0x9c,0x7d,0x4c,0xe4,0x2d,0xb7,0x05,0x12,0x51,0x17,0xfb,0x15,0x47,0xdd,0xd7,0x5b,0x0e,0x47,0x9d, + 0x04,0x20,0x06,0x30,0xd8,0x03,0x34,0x16,0x0f,0xa4,0x8f,0xb1,0x21,0xc4,0x53,0x19,0x87,0xa3,0x60,0xf1,0xdb,0x2b,0x09,0xf2,0x18,0x1b,0x1e,0x5a,0x78,0x29,0xe7,0x4e,0x12,0x7e,0x47,0x9d, + 0x04,0x20,0x0e,0x90,0xa0,0x77,0x60,0x80,0x95,0x5e,0x1a,0x5f,0xb3,0x1c,0x6d,0x87,0x11,0x20,0x35,0x52,0xe5,0x9d,0x7f,0xf0,0x4d,0xec,0x68,0x30,0xa4,0xca,0xd5,0xaf,0x0e,0x20,0x47,0x9d, + 0x04,0x20,0x09,0x3f,0x9b,0xec,0xe7,0xf0,0xd6,0x03,0xba,0x2b,0xac,0xa3,0x13,0x41,0x9c,0x70,0x0e,0x58,0x9a,0x0c,0xd4,0xc3,0x66,0x84,0x7c,0xa7,0x76,0xd9,0xd3,0xa5,0xff,0xba,0x47,0x9d, + 0x04,0x20,0x0a,0xe8,0xaf,0x6a,0xc9,0xd7,0x03,0x2a,0x8e,0xc7,0xe7,0xd9,0x47,0x77,0x87,0x3d,0xa4,0x09,0xa8,0xb3,0x44,0x2e,0x4a,0xcf,0xaa,0x08,0x3e,0x79,0x4d,0x2e,0x25,0xfd,0x47,0x9d, + 0x04,0x20,0x0d,0x02,0xcf,0x15,0x0e,0x79,0x72,0xab,0xc2,0x25,0xbf,0xab,0x07,0xa1,0xc4,0xe8,0x0e,0xb3,0xe2,0x81,0xcf,0x7e,0xe3,0x4a,0x10,0xc7,0x0e,0x0e,0xbd,0xad,0x32,0x20,0x47,0x9d, + 0x04,0x20,0x1e,0xc5,0x90,0x07,0x29,0x4f,0x7e,0xb3,0x46,0x51,0xe9,0x81,0x65,0x24,0x7f,0xae,0xcd,0x96,0xc6,0x00,0xfe,0x70,0x8c,0xc1,0x8a,0xe2,0xe3,0x80,0x48,0x40,0xab,0x10,0x47,0x9d, + 0x04,0x20,0x18,0xd3,0xc1,0x52,0xa1,0xde,0xaa,0x4e,0x88,0xf3,0x7f,0x92,0x09,0xcc,0x43,0x6b,0x59,0x76,0x3d,0xce,0x2a,0x66,0x7c,0xa3,0xf3,0x39,0xaf,0x73,0xcf,0xf8,0x83,0x89,0x47,0x9d, + 0x04,0x20,0x1c,0x0e,0x75,0xca,0x45,0xb3,0x0f,0xb3,0x7b,0x27,0xb5,0xde,0x22,0x86,0xde,0xe5,0xf3,0xd8,0x95,0x0a,0x11,0x96,0x86,0x84,0xee,0xbd,0x7a,0x04,0xd7,0x90,0xca,0x04,0x47,0x9d, + 0x04,0x20,0x1c,0x66,0x71,0x60,0x3c,0xbf,0x22,0x32,0x91,0x56,0xe9,0xbf,0x74,0xb8,0xd7,0x47,0xc1,0x07,0x2e,0x88,0x59,0xa8,0xb0,0x9a,0xd5,0x93,0x09,0xb6,0xdb,0x6e,0x40,0x6a,0x47,0x9d, + 0x04,0x20,0x1d,0x83,0xcf,0x89,0x90,0x06,0xa6,0x97,0xb2,0xa9,0x01,0x01,0x1f,0x98,0x62,0x04,0x65,0xa5,0x93,0x3e,0x6a,0x08,0x53,0xa3,0x90,0x2e,0xb5,0x02,0x1e,0x78,0x98,0x3d,0x47,0x9d, + 0x04,0x20,0x27,0xe6,0xa8,0x97,0xbc,0x69,0xb7,0x0e,0xd4,0x4d,0xe9,0x9b,0xff,0xe6,0xc9,0xb3,0x3f,0xc5,0xa8,0xa0,0xaf,0x19,0x61,0xd2,0xfb,0x7d,0x5c,0xdf,0x62,0xb0,0x36,0xe6,0x47,0x9d, + 0x04,0x20,0x24,0xe9,0x86,0x63,0x9f,0x96,0xe1,0x42,0x3e,0xa3,0x03,0x9d,0xfd,0x23,0xa4,0xeb,0x05,0xfa,0x3a,0xb1,0xcd,0x3a,0xce,0x24,0xbd,0x87,0x99,0x65,0xd9,0x19,0x75,0xf1,0x47,0x9d, + 0x04,0x20,0x28,0x50,0xc2,0x49,0xb8,0x3e,0x68,0x10,0xe6,0x02,0xdd,0x01,0x42,0xe5,0x41,0xc1,0x58,0xd5,0x5e,0xb8,0x7b,0xae,0x0a,0x90,0x14,0x0f,0xe3,0x97,0xe4,0xfa,0x2b,0xaf,0x47,0x9d, + 0x04,0x20,0x2e,0x43,0x1b,0x30,0xd6,0x62,0x9d,0xf8,0x50,0x8b,0x89,0xcb,0x49,0x2a,0x7b,0x42,0x40,0x10,0x0b,0xfe,0xcd,0xfe,0x6e,0xe8,0x65,0x89,0x2a,0xc3,0x8d,0x49,0xf2,0x2a,0x47,0x9d, + 0x04,0x20,0x36,0x3c,0xd4,0x1f,0x8f,0x63,0xfa,0x49,0x62,0xb5,0x69,0xd6,0x9f,0x42,0xaa,0xfe,0x54,0x14,0xd1,0xd2,0xb2,0xae,0x52,0xe1,0x08,0x7e,0xc6,0x15,0x56,0x45,0xbd,0xb3,0x47,0x9d, + 0x04,0x20,0x38,0x3d,0xac,0xa2,0x19,0x80,0xdc,0x61,0xff,0xb9,0x37,0xd6,0x53,0xf0,0xb0,0x89,0xb6,0x14,0x33,0x62,0x7c,0x33,0x8a,0x3d,0xdc,0xdd,0xba,0xfb,0x70,0xa4,0x6f,0x9b,0x47,0x9d, + 0x04,0x20,0x38,0x04,0x94,0x99,0x3a,0x60,0x61,0x08,0xcc,0xf9,0x43,0x18,0x8f,0x01,0xb5,0x43,0x7e,0x35,0xa5,0x27,0x2a,0xf6,0x85,0x78,0x81,0x36,0xed,0xb6,0xb0,0xd2,0xac,0x77,0x47,0x9d, + 0x04,0x20,0x38,0x54,0xfe,0xde,0xcf,0x83,0xb9,0x06,0x7f,0xaa,0x79,0x96,0x58,0x89,0x78,0x45,0x29,0x51,0x9a,0xbf,0x64,0xd1,0x02,0xe2,0x5f,0x74,0x15,0x2e,0x0d,0x8f,0x81,0x9e,0x47,0x9d, + 0x04,0x20,0x3c,0x0c,0xec,0x7b,0x47,0x74,0x12,0xcc,0xef,0xe1,0x88,0xcb,0x57,0x11,0xd5,0xd8,0x91,0x7e,0x95,0x17,0x0c,0x12,0xe2,0x46,0x7c,0xc0,0xe3,0xe3,0x92,0x26,0xeb,0x85,0x47,0x9d, + 0x04,0x20,0x3d,0x42,0xc6,0x66,0xb0,0x8b,0xcc,0xf9,0x6a,0xfd,0xa7,0x10,0xfe,0x2a,0x45,0xd9,0x3a,0xcd,0x15,0xa4,0x00,0xbf,0xde,0x1a,0x6d,0x3a,0x5b,0xa8,0xc8,0x95,0x6a,0x3c,0x47,0x9d, + 0x04,0x20,0x3d,0xb7,0x5c,0xbf,0x7a,0xb7,0x0f,0xe3,0x21,0xeb,0xa1,0x3c,0x8b,0xf3,0x9d,0x72,0x3d,0x69,0xfc,0xcc,0x22,0xa5,0x1c,0xb4,0x3f,0x98,0xcb,0x63,0xa8,0xc8,0x9f,0xcc,0x47,0x9d, + 0x04,0x20,0x40,0xc7,0x1f,0x78,0x96,0x51,0xc8,0xd4,0x54,0x0f,0x32,0x00,0xda,0x0d,0x2a,0xb4,0x04,0xff,0x0e,0xf3,0x94,0x8d,0xf4,0x5e,0x23,0x74,0xfa,0x0c,0xfa,0x87,0xfb,0x3b,0x47,0x9d, + 0x04,0x20,0x43,0x30,0x0d,0xf9,0x04,0xba,0x10,0x88,0x45,0x56,0xa5,0xee,0x22,0x1d,0xb5,0xe2,0x8d,0xd9,0x1e,0x68,0x8d,0x87,0xaa,0x9b,0x82,0x6a,0x71,0xe5,0x95,0x2b,0x79,0xf6,0x47,0x9d, + 0x04,0x20,0x45,0x0e,0x7a,0x38,0x4d,0x97,0xc8,0xd9,0xc7,0x2b,0xbc,0xae,0xa9,0xe3,0x3a,0x40,0x65,0xf3,0xc0,0xc8,0x31,0xab,0xe9,0x02,0x99,0x82,0xb2,0xa0,0x79,0x60,0x92,0xed,0x47,0x9d, + 0x04,0x20,0x4a,0x3b,0x66,0x48,0xee,0x55,0x05,0xed,0x91,0x14,0x5e,0x57,0x64,0xeb,0x23,0xab,0x56,0x83,0x56,0x36,0x2d,0x6a,0x2f,0xf8,0x28,0x11,0x37,0x3a,0x73,0x76,0x2e,0x6a,0x47,0x9d, + 0x04,0x20,0x4a,0x4b,0x4c,0x27,0xea,0x89,0xb2,0xa6,0x3e,0xf5,0x6e,0xc3,0xa4,0xe8,0xf6,0x5e,0x54,0xcc,0x93,0x64,0xce,0x36,0x82,0xd9,0x5f,0x1b,0x65,0x6b,0x02,0xc6,0x66,0x60,0x47,0x9d, + 0x04,0x20,0x4b,0x74,0xfe,0x48,0xc5,0x79,0xd5,0x77,0xba,0xdf,0x52,0x63,0x40,0xc4,0x30,0x04,0xff,0xf5,0x29,0x01,0xcc,0x15,0x5a,0x58,0xf7,0xc0,0x16,0x28,0x83,0x36,0x60,0xa0,0x47,0x9d, + 0x04,0x20,0x4c,0x6a,0x4c,0x67,0x94,0x97,0xa4,0xe3,0x78,0x9e,0x16,0x65,0x58,0xf5,0x95,0xa9,0xcd,0x94,0x9a,0xbc,0x40,0xc2,0x4e,0x20,0x71,0x72,0xd9,0x02,0x50,0x75,0x9f,0x41,0x47,0x9d, + 0x04,0x20,0x4c,0x85,0xc2,0xc6,0xb5,0x6a,0xf4,0x3d,0x84,0xf9,0xc3,0x8b,0x21,0x7f,0x57,0x7e,0x66,0x66,0x6b,0x6d,0x5f,0x0a,0xd0,0xf0,0x76,0x56,0x65,0x78,0xf8,0xa7,0x42,0x75,0x47,0x9d, + 0x04,0x20,0x52,0xf0,0xcb,0x8e,0xa9,0x27,0xd4,0x21,0x57,0x73,0xcb,0x40,0x17,0x6e,0x83,0x73,0xe4,0x59,0xa9,0x89,0x23,0x14,0x14,0x6a,0x91,0x85,0xd2,0xce,0x1c,0x85,0x05,0x06,0x47,0x9d, + 0x04,0x20,0x55,0x93,0x75,0x82,0x96,0x4c,0xc8,0x24,0x96,0x48,0xb3,0x9e,0x15,0xf5,0xf5,0x6f,0x5b,0xec,0xf6,0x39,0xff,0xa8,0xaf,0x3a,0x4c,0x5d,0x22,0x3d,0xd3,0x14,0xc3,0x05,0x47,0x9d, + 0x04,0x20,0x58,0xbf,0x47,0xe7,0x52,0x8d,0xb5,0x83,0xbc,0x55,0xb1,0xb8,0x02,0xe3,0xdc,0xc2,0xc4,0xe7,0x79,0x85,0xb2,0xe7,0x38,0x27,0xae,0xad,0x0c,0xb8,0x34,0xed,0x71,0xde,0x47,0x9d, + 0x04,0x20,0x59,0x76,0xc7,0xdc,0xb8,0x4d,0x1d,0x51,0x40,0x75,0x43,0x57,0xdd,0x3e,0xa3,0x63,0x06,0x0f,0x5e,0x18,0x29,0x10,0x08,0xac,0xa0,0x60,0xd2,0xf3,0x63,0x6e,0xa6,0x58,0x47,0x9d, 0x04,0x20,0x60,0xbe,0xae,0x7d,0xa3,0x4d,0x6a,0x71,0x1a,0x5d,0xe5,0x98,0x9c,0xde,0xa0,0x99,0x39,0x19,0xd3,0x01,0x0a,0x5d,0x1c,0x21,0x43,0x94,0x92,0x71,0x5d,0x77,0xd7,0xdf,0x47,0x9d, - 0x04,0x20,0x64,0x4e,0x86,0xa1,0x02,0xa1,0x8a,0xef,0xb0,0xd1,0xb5,0x77,0x69,0xb9,0x6a,0xdc,0xdf,0x35,0x8a,0xda,0xa4,0x3e,0x83,0xfa,0x50,0xe6,0xca,0x0e,0x2b,0x99,0x0a,0x17,0x47,0x9d, - 0x04,0x20,0xa2,0x28,0x3c,0x5a,0x5b,0x82,0x32,0x66,0x11,0xe5,0x71,0xff,0x6b,0x25,0x92,0x75,0xdd,0x7a,0x4f,0x90,0x8b,0x1d,0x34,0xa4,0xf1,0x6e,0xb9,0xfb,0xb5,0x2e,0x7c,0x7f,0x47,0x9d, - 0x04,0x20,0xc8,0xb5,0x6a,0xba,0x02,0x26,0x45,0x12,0xfb,0x93,0x8a,0x51,0xe4,0xb0,0xf3,0x94,0xb7,0xc0,0x74,0x72,0xeb,0x67,0x91,0x9e,0x04,0x36,0x6a,0x4b,0xef,0x0d,0x88,0xfe,0x47,0x9d, - 0x04,0x20,0xc8,0xfa,0xcd,0x8c,0xc3,0x6f,0x3c,0xd0,0x27,0x7e,0x7d,0xeb,0x51,0x01,0x65,0xb6,0x9e,0x02,0x09,0x64,0xf4,0x87,0x78,0x7b,0x8f,0x9d,0xaf,0x3b,0xa5,0xcc,0x56,0x2c,0x47,0x9d, + 0x04,0x20,0x62,0x42,0x6d,0x98,0xc4,0xa1,0x16,0xc1,0x7d,0x17,0x9e,0x37,0x94,0x88,0x58,0x76,0xa9,0x13,0x6a,0x98,0x39,0x22,0x58,0x13,0xf8,0x9a,0x99,0xa2,0x25,0x56,0x59,0x05,0x47,0x9d, + 0x04,0x20,0x6a,0xb1,0x07,0x66,0xbe,0x50,0xec,0x8e,0x6b,0x72,0xfc,0xb4,0xc2,0x67,0x26,0xa1,0x7a,0x10,0x15,0xd3,0xd0,0x36,0x7a,0xf0,0x83,0xd0,0xc3,0x59,0x85,0x68,0x90,0xd8,0x47,0x9d, + 0x04,0x20,0x6d,0x6b,0x07,0x72,0xf7,0x45,0x8c,0x1d,0xe3,0x5c,0xf2,0x58,0x20,0xd2,0x95,0x25,0x22,0x51,0xc3,0x59,0x96,0xc1,0xdc,0x7e,0xa4,0x82,0x89,0x0a,0xf5,0x25,0x38,0x1a,0x47,0x9d, + 0x04,0x20,0x77,0xaa,0x57,0x56,0x17,0xce,0xdd,0x79,0x64,0xaf,0x78,0xb2,0xf4,0x91,0x36,0x75,0x1c,0x1c,0xcd,0x31,0x35,0x4a,0xe4,0x8b,0x64,0x65,0x4e,0x06,0xec,0x2a,0xc4,0x95,0x47,0x9d, + 0x04,0x20,0x70,0x11,0x6d,0x2d,0xa7,0xc9,0x9f,0xd8,0xe3,0xe8,0xae,0x5a,0x4a,0x50,0xac,0x3f,0xd6,0x57,0xad,0xd0,0xa5,0x35,0x14,0xd7,0xb1,0x76,0x58,0xb0,0x90,0xa4,0x1c,0x9b,0x47,0x9d, + 0x04,0x20,0x72,0xdb,0xfc,0x04,0x48,0xee,0xec,0xae,0x1b,0xad,0xe6,0x9a,0x87,0xe1,0x17,0xae,0x13,0x70,0xae,0x83,0x90,0x62,0x59,0x30,0xed,0x44,0x43,0xe9,0xab,0xee,0xaa,0xd0,0x47,0x9d, + 0x04,0x20,0x74,0xd8,0x56,0x9c,0x5e,0xb4,0x62,0x12,0xea,0x6f,0x1e,0x3d,0x95,0x22,0x50,0x16,0xe3,0xba,0x45,0xb2,0xa3,0xad,0x26,0xb0,0x13,0x74,0xdd,0xec,0x22,0xe0,0x70,0x9a,0x47,0x9d, + 0x04,0x20,0x75,0x45,0xe9,0x01,0x21,0x81,0x44,0x1b,0x57,0x76,0x8c,0x3f,0x85,0xa9,0x74,0xf4,0x3c,0xf8,0xd5,0x12,0xcf,0x13,0x1e,0x2f,0x18,0x13,0x78,0xa3,0x51,0x59,0x49,0x49,0x47,0x9d, + 0x04,0x20,0x7b,0x3b,0xf1,0xa0,0x78,0xc9,0xba,0xb4,0xd2,0xad,0xed,0x0b,0x1e,0xd2,0x8d,0xd2,0x08,0xd1,0x51,0x5b,0x01,0x74,0x6c,0xc0,0x5d,0xcd,0x4c,0x53,0xf3,0xba,0x16,0xe3,0x47,0x9d, + 0x04,0x20,0x7b,0x11,0x26,0x1d,0xf6,0xa1,0xb7,0xc3,0x36,0x19,0x0d,0x27,0x10,0x36,0xb7,0xd5,0x93,0x60,0xc8,0xf8,0x82,0x79,0x46,0xe8,0x78,0xce,0x29,0x50,0x2b,0x44,0x3f,0x7a,0x47,0x9d, + 0x04,0x20,0x7b,0x96,0x08,0xa2,0x54,0x5c,0xd0,0x94,0x9c,0x0a,0xa7,0xb3,0xea,0x7d,0x38,0x0b,0x8e,0xee,0x91,0xe3,0x91,0xb9,0xc9,0xcc,0x81,0x28,0x2e,0xc3,0x02,0x9a,0xcf,0x65,0x47,0x9d, + 0x04,0x20,0x81,0x34,0x90,0x93,0x9c,0xf9,0xc9,0xe7,0x81,0xa5,0xab,0xf1,0x03,0xe1,0xb3,0x2f,0xf7,0xcf,0x19,0x94,0x2f,0x7a,0x1b,0xc5,0x83,0xc9,0x8c,0xc3,0x5b,0x09,0x96,0x14,0x47,0x9d, + 0x04,0x20,0x86,0x7d,0x81,0xf5,0x72,0x30,0xc0,0x91,0x4c,0x8e,0x04,0x48,0x47,0xce,0xcd,0x43,0xef,0x22,0x67,0x17,0xea,0x95,0x2f,0x51,0x4f,0x57,0x67,0x58,0x21,0xa5,0x2e,0x68,0x47,0x9d, + 0x04,0x20,0x8b,0xfc,0xf6,0xec,0x3b,0x71,0x25,0x88,0xe8,0xc8,0x72,0xc3,0x89,0x05,0x27,0x81,0x28,0x6b,0xb6,0x72,0xa7,0xc5,0x16,0xaa,0x67,0xe6,0x37,0xb7,0x2b,0x99,0xa8,0x97,0x47,0x9d, + 0x04,0x20,0xa2,0x46,0x23,0xd2,0xdb,0x3e,0x7a,0x65,0x05,0xd4,0x45,0x78,0xff,0x3e,0xc1,0x28,0xdb,0xfa,0xf1,0x5e,0x32,0xe9,0x6a,0x8f,0x96,0x45,0x15,0x01,0x7f,0x1f,0x75,0xbf,0x47,0x9d, + 0x04,0x20,0xa8,0xa6,0xbb,0x02,0x06,0x65,0x3b,0xb2,0x52,0x79,0xd1,0xc9,0x6a,0x01,0x42,0x43,0xca,0x69,0xe1,0x69,0x90,0xfe,0x2c,0xd2,0x7c,0x18,0xfd,0xab,0xc7,0x71,0x7f,0x8b,0x47,0x9d, + 0x04,0x20,0xa9,0x7b,0x48,0xf7,0x73,0xcb,0x07,0x37,0x4e,0xaa,0x68,0xc4,0x67,0x08,0xea,0x5b,0x68,0x0a,0xfe,0x14,0x82,0x6a,0xa1,0x79,0x82,0x9c,0x0b,0x52,0x17,0xd6,0x6b,0x1b,0x47,0x9d, + 0x04,0x20,0xb3,0x6e,0x64,0x99,0x26,0x7a,0xeb,0xd4,0x53,0x8c,0x94,0xb1,0x4a,0x37,0x02,0xaa,0xa9,0xc8,0x36,0x11,0xec,0xf9,0x0f,0x08,0xa3,0x9f,0x3e,0xaf,0xd2,0xd1,0x2a,0x0b,0x47,0x9d, + 0x04,0x20,0xb3,0xd4,0x15,0x0e,0x3f,0x12,0xed,0xfc,0xab,0x69,0x55,0x91,0x45,0xcf,0xc1,0x2f,0x35,0xa4,0xf7,0x94,0xff,0xd8,0xbe,0x44,0xc8,0x36,0xaf,0x0f,0xa0,0x4e,0x36,0x22,0x47,0x9d, + 0x04,0x20,0xb6,0x5e,0x39,0xeb,0x93,0x18,0x22,0xad,0x78,0x94,0x34,0x48,0x31,0x8d,0xd1,0x42,0xb7,0x38,0x58,0x49,0xea,0x00,0xb9,0xcf,0x58,0x43,0x38,0x22,0x22,0x88,0x87,0xde,0x47,0x9d, + 0x04,0x20,0xb9,0x80,0xf6,0xa1,0x4a,0x0a,0xc6,0xe3,0x19,0x27,0xe9,0x2d,0x75,0x60,0x14,0x3d,0x2c,0xda,0x97,0x77,0x54,0x9f,0x78,0xb8,0x9b,0x72,0x6a,0x58,0xab,0x8b,0x95,0x95,0x47,0x9d, + 0x04,0x20,0xba,0xab,0x91,0x9c,0x48,0x8b,0x9b,0x34,0x5c,0x30,0xf3,0xd2,0x78,0xd3,0xbf,0x09,0x79,0x23,0x4e,0x18,0x5d,0x5e,0x75,0x6b,0xa2,0x91,0x63,0x2c,0x75,0xfd,0x06,0x36,0x47,0x9d, + 0x04,0x20,0xbb,0x50,0xf0,0x50,0x8d,0xb7,0x6c,0xd4,0x87,0x59,0x0d,0xfd,0x5f,0x51,0x86,0xa8,0x43,0xb3,0x7a,0xe7,0x2f,0x54,0x97,0x7d,0xed,0xc3,0x7b,0x31,0xe6,0xb9,0x05,0xe7,0x47,0x9d, + 0x04,0x20,0xc0,0xc1,0xf5,0x59,0xe8,0x46,0xf6,0x9d,0x41,0xf0,0xde,0x8b,0x32,0xf9,0x6f,0xd6,0xb2,0xd5,0x36,0x56,0x43,0xd3,0x60,0x08,0x55,0x94,0x13,0xf5,0xef,0x7f,0x4d,0x4a,0x47,0x9d, + 0x04,0x20,0xce,0xd3,0xd2,0xba,0x56,0xa1,0xde,0xc9,0xc4,0xdb,0x50,0x7b,0xe9,0x4d,0x59,0x65,0x1c,0x02,0x4a,0xa3,0xea,0x73,0xb2,0x66,0x70,0xe7,0x85,0xc1,0x20,0x60,0x79,0x96,0x47,0x9d, + 0x04,0x20,0xc8,0x88,0xfe,0x71,0x5f,0xa3,0x6c,0x96,0x6a,0xd7,0x9e,0x38,0x84,0x9f,0x44,0xe1,0x6b,0xdc,0x98,0x31,0xad,0x96,0x29,0xe7,0x00,0x83,0x63,0x03,0xae,0x69,0x2e,0x63,0x47,0x9d, + 0x04,0x20,0xcb,0x2a,0x8c,0xe7,0xe5,0x1f,0x4e,0x3a,0x13,0xd6,0x9e,0xd7,0x68,0x51,0x83,0xf4,0x2d,0x3e,0x21,0x38,0x63,0x18,0xe9,0x97,0x27,0xff,0x45,0x48,0xc3,0x6c,0xca,0x59,0x47,0x9d, + 0x04,0x20,0xcb,0x80,0x0d,0xdf,0xf0,0xa6,0x28,0x84,0x98,0xc8,0x47,0x72,0xbe,0x53,0x04,0x43,0x9c,0x3a,0x0e,0x46,0x9c,0x75,0x4c,0x57,0x50,0x98,0xe5,0x25,0x80,0x5d,0xa2,0x91,0x47,0x9d, + 0x04,0x20,0xcb,0xaa,0x0a,0x5d,0x6e,0x8a,0xfa,0x49,0x5a,0x8c,0x0c,0x9d,0x7a,0xe9,0x9d,0xc6,0xe4,0xcd,0xc1,0x6a,0xff,0xbb,0xf1,0x89,0xf1,0xd5,0x16,0x3f,0xdc,0xbb,0xe9,0x1b,0x47,0x9d, }; #endif // BITCOIN_CHAINPARAMSSEEDS_H diff --git a/src/fs.cpp b/src/fs.cpp index 74b167e313..07cce269ed 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -126,7 +126,7 @@ bool FileLock::TryLock() if (hFile == INVALID_HANDLE_VALUE) { return false; } - _OVERLAPPED overlapped = {0}; + _OVERLAPPED overlapped = {}; if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, std::numeric_limits<DWORD>::max(), std::numeric_limits<DWORD>::max(), &overlapped)) { reason = GetErrorReason(); return false; diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 8e00a6278f..e68436cc2c 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -142,7 +142,8 @@ static std::vector<CSubNet> rpc_allow_subnets; //! Work queue for handling longer requests off the event loop thread static std::unique_ptr<WorkQueue<HTTPClosure>> g_work_queue{nullptr}; //! Handlers for (sub)paths -static std::vector<HTTPPathHandler> pathHandlers; +static GlobalMutex g_httppathhandlers_mutex; +static std::vector<HTTPPathHandler> pathHandlers GUARDED_BY(g_httppathhandlers_mutex); //! Bound listening sockets static std::vector<evhttp_bound_socket *> boundSockets; @@ -243,6 +244,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg) // Find registered handler for prefix std::string strURI = hreq->GetURI(); std::string path; + LOCK(g_httppathhandlers_mutex); std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin(); std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end(); for (; i != iend; ++i) { @@ -674,11 +676,13 @@ std::optional<std::string> GetQueryParameterFromUri(const char* uri, const std:: void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler) { LogPrint(BCLog::HTTP, "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch); + LOCK(g_httppathhandlers_mutex); pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler)); } void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch) { + LOCK(g_httppathhandlers_mutex); std::vector<HTTPPathHandler>::iterator i = pathHandlers.begin(); std::vector<HTTPPathHandler>::iterator iend = pathHandlers.end(); for (; i != iend; ++i) diff --git a/src/i2p.cpp b/src/i2p.cpp index f7d480988b..28be8009dc 100644 --- a/src/i2p.cpp +++ b/src/i2p.cpp @@ -325,6 +325,7 @@ void Session::DestGenerate(const Sock& sock) // https://geti2p.net/spec/common-structures#key-certificates // "7" or "EdDSA_SHA512_Ed25519" - "Recent Router Identities and Destinations". // Use "7" because i2pd <2.24.0 does not recognize the textual form. + // If SIGNATURE_TYPE is not specified, then the default one is DSA_SHA1. const Reply& reply = SendRequestAndGetReply(sock, "DEST GENERATE SIGNATURE_TYPE=7", false); m_private_key = DecodeI2PBase64(reply.Get("PRIV")); @@ -378,7 +379,7 @@ void Session::CreateIfNotCreatedAlready() // in the reply in DESTINATION=. const Reply& reply = SendRequestAndGetReply( *sock, - strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT", session_id)); + strprintf("SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT SIGNATURE_TYPE=7", session_id)); m_private_key = DecodeI2PBase64(reply.Get("DESTINATION")); } else { diff --git a/src/index/base.cpp b/src/index/base.cpp index 1ebe89ef7c..88c2ce98fa 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -18,6 +18,9 @@ #include <validation.h> // For g_chainman #include <warnings.h> +#include <string> +#include <utility> + using node::ReadBlockFromDisk; constexpr uint8_t DB_BEST_BLOCK{'B'}; @@ -62,8 +65,8 @@ void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator batch.Write(DB_BEST_BLOCK, locator); } -BaseIndex::BaseIndex(std::unique_ptr<interfaces::Chain> chain) - : m_chain{std::move(chain)} {} +BaseIndex::BaseIndex(std::unique_ptr<interfaces::Chain> chain, std::string name) + : m_chain{std::move(chain)}, m_name{std::move(name)} {} BaseIndex::~BaseIndex() { diff --git a/src/index/base.h b/src/index/base.h index 5a484377e7..349178a535 100644 --- a/src/index/base.h +++ b/src/index/base.h @@ -10,9 +10,11 @@ #include <threadinterrupt.h> #include <validationinterface.h> +#include <string> + class CBlock; class CBlockIndex; -class CChainState; +class Chainstate; namespace interfaces { class Chain; } // namespace interfaces @@ -94,7 +96,8 @@ private: protected: std::unique_ptr<interfaces::Chain> m_chain; - CChainState* m_chainstate{nullptr}; + Chainstate* m_chainstate{nullptr}; + const std::string m_name; void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override; @@ -117,13 +120,13 @@ protected: virtual DB& GetDB() const = 0; /// Get the name of the index for display in logs. - virtual const char* GetName() const = 0; + const std::string& GetName() const LIFETIMEBOUND { return m_name; } /// Update the internal best block index as well as the prune lock. void SetBestBlockIndex(const CBlockIndex* block); public: - BaseIndex(std::unique_ptr<interfaces::Chain> chain); + BaseIndex(std::unique_ptr<interfaces::Chain> chain, std::string name); /// Destructor interrupts sync thread if running and blocks until it exits. virtual ~BaseIndex(); diff --git a/src/index/blockfilterindex.cpp b/src/index/blockfilterindex.cpp index f4837f3456..292e11c874 100644 --- a/src/index/blockfilterindex.cpp +++ b/src/index/blockfilterindex.cpp @@ -97,7 +97,8 @@ static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes; BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type, size_t n_cache_size, bool f_memory, bool f_wipe) - : BaseIndex(std::move(chain)), m_filter_type(filter_type) + : BaseIndex(std::move(chain), BlockFilterTypeName(filter_type) + " block filter index") + , m_filter_type(filter_type) { const std::string& filter_name = BlockFilterTypeName(filter_type); if (filter_name.empty()) throw std::invalid_argument("unknown filter_type"); @@ -105,7 +106,6 @@ BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, Blo fs::path path = gArgs.GetDataDirNet() / "indexes" / "blockfilter" / fs::u8path(filter_name); fs::create_directories(path); - m_name = filter_name + " block filter index"; m_db = std::make_unique<BaseIndex::DB>(path / "db", n_cache_size, f_memory, f_wipe); m_filter_fileseq = std::make_unique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE); } diff --git a/src/index/blockfilterindex.h b/src/index/blockfilterindex.h index a31f7e460e..5af4671091 100644 --- a/src/index/blockfilterindex.h +++ b/src/index/blockfilterindex.h @@ -26,7 +26,6 @@ class BlockFilterIndex final : public BaseIndex { private: BlockFilterType m_filter_type; - std::string m_name; std::unique_ptr<BaseIndex::DB> m_db; FlatFilePos m_next_filter_pos; @@ -52,8 +51,6 @@ protected: BaseIndex::DB& GetDB() const LIFETIMEBOUND override { return *m_db; } - const char* GetName() const LIFETIMEBOUND override { return m_name.c_str(); } - public: /** Constructs the index, which becomes available to be queried. */ explicit BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type, diff --git a/src/index/coinstatsindex.cpp b/src/index/coinstatsindex.cpp index b9029e946a..d3559b1b75 100644 --- a/src/index/coinstatsindex.cpp +++ b/src/index/coinstatsindex.cpp @@ -6,6 +6,7 @@ #include <coins.h> #include <crypto/muhash.h> #include <index/coinstatsindex.h> +#include <kernel/coinstats.h> #include <node/blockstorage.h> #include <serialize.h> #include <txdb.h> @@ -104,7 +105,7 @@ struct DBHashKey { std::unique_ptr<CoinStatsIndex> g_coin_stats_index; CoinStatsIndex::CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe) - : BaseIndex(std::move(chain)) + : BaseIndex(std::move(chain), "coinstatsindex") { fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"}; fs::create_directories(path); @@ -322,13 +323,13 @@ static bool LookUpOne(const CDBWrapper& db, const interfaces::BlockKey& block, D return db.Read(DBHashKey(block.hash), result); } -std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex* block_index) const +std::optional<CCoinsStats> CoinStatsIndex::LookUpStats(const CBlockIndex& block_index) const { - CCoinsStats stats{Assert(block_index)->nHeight, block_index->GetBlockHash()}; + CCoinsStats stats{block_index.nHeight, block_index.GetBlockHash()}; stats.index_used = true; DBVal entry; - if (!LookUpOne(*m_db, {block_index->GetBlockHash(), block_index->nHeight}, entry)) { + if (!LookUpOne(*m_db, {block_index.GetBlockHash(), block_index.nHeight}, entry)) { return std::nullopt; } diff --git a/src/index/coinstatsindex.h b/src/index/coinstatsindex.h index c4af223388..fa59cb1ab1 100644 --- a/src/index/coinstatsindex.h +++ b/src/index/coinstatsindex.h @@ -5,11 +5,14 @@ #ifndef BITCOIN_INDEX_COINSTATSINDEX_H #define BITCOIN_INDEX_COINSTATSINDEX_H -#include <chain.h> #include <crypto/muhash.h> -#include <flatfile.h> #include <index/base.h> -#include <kernel/coinstats.h> + +class CBlockIndex; +class CDBBatch; +namespace kernel { +struct CCoinsStats; +} /** * CoinStatsIndex maintains statistics on the UTXO set. @@ -17,7 +20,6 @@ class CoinStatsIndex final : public BaseIndex { private: - std::string m_name; std::unique_ptr<BaseIndex::DB> m_db; MuHash3072 m_muhash; @@ -49,14 +51,12 @@ protected: BaseIndex::DB& GetDB() const override { return *m_db; } - const char* GetName() const override { return "coinstatsindex"; } - public: // Constructs the index, which becomes available to be queried. explicit CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false); // Look up stats for a specific block using CBlockIndex - std::optional<kernel::CCoinsStats> LookUpStats(const CBlockIndex* block_index) const; + std::optional<kernel::CCoinsStats> LookUpStats(const CBlockIndex& block_index) const; }; /// The global UTXO set hash object. diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index b719aface8..a4fe1b611e 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -49,7 +49,7 @@ bool TxIndex::DB::WriteTxs(const std::vector<std::pair<uint256, CDiskTxPos>>& v_ } TxIndex::TxIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe) - : BaseIndex(std::move(chain)), m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe)) + : BaseIndex(std::move(chain), "txindex"), m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe)) {} TxIndex::~TxIndex() = default; diff --git a/src/index/txindex.h b/src/index/txindex.h index be240c4582..8c1aa00033 100644 --- a/src/index/txindex.h +++ b/src/index/txindex.h @@ -27,8 +27,6 @@ protected: BaseIndex::DB& GetDB() const override; - const char* GetName() const override { return "txindex"; } - public: /// Constructs the index, which becomes available to be queried. explicit TxIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false); diff --git a/src/init.cpp b/src/init.cpp index f3cb763ecc..25b40c6c6e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -263,7 +263,7 @@ void Shutdown(NodeContext& node) // FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing if (node.chainman) { LOCK(cs_main); - for (CChainState* chainstate : node.chainman->GetAll()) { + for (Chainstate* chainstate : node.chainman->GetAll()) { if (chainstate->CanFlushToDisk()) { chainstate->ForceFlushStateToDisk(); } @@ -294,7 +294,7 @@ void Shutdown(NodeContext& node) if (node.chainman) { LOCK(cs_main); - for (CChainState* chainstate : node.chainman->GetAll()) { + for (Chainstate* chainstate : node.chainman->GetAll()) { if (chainstate->CanFlushToDisk()) { chainstate->ForceFlushStateToDisk(); chainstate->ResetCoinsViews(); @@ -476,7 +476,6 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); // TODO: remove the sentence "Nodes not using ... incoming connections." once the changes from // https://github.com/bitcoin/bitcoin/pull/23542 have become widespread. argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port>. Nodes not using the default ports (default: %u, testnet: %u, signet: %u, regtest: %u) are unlikely to get incoming connections. Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); @@ -566,6 +565,8 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-mempoolfullrbf", strprintf("Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", DEFAULT_MEMPOOL_FULL_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); + argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, + OptionsCategory::NODE_RELAY); argsman.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-whitelistforcerelay", strprintf("Add 'forcerelay' permission to whitelisted inbound peers with default permissions. This will relay transactions even if the transactions were already in the mempool. (default: %d)", DEFAULT_WHITELISTFORCERELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); @@ -723,6 +724,16 @@ void InitParameterInteraction(ArgsManager& args) if (args.SoftSetBoolArg("-whitelistrelay", true)) LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__); } + if (args.IsArgSet("-onlynet")) { + const auto onlynets = args.GetArgs("-onlynet"); + bool clearnet_reachable = std::any_of(onlynets.begin(), onlynets.end(), [](const auto& net) { + const auto n = ParseNetwork(net); + return n == NET_IPV4 || n == NET_IPV6; + }); + if (!clearnet_reachable && args.SoftSetBoolArg("-dnsseed", false)) { + LogPrintf("%s: parameter interaction: -onlynet excludes IPv4 and IPv6 -> setting -dnsseed=0\n", __func__); + } + } } /** @@ -1274,6 +1285,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } if (!args.IsArgSet("-cjdnsreachable")) { + if (args.IsArgSet("-onlynet") && IsReachable(NET_CJDNS)) { + return InitError( + _("Outbound connections restricted to CJDNS (-onlynet=cjdns) but " + "-cjdnsreachable is not provided")); + } SetReachable(NET_CJDNS, false); } // Now IsReachable(NET_CJDNS) is true if: @@ -1281,6 +1297,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // 2.1. -onlynet is not given or // 2.2. -onlynet=cjdns is given + // Requesting DNS seeds entails connecting to IPv4/IPv6, which -onlynet options may prohibit: + // If -dnsseed=1 is explicitly specified, abort. If it's left unspecified by the user, we skip + // the DNS seeds by adjusting -dnsseed in InitParameterInteraction. + if (args.GetBoolArg("-dnsseed") == true && !IsReachable(NET_IPV4) && !IsReachable(NET_IPV6)) { + return InitError(strprintf(_("Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6"))); + }; + // Check for host lookup allowed before parsing any network related parameters fNameLookup = args.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); @@ -1307,6 +1330,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) onion_proxy = addrProxy; } + const bool onlynet_used_with_onion{args.IsArgSet("-onlynet") && IsReachable(NET_ONION)}; + // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses // -noonion (or -onion=0) disables connecting to .onion entirely // An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none) @@ -1314,6 +1339,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) if (onionArg != "") { if (onionArg == "0") { // Handle -noonion/-onion=0 onion_proxy = Proxy{}; + if (onlynet_used_with_onion) { + return InitError( + _("Outbound connections restricted to Tor (-onlynet=onion) but the proxy for " + "reaching the Tor network is explicitly forbidden: -onion=0")); + } } else { CService addr; if (!Lookup(onionArg, addr, 9050, fNameLookup) || !addr.IsValid()) { @@ -1326,11 +1356,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) if (onion_proxy.IsValid()) { SetProxy(NET_ONION, onion_proxy); } else { - if (args.IsArgSet("-onlynet") && IsReachable(NET_ONION)) { + // If -listenonion is set, then we will (try to) connect to the Tor control port + // later from the torcontrol thread and may retrieve the onion proxy from there. + const bool listenonion_disabled{!args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)}; + if (onlynet_used_with_onion && listenonion_disabled) { return InitError( _("Outbound connections restricted to Tor (-onlynet=onion) but the proxy for " - "reaching the Tor network is not provided (no -proxy= and no -onion= given) or " - "it is explicitly forbidden (-onion=0)")); + "reaching the Tor network is not provided: none of -proxy, -onion or " + "-listenonion is given")); } SetReachable(NET_ONION, false); } @@ -1413,7 +1446,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) }; uiInterface.InitMessage(_("Loading block index…").translated); - const int64_t load_block_index_start_time = GetTimeMillis(); + const auto load_block_index_start_time{SteadyClock::now()}; auto catch_exceptions = [](auto&& f) { try { return f(); @@ -1432,7 +1465,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) std::tie(status, error) = catch_exceptions([&]{ return VerifyLoadedChainstate(chainman, options);}); if (status == node::ChainstateLoadStatus::SUCCESS) { fLoaded = true; - LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time); + LogPrintf(" block index %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - load_block_index_start_time)); } } @@ -1515,7 +1548,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) if (fPruneMode) { if (!fReindex) { LOCK(cs_main); - for (CChainState* chainstate : chainman.GetAll()) { + for (Chainstate* chainstate : chainman.GetAll()) { uiInterface.InitMessage(_("Pruning blockstore…").translated); chainstate->PruneAndFlush(); } @@ -1729,6 +1762,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } SetProxy(NET_I2P, Proxy{addr}); } else { + if (args.IsArgSet("-onlynet") && IsReachable(NET_I2P)) { + return InitError( + _("Outbound connections restricted to i2p (-onlynet=i2p) but " + "-i2psam is not provided")); + } SetReachable(NET_I2P, false); } diff --git a/src/kernel/mempool_persist.cpp b/src/kernel/mempool_persist.cpp index 1a1cf2bbdc..a14b2e6163 100644 --- a/src/kernel/mempool_persist.cpp +++ b/src/kernel/mempool_persist.cpp @@ -37,7 +37,7 @@ namespace kernel { static const uint64_t MEMPOOL_DUMP_VERSION = 1; -bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, CChainState& active_chainstate, FopenFn mockable_fopen_function) +bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active_chainstate, FopenFn mockable_fopen_function) { if (load_path.empty()) return false; diff --git a/src/kernel/mempool_persist.h b/src/kernel/mempool_persist.h index 9a15ec6dca..ca4917e38b 100644 --- a/src/kernel/mempool_persist.h +++ b/src/kernel/mempool_persist.h @@ -7,7 +7,7 @@ #include <fs.h> -class CChainState; +class Chainstate; class CTxMemPool; namespace kernel { @@ -19,7 +19,7 @@ bool DumpMempool(const CTxMemPool& pool, const fs::path& dump_path, /** Load the mempool from disk. */ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, - CChainState& active_chainstate, + Chainstate& active_chainstate, fsbridge::FopenFn mockable_fopen_function = fsbridge::fopen); } // namespace kernel diff --git a/src/net.cpp b/src/net.cpp index 6659b64246..0cc14b1d2a 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1500,12 +1500,12 @@ void CConnman::ThreadDNSAddressSeed() void CConnman::DumpAddresses() { - int64_t nStart = GetTimeMillis(); + const auto start{SteadyClock::now()}; DumpPeerAddresses(::gArgs, addrman); LogPrint(BCLog::NET, "Flushed %d addresses to peers.dat %dms\n", - addrman.size(), GetTimeMillis() - nStart); + addrman.size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); } void CConnman::ProcessAddrFetch() @@ -1642,15 +1642,28 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) LOCK2(m_addr_fetches_mutex, m_added_nodes_mutex); if (m_addr_fetches.empty() && m_added_nodes.empty()) { add_fixed_seeds_now = true; - LogPrintf("Adding fixed seeds as -dnsseed=0, -addnode is not provided and all -seednode(s) attempted\n"); + LogPrintf("Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet), -addnode is not provided and all -seednode(s) attempted\n"); } } if (add_fixed_seeds_now) { + std::vector<CAddress> seed_addrs{ConvertSeeds(Params().FixedSeeds())}; + // We will not make outgoing connections to peers that are unreachable + // (e.g. because of -onlynet configuration). + // Therefore, we do not add them to addrman in the first place. + // Note that if you change -onlynet setting from one network to another, + // peers.dat will contain only peers of unreachable networks and + // manual intervention will be needed (either delete peers.dat after + // configuration change or manually add some reachable peer using addnode), + // see <https://github.com/bitcoin/bitcoin/issues/26035> for details. + seed_addrs.erase(std::remove_if(seed_addrs.begin(), seed_addrs.end(), + [](const CAddress& addr) { return !IsReachable(addr); }), + seed_addrs.end()); CNetAddr local; local.SetInternal("fixedseeds"); - addrman.Add(ConvertSeeds(Params().FixedSeeds()), local); + addrman.Add(seed_addrs, local); add_fixed_seeds = false; + LogPrintf("Added %d fixed seeds from reachable networks.\n", seed_addrs.size()); } } @@ -164,6 +164,7 @@ bool SeenLocal(const CService& addr); bool IsLocal(const CService& addr); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = nullptr); CService GetLocalAddress(const CNetAddr& addrPeer); +CService MaybeFlipIPv6toCJDNS(const CService& service); extern bool fDiscover; diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 42b6b017fe..57f81e6bb6 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -882,7 +882,7 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile // We can't hold cs_main during ActivateBestChain even though we're accessing // the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve // the relevant pointers before the ABC call. - for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) { + for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) { BlockValidationState state; if (!chainstate->ActivateBestChain(state, nullptr)) { LogPrintf("Failed to connect best block (%s)\n", state.ToString()); diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index 9b76371aae..37d74ed102 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -26,7 +26,7 @@ class CBlockFileInfo; class CBlockUndo; class CChain; class CChainParams; -class CChainState; +class Chainstate; class ChainstateManager; struct CCheckpointData; struct FlatFilePos; @@ -75,12 +75,12 @@ struct PruneLockInfo { * 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., + * This data is used mostly in `Chainstate` - information about, e.g., * candidate tips is not maintained here. */ class BlockManager { - friend CChainState; + friend Chainstate; friend ChainstateManager; private: diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index c4dd9ba6c5..3f1d6dd743 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -28,7 +28,7 @@ namespace node { ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes, const ChainstateLoadOptions& options) { - auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull(); }; @@ -101,7 +101,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize // At this point we're either in reindex or we've loaded a useful // block tree into BlockIndex()! - for (CChainState* chainstate : chainman.GetAll()) { + for (Chainstate* chainstate : chainman.GetAll()) { chainstate->InitCoinsDB( /*cache_size_bytes=*/cache_sizes.coins_db, /*in_memory=*/options.coins_db_in_memory, @@ -140,7 +140,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize if (!options.reindex) { auto chainstates{chainman.GetAll()}; if (std::any_of(chainstates.begin(), chainstates.end(), - [](const CChainState* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) { + [](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) { return {ChainstateLoadStatus::FAILURE, strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."), chainman.GetConsensus().SegwitHeight)}; }; @@ -151,13 +151,13 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options) { - auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { + auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull(); }; LOCK(cs_main); - for (CChainState* chainstate : chainman.GetAll()) { + for (Chainstate* chainstate : chainman.GetAll()) { if (!is_coinsview_empty(chainstate)) { const CBlockIndex* tip = chainstate->m_chain.Tip(); if (tip && tip->nTime > GetTime() + MAX_FUTURE_BLOCK_TIME) { diff --git a/src/node/miner.cpp b/src/node/miner.cpp index f04742deeb..b277188c1f 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -62,7 +62,7 @@ BlockAssembler::Options::Options() nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT; } -BlockAssembler::BlockAssembler(CChainState& chainstate, const CTxMemPool* mempool, const Options& options) +BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options) : chainparams{chainstate.m_chainman.GetParams()}, m_mempool(mempool), m_chainstate(chainstate) @@ -87,7 +87,7 @@ static BlockAssembler::Options DefaultOptions() return options; } -BlockAssembler::BlockAssembler(CChainState& chainstate, const CTxMemPool* mempool) +BlockAssembler::BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool) : BlockAssembler(chainstate, mempool, DefaultOptions()) {} void BlockAssembler::resetBlock() diff --git a/src/node/miner.h b/src/node/miner.h index 26454df3df..7269ce1186 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -148,7 +148,7 @@ private: const CChainParams& chainparams; const CTxMemPool* const m_mempool; - CChainState& m_chainstate; + Chainstate& m_chainstate; public: struct Options { @@ -157,8 +157,8 @@ public: CFeeRate blockMinFeeRate; }; - explicit BlockAssembler(CChainState& chainstate, const CTxMemPool* mempool); - explicit BlockAssembler(CChainState& chainstate, const CTxMemPool* mempool, const Options& options); + explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool); + explicit BlockAssembler(Chainstate& chainstate, const CTxMemPool* mempool, const Options& options); /** Construct a new block template with coinbase to scriptPubKeyIn */ std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn); diff --git a/src/node/utxo_snapshot.h b/src/node/utxo_snapshot.h index 401d4baaeb..9dd6f06997 100644 --- a/src/node/utxo_snapshot.h +++ b/src/node/utxo_snapshot.h @@ -11,7 +11,7 @@ namespace node { //! Metadata describing a serialized version of a UTXO set from which an -//! assumeutxo CChainState can be constructed. +//! assumeutxo Chainstate can be constructed. class SnapshotMetadata { public: diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 1c1328e000..894a401e56 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -431,7 +431,7 @@ void BitcoinGUI::createActions() bool wallet_name_ok; /*: Title of pop-up window shown when the user is attempting to -+ restore a wallet. */ + restore a wallet. */ QString title = tr("Restore Wallet"); //: Label of the input field where the name of the wallet is entered. QString label = tr("Wallet Name"); diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 4489c00932..3df4d4d921 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -60,6 +60,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Error reading %s! Transaction data may be missing or incorrect. Rescanning " "wallet."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: Address book data in wallet cannot be identified to belong to " +"migrated wallets"), +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\"."), @@ -67,9 +70,18 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: Dumpfile version is not supported. This version of bitcoin-wallet " "only supports version 1 dumpfiles. Got dumpfile with version %s"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: Duplicate descriptors created during migration. Your wallet may be " +"corrupted."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Error: Legacy wallets only support the \"legacy\", \"p2sh-segwit\", and " "\"bech32\" address types"), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: Transaction %s in wallet cannot be identified to belong to migrated " +"wallets"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Error: Unable to produce descriptors for this legacy wallet. Make sure the " +"wallet is unlocked first"), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Failed to rename invalid peers.dat file. Please move or delete it and try " "again."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -79,6 +91,9 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "File %s already exists. If you are sure this is what you want, move it out " "of the way first."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet " +"forbids connections to IPv4/IPv6"), +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", "" @@ -98,8 +113,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "be provided."), QT_TRANSLATE_NOOP("bitcoin-core", "" "Outbound connections restricted to Tor (-onlynet=onion) but the proxy for " -"reaching the Tor network is not provided (no -proxy= and no -onion= given) " -"or it is explicitly forbidden (-onion=0)"), +"reaching the Tor network is explicitly forbidden: -onion=0"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Outbound connections restricted to Tor (-onlynet=onion) but the proxy for " +"reaching the Tor network is not provided: none of -proxy, -onion or -" +"listenonion is given"), QT_TRANSLATE_NOOP("bitcoin-core", "" "Please check that your computer's date and time are correct! If your clock " "is wrong, %s will not work properly."), @@ -156,6 +174,14 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" "Unknown wallet file format \"%s\" provided. Please provide one of \"bdb\" or " "\"sqlite\"."), QT_TRANSLATE_NOOP("bitcoin-core", "" +"Unrecognized descriptor found. Loading wallet %s\n" +"\n" +"The wallet might had been created on a newer version.\n" +"Please try running the latest software version.\n"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"Unsupported category-specific logging level -loglevel=%s. Expected -" +"loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s."), +QT_TRANSLATE_NOOP("bitcoin-core", "" "Unsupported chainstate database format found. Please restart with -reindex-" "chainstate. This will rebuild the chainstate database."), QT_TRANSLATE_NOOP("bitcoin-core", "" @@ -176,6 +202,12 @@ QT_TRANSLATE_NOOP("bitcoin-core", "" QT_TRANSLATE_NOOP("bitcoin-core", "" "You need to rebuild the database using -reindex to go back to unpruned " "mode. This will redownload the entire blockchain"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"\n" +"Unable to cleanup failed migration"), +QT_TRANSLATE_NOOP("bitcoin-core", "" +"\n" +"Unable to restore backup of wallet."), 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"), @@ -203,15 +235,25 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error reading from database, shutting down."), QT_TRANSLATE_NOOP("bitcoin-core", "Error reading next record from wallet database"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Could not add watchonly tx to watchonly wallet"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Could not delete watchonly transactions"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Couldn't create cursor into database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low for %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Dumpfile checksum does not match. Computed %s, expected %s"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Failed to create new watchonly wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Got key that was not hex: %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Got value that was not hex: %s"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Keypool ran out, please call keypoolrefill first"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Missing checksum"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: No %s addresses available."), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Not all watchonly txs could be deleted"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: This wallet already uses SQLite"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: This wallet is already a descriptor wallet"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to begin reading all records in the database"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to make a backup of your wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to parse version %u as a uint32_t"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to read all records in the database"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to remove watchonly address book data"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unable to write record to new wallet"), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to rescan the wallet during initialization"), @@ -283,11 +325,13 @@ 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", "Unable to unload the wallet before migrating"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown -blockfilterindex value %s."), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown address type '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown change type '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown network specified in -onlynet: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Unknown new rules activated (versionbit %i)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported global logging level -loglevel=%s. Valid values: %s."), QT_TRANSLATE_NOOP("bitcoin-core", "Unsupported logging category %s=%s."), QT_TRANSLATE_NOOP("bitcoin-core", "User Agent comment (%s) contains unsafe characters."), QT_TRANSLATE_NOOP("bitcoin-core", "Verifying blocks…"), diff --git a/src/qt/forms/intro.ui b/src/qt/forms/intro.ui index a1e94f99e6..9ab91f6aa9 100644 --- a/src/qt/forms/intro.ui +++ b/src/qt/forms/intro.ui @@ -203,7 +203,7 @@ <item> <widget class="QLabel" name="lblExplanation1"> <property name="text"> - <string>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.</string> + <string>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</string> </property> <property name="wordWrap"> <bool>true</bool> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 5cc21dd40b..b9f0be41e3 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -982,7 +982,7 @@ void PrintSlotException( std::string description = sender->metaObject()->className(); description += "->"; description += receiver->metaObject()->className(); - PrintExceptionContinue(exception, description.c_str()); + PrintExceptionContinue(exception, description); } void ShowModalDialogAsynchronously(QDialog* dialog) diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index 883d3fe24a..586240445e 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -751,7 +751,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <message> <location line="+8"/> <source>Restore Wallet</source> - <extracomment>Title of pop-up window shown when the user is attempting to + restore a wallet.</extracomment> + <extracomment>Title of pop-up window shown when the user is attempting to restore a wallet.</extracomment> <translation type="unfinished"></translation> </message> <message> @@ -1370,12 +1370,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+157"/> - <source>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> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+32"/> + <location line="+189"/> <source>Limit block chain storage to</source> <translation type="unfinished"></translation> </message> @@ -1395,7 +1390,12 @@ Signing is only possible with addresses of the type 'legacy'.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+10"/> + <location line="-10"/> + <source>When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+20"/> <source>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> <translation type="unfinished"></translation> </message> @@ -5228,7 +5228,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+6"/> <source>Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> <translation type="unfinished"></translation> </message> @@ -5243,12 +5243,12 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+6"/> <source>Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source> <translation type="unfinished"></translation> </message> <message> - <location line="+6"/> + <location line="+12"/> <source>Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> <translation type="unfinished"></translation> </message> @@ -5258,7 +5258,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+6"/> <source>Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> <translation type="unfinished"></translation> </message> @@ -5288,12 +5288,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> - <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided (no -proxy= and no -onion= given) or it is explicitly forbidden (-onion=0)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location line="+4"/> + <location line="+10"/> <source>Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.</source> <translation type="unfinished"></translation> </message> @@ -5378,7 +5373,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+11"/> <source>Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source> <translation type="unfinished"></translation> </message> @@ -5413,7 +5408,7 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+3"/> + <location line="+9"/> <source>%s is set very high!</source> <translation type="unfinished"></translation> </message> @@ -5448,12 +5443,12 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="-65"/> + <location line="-79"/> <source>The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-104"/> + <location line="-122"/> <source>%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source> <translation type="unfinished"></translation> </message> @@ -5488,12 +5483,73 @@ Go to File > Open Wallet to load a wallet. <translation type="unfinished"></translation> </message> <message> - <location line="+19"/> + <location line="+9"/> + <source>Error: Address book data in wallet cannot be identified to belong to migrated wallets</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> + <source>Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+6"/> + <source>Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+114"/> + <location line="+9"/> + <source>Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+21"/> + <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source>Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+59"/> + <source>Unrecognized descriptor found. Loading wallet %s + +The wallet might had been created on a newer version. +Please try running the latest software version. +</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+5"/> + <source>Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+24"/> + <source> +Unable to cleanup failed migration</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> + <source> +Unable to restore backup of wallet.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+10"/> <source>Config setting for %s only applied on %s network when in [%s] section.</source> <translation type="unfinished"></translation> </message> @@ -5594,6 +5650,16 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> + <source>Error: Could not add watchonly tx to watchonly wallet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error: Could not delete watchonly transactions</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Error: Couldn't create cursor into database</source> <translation type="unfinished"></translation> </message> @@ -5609,6 +5675,11 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> + <source>Error: Failed to create new watchonly wallet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Error: Got key that was not hex: %s</source> <translation type="unfinished"></translation> </message> @@ -5634,11 +5705,46 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> + <source>Error: Not all watchonly txs could be deleted</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error: This wallet already uses SQLite</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error: This wallet is already a descriptor wallet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error: Unable to begin reading all records in the database</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error: Unable to make a backup of your wallet</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Error: Unable to parse version %u as a uint32_t</source> <translation type="unfinished"></translation> </message> <message> <location line="+1"/> + <source>Error: Unable to read all records in the database</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> + <source>Error: Unable to remove watchonly address book data</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Error: Unable to write record to new wallet</source> <translation type="unfinished"></translation> </message> @@ -5994,6 +6100,11 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> + <source>Unable to unload the wallet before migrating</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Unknown -blockfilterindex value %s.</source> <translation type="unfinished"></translation> </message> @@ -6019,6 +6130,11 @@ Go to File > Open Wallet to load a wallet. </message> <message> <location line="+1"/> + <source>Unsupported global logging level -loglevel=%s. Valid values: %s.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Unsupported logging category %s=%s.</source> <translation type="unfinished"></translation> </message> diff --git a/src/qt/locale/bitcoin_en.xlf b/src/qt/locale/bitcoin_en.xlf index 7b2cfd30cf..a25ccfca72 100644 --- a/src/qt/locale/bitcoin_en.xlf +++ b/src/qt/locale/bitcoin_en.xlf @@ -661,7 +661,7 @@ Signing is only possible with addresses of the type 'legacy'.</source> <trans-unit id="_msg151"> <source xml:space="preserve">Restore Wallet</source> <context-group purpose="location"><context context-type="linenumber">435</context></context-group> - <note annotates="source" from="developer">Title of pop-up window shown when the user is attempting to + restore a wallet.</note> + <note annotates="source" from="developer">Title of pop-up window shown when the user is attempting to restore a wallet.</note> </trans-unit> <trans-unit id="_msg152"> <source xml:space="preserve">Wallet Name</source> @@ -1353,25 +1353,25 @@ Signing is only possible with addresses of the type 'legacy'.</source> <context-group purpose="location"><context context-type="linenumber">49</context></context-group> </trans-unit> <trans-unit id="_msg298"> - <source xml:space="preserve">When you click OK, %1 will begin to download and process the full %4 block chain (%2GB) starting with the earliest transactions in %3 when %4 initially launched.</source> - <context-group purpose="location"><context context-type="linenumber">206</context></context-group> - </trans-unit> - <trans-unit id="_msg299"> <source xml:space="preserve">Limit block chain storage to</source> <context-group purpose="location"><context context-type="linenumber">238</context></context-group> </trans-unit> - <trans-unit id="_msg300"> + <trans-unit id="_msg299"> <source xml:space="preserve">Reverting this setting requires re-downloading the entire blockchain. It is faster to download the full chain first and prune it later. Disables some advanced features.</source> <context-group purpose="location"><context context-type="linenumber">241</context></context-group> </trans-unit> - <trans-unit id="_msg301"> + <trans-unit id="_msg300"> <source xml:space="preserve"> GB</source> <context-group purpose="location"><context context-type="linenumber">248</context></context-group> </trans-unit> - <trans-unit id="_msg302"> + <trans-unit id="_msg301"> <source xml:space="preserve">This initial synchronisation is very demanding, and may expose hardware problems with your computer that had previously gone unnoticed. Each time you run %1, it will continue downloading where it left off.</source> <context-group purpose="location"><context context-type="linenumber">216</context></context-group> </trans-unit> + <trans-unit id="_msg302"> + <source xml:space="preserve">When you click OK, %1 will begin to download and process the full %4 block chain (%2 GB) starting with the earliest transactions in %3 when %4 initially launched.</source> + <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + </trans-unit> <trans-unit id="_msg303"> <source xml:space="preserve">If you have chosen to limit block chain storage (pruning), the historical data must still be downloaded and processed, but will be deleted afterward to keep your disk usage low.</source> <context-group purpose="location"><context context-type="linenumber">226</context></context-group> @@ -4416,655 +4416,749 @@ Go to File > Open Wallet to load a wallet. </trans-unit> <trans-unit id="_msg965"> <source xml:space="preserve">Error: Dumpfile format record is incorrect. Got "%s", expected "format".</source> - <context-group purpose="location"><context context-type="linenumber">62</context></context-group> + <context-group purpose="location"><context context-type="linenumber">65</context></context-group> </trans-unit> <trans-unit id="_msg966"> <source xml:space="preserve">Error: Dumpfile identifier record is incorrect. Got "%s", expected "%s".</source> - <context-group purpose="location"><context context-type="linenumber">64</context></context-group> + <context-group purpose="location"><context context-type="linenumber">67</context></context-group> </trans-unit> <trans-unit id="_msg967"> <source xml:space="preserve">Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version %s</source> - <context-group purpose="location"><context context-type="linenumber">66</context></context-group> + <context-group purpose="location"><context context-type="linenumber">69</context></context-group> </trans-unit> <trans-unit id="_msg968"> <source xml:space="preserve">Error: Legacy wallets only support the "legacy", "p2sh-segwit", and "bech32" address types</source> - <context-group purpose="location"><context context-type="linenumber">69</context></context-group> + <context-group purpose="location"><context context-type="linenumber">75</context></context-group> </trans-unit> <trans-unit id="_msg969"> <source xml:space="preserve">Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.</source> - <context-group purpose="location"><context context-type="linenumber">75</context></context-group> + <context-group purpose="location"><context context-type="linenumber">87</context></context-group> </trans-unit> <trans-unit id="_msg970"> <source xml:space="preserve">File %s already exists. If you are sure this is what you want, move it out of the way first.</source> - <context-group purpose="location"><context context-type="linenumber">78</context></context-group> + <context-group purpose="location"><context context-type="linenumber">90</context></context-group> </trans-unit> <trans-unit id="_msg971"> <source xml:space="preserve">Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)</source> - <context-group purpose="location"><context context-type="linenumber">81</context></context-group> + <context-group purpose="location"><context context-type="linenumber">96</context></context-group> </trans-unit> <trans-unit id="_msg972"> <source xml:space="preserve">Invalid or corrupt peers.dat (%s). If you believe this is a bug, please report it to %s. As a workaround, you can move the file (%s) out of the way (rename, move, or delete) to have a new one created on the next start.</source> - <context-group purpose="location"><context context-type="linenumber">84</context></context-group> + <context-group purpose="location"><context context-type="linenumber">99</context></context-group> </trans-unit> <trans-unit id="_msg973"> <source xml:space="preserve">More than one onion bind address is provided. Using %s for the automatically created Tor onion service.</source> - <context-group purpose="location"><context context-type="linenumber">88</context></context-group> + <context-group purpose="location"><context context-type="linenumber">103</context></context-group> </trans-unit> <trans-unit id="_msg974"> <source xml:space="preserve">No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.</source> - <context-group purpose="location"><context context-type="linenumber">91</context></context-group> + <context-group purpose="location"><context context-type="linenumber">106</context></context-group> </trans-unit> <trans-unit id="_msg975"> <source xml:space="preserve">No dump file provided. To use dump, -dumpfile=<filename> must be provided.</source> - <context-group purpose="location"><context context-type="linenumber">94</context></context-group> + <context-group purpose="location"><context context-type="linenumber">109</context></context-group> </trans-unit> <trans-unit id="_msg976"> <source xml:space="preserve">No wallet file format provided. To use createfromdump, -format=<format> must be provided.</source> - <context-group purpose="location"><context context-type="linenumber">96</context></context-group> + <context-group purpose="location"><context context-type="linenumber">111</context></context-group> </trans-unit> <trans-unit id="_msg977"> - <source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided (no -proxy= and no -onion= given) or it is explicitly forbidden (-onion=0)</source> - <context-group purpose="location"><context context-type="linenumber">99</context></context-group> - </trans-unit> - <trans-unit id="_msg978"> <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> - <context-group purpose="location"><context context-type="linenumber">103</context></context-group> + <context-group purpose="location"><context context-type="linenumber">121</context></context-group> </trans-unit> - <trans-unit id="_msg979"> + <trans-unit id="_msg978"> <source xml:space="preserve">Please contribute if you find %s useful. Visit %s for further information about the software.</source> - <context-group purpose="location"><context context-type="linenumber">106</context></context-group> + <context-group purpose="location"><context context-type="linenumber">124</context></context-group> </trans-unit> - <trans-unit id="_msg980"> + <trans-unit id="_msg979"> <source xml:space="preserve">Prune configured below the minimum of %d MiB. Please use a higher number.</source> - <context-group purpose="location"><context context-type="linenumber">109</context></context-group> + <context-group purpose="location"><context context-type="linenumber">127</context></context-group> </trans-unit> - <trans-unit id="_msg981"> + <trans-unit id="_msg980"> <source xml:space="preserve">Prune mode is incompatible with -reindex-chainstate. Use full -reindex instead.</source> - <context-group purpose="location"><context context-type="linenumber">111</context></context-group> + <context-group purpose="location"><context context-type="linenumber">129</context></context-group> </trans-unit> - <trans-unit id="_msg982"> + <trans-unit id="_msg981"> <source xml:space="preserve">Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)</source> - <context-group purpose="location"><context context-type="linenumber">114</context></context-group> + <context-group purpose="location"><context context-type="linenumber">132</context></context-group> </trans-unit> - <trans-unit id="_msg983"> + <trans-unit id="_msg982"> <source xml:space="preserve">SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported</source> - <context-group purpose="location"><context context-type="linenumber">117</context></context-group> + <context-group purpose="location"><context context-type="linenumber">135</context></context-group> </trans-unit> - <trans-unit id="_msg984"> + <trans-unit id="_msg983"> <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> - <context-group purpose="location"><context context-type="linenumber">123</context></context-group> + <context-group purpose="location"><context context-type="linenumber">141</context></context-group> </trans-unit> - <trans-unit id="_msg985"> + <trans-unit id="_msg984"> <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> - <context-group purpose="location"><context context-type="linenumber">128</context></context-group> + <context-group purpose="location"><context context-type="linenumber">146</context></context-group> </trans-unit> - <trans-unit id="_msg986"> + <trans-unit id="_msg985"> <source xml:space="preserve">The transaction amount is too small to send after the fee has been deducted</source> - <context-group purpose="location"><context context-type="linenumber">132</context></context-group> + <context-group purpose="location"><context context-type="linenumber">150</context></context-group> </trans-unit> - <trans-unit id="_msg987"> + <trans-unit id="_msg986"> <source xml:space="preserve">This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet</source> - <context-group purpose="location"><context context-type="linenumber">134</context></context-group> + <context-group purpose="location"><context context-type="linenumber">152</context></context-group> </trans-unit> - <trans-unit id="_msg988"> + <trans-unit id="_msg987"> <source xml:space="preserve">This is a pre-release test build - use at your own risk - do not use for mining or merchant applications</source> - <context-group purpose="location"><context context-type="linenumber">138</context></context-group> + <context-group purpose="location"><context context-type="linenumber">156</context></context-group> </trans-unit> - <trans-unit id="_msg989"> + <trans-unit id="_msg988"> <source xml:space="preserve">This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection.</source> - <context-group purpose="location"><context context-type="linenumber">141</context></context-group> + <context-group purpose="location"><context context-type="linenumber">159</context></context-group> </trans-unit> - <trans-unit id="_msg990"> + <trans-unit id="_msg989"> <source xml:space="preserve">This is the transaction fee you may discard if change is smaller than dust at this level</source> - <context-group purpose="location"><context context-type="linenumber">144</context></context-group> + <context-group purpose="location"><context context-type="linenumber">162</context></context-group> </trans-unit> - <trans-unit id="_msg991"> + <trans-unit id="_msg990"> <source xml:space="preserve">This is the transaction fee you may pay when fee estimates are not available.</source> - <context-group purpose="location"><context context-type="linenumber">147</context></context-group> + <context-group purpose="location"><context context-type="linenumber">165</context></context-group> </trans-unit> - <trans-unit id="_msg992"> + <trans-unit id="_msg991"> <source xml:space="preserve">Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.</source> - <context-group purpose="location"><context context-type="linenumber">149</context></context-group> + <context-group purpose="location"><context context-type="linenumber">167</context></context-group> </trans-unit> - <trans-unit id="_msg993"> + <trans-unit id="_msg992"> <source xml:space="preserve">Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.</source> - <context-group purpose="location"><context context-type="linenumber">152</context></context-group> + <context-group purpose="location"><context context-type="linenumber">170</context></context-group> </trans-unit> - <trans-unit id="_msg994"> + <trans-unit id="_msg993"> <source xml:space="preserve">Unknown wallet file format "%s" provided. Please provide one of "bdb" or "sqlite".</source> - <context-group purpose="location"><context context-type="linenumber">155</context></context-group> + <context-group purpose="location"><context context-type="linenumber">173</context></context-group> </trans-unit> - <trans-unit id="_msg995"> + <trans-unit id="_msg994"> <source xml:space="preserve">Unsupported chainstate database format found. Please restart with -reindex-chainstate. This will rebuild the chainstate database.</source> - <context-group purpose="location"><context context-type="linenumber">158</context></context-group> + <context-group purpose="location"><context context-type="linenumber">184</context></context-group> </trans-unit> - <trans-unit id="_msg996"> + <trans-unit id="_msg995"> <source xml:space="preserve">Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future.</source> - <context-group purpose="location"><context context-type="linenumber">161</context></context-group> + <context-group purpose="location"><context context-type="linenumber">187</context></context-group> </trans-unit> - <trans-unit id="_msg997"> + <trans-unit id="_msg996"> <source xml:space="preserve">Warning: Dumpfile wallet format "%s" does not match command line specified format "%s".</source> - <context-group purpose="location"><context context-type="linenumber">165</context></context-group> + <context-group purpose="location"><context context-type="linenumber">191</context></context-group> </trans-unit> - <trans-unit id="_msg998"> + <trans-unit id="_msg997"> <source xml:space="preserve">Warning: Private keys detected in wallet {%s} with disabled private keys</source> - <context-group purpose="location"><context context-type="linenumber">168</context></context-group> + <context-group purpose="location"><context context-type="linenumber">194</context></context-group> </trans-unit> - <trans-unit id="_msg999"> + <trans-unit id="_msg998"> <source xml:space="preserve">Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.</source> - <context-group purpose="location"><context context-type="linenumber">170</context></context-group> + <context-group purpose="location"><context context-type="linenumber">196</context></context-group> </trans-unit> - <trans-unit id="_msg1000"> + <trans-unit id="_msg999"> <source xml:space="preserve">Witness data for blocks after height %d requires validation. Please restart with -reindex.</source> - <context-group purpose="location"><context context-type="linenumber">173</context></context-group> + <context-group purpose="location"><context context-type="linenumber">199</context></context-group> </trans-unit> - <trans-unit id="_msg1001"> + <trans-unit id="_msg1000"> <source xml:space="preserve">You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source> - <context-group purpose="location"><context context-type="linenumber">176</context></context-group> + <context-group purpose="location"><context context-type="linenumber">202</context></context-group> </trans-unit> - <trans-unit id="_msg1002"> + <trans-unit id="_msg1001"> <source xml:space="preserve">%s is set very high!</source> - <context-group purpose="location"><context context-type="linenumber">179</context></context-group> + <context-group purpose="location"><context context-type="linenumber">211</context></context-group> </trans-unit> - <trans-unit id="_msg1003"> + <trans-unit id="_msg1002"> <source xml:space="preserve">-maxmempool must be at least %d MB</source> - <context-group purpose="location"><context context-type="linenumber">180</context></context-group> + <context-group purpose="location"><context context-type="linenumber">212</context></context-group> </trans-unit> - <trans-unit id="_msg1004"> + <trans-unit id="_msg1003"> <source xml:space="preserve">A fatal internal error occurred, see debug.log for details</source> - <context-group purpose="location"><context context-type="linenumber">181</context></context-group> + <context-group purpose="location"><context context-type="linenumber">213</context></context-group> </trans-unit> - <trans-unit id="_msg1005"> + <trans-unit id="_msg1004"> <source xml:space="preserve">Cannot resolve -%s address: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">182</context></context-group> + <context-group purpose="location"><context context-type="linenumber">214</context></context-group> </trans-unit> - <trans-unit id="_msg1006"> + <trans-unit id="_msg1005"> <source xml:space="preserve">Cannot set -forcednsseed to true when setting -dnsseed to false.</source> - <context-group purpose="location"><context context-type="linenumber">183</context></context-group> + <context-group purpose="location"><context context-type="linenumber">215</context></context-group> </trans-unit> - <trans-unit id="_msg1007"> + <trans-unit id="_msg1006"> <source xml:space="preserve">Cannot set -peerblockfilters without -blockfilterindex.</source> - <context-group purpose="location"><context context-type="linenumber">184</context></context-group> + <context-group purpose="location"><context context-type="linenumber">216</context></context-group> </trans-unit> - <trans-unit id="_msg1008"> + <trans-unit id="_msg1007"> <source xml:space="preserve">Cannot write to data directory '%s'; check permissions.</source> - <context-group purpose="location"><context context-type="linenumber">185</context></context-group> + <context-group purpose="location"><context context-type="linenumber">217</context></context-group> </trans-unit> - <trans-unit id="_msg1009"> + <trans-unit id="_msg1008"> <source xml:space="preserve">The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.</source> - <context-group purpose="location"><context context-type="linenumber">120</context></context-group> + <context-group purpose="location"><context context-type="linenumber">138</context></context-group> </trans-unit> - <trans-unit id="_msg1010"> + <trans-unit id="_msg1009"> <source xml:space="preserve">%s request to listen on port %u. This port is considered "bad" and thus it is unlikely that any Bitcoin Core peers connect to it. See doc/p2p-bad-ports.md for details and a full list.</source> <context-group purpose="location"><context context-type="linenumber">16</context></context-group> </trans-unit> - <trans-unit id="_msg1011"> + <trans-unit id="_msg1010"> <source xml:space="preserve">-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source> <context-group purpose="location"><context context-type="linenumber">23</context></context-group> </trans-unit> - <trans-unit id="_msg1012"> + <trans-unit id="_msg1011"> <source xml:space="preserve">-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source> <context-group purpose="location"><context context-type="linenumber">27</context></context-group> </trans-unit> - <trans-unit id="_msg1013"> + <trans-unit id="_msg1012"> <source xml:space="preserve">-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.</source> <context-group purpose="location"><context context-type="linenumber">31</context></context-group> </trans-unit> - <trans-unit id="_msg1014"> + <trans-unit id="_msg1013"> <source xml:space="preserve">Assumed-valid: last wallet synchronisation goes beyond available block data. You need to wait for the background validation chain to download more blocks.</source> <context-group purpose="location"><context context-type="linenumber">35</context></context-group> </trans-unit> - <trans-unit id="_msg1015"> + <trans-unit id="_msg1014"> <source xml:space="preserve">Cannot provide specific connections and have addrman find outgoing connections at the same time.</source> <context-group purpose="location"><context context-type="linenumber">43</context></context-group> </trans-unit> - <trans-unit id="_msg1016"> + <trans-unit id="_msg1015"> <source xml:space="preserve">Error loading %s: External signer wallet being loaded without external signer support compiled</source> <context-group purpose="location"><context context-type="linenumber">53</context></context-group> </trans-unit> + <trans-unit id="_msg1016"> + <source xml:space="preserve">Error: Address book data in wallet cannot be identified to belong to migrated wallets</source> + <context-group purpose="location"><context context-type="linenumber">62</context></context-group> + </trans-unit> <trans-unit id="_msg1017"> - <source xml:space="preserve">Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> + <source xml:space="preserve">Error: Duplicate descriptors created during migration. Your wallet may be corrupted.</source> <context-group purpose="location"><context context-type="linenumber">72</context></context-group> </trans-unit> <trans-unit id="_msg1018"> - <source xml:space="preserve">Config setting for %s only applied on %s network when in [%s] section.</source> - <context-group purpose="location"><context context-type="linenumber">186</context></context-group> + <source xml:space="preserve">Error: Transaction %s in wallet cannot be identified to belong to migrated wallets</source> + <context-group purpose="location"><context context-type="linenumber">78</context></context-group> </trans-unit> <trans-unit id="_msg1019"> - <source xml:space="preserve">Copyright (C) %i-%i</source> - <context-group purpose="location"><context context-type="linenumber">187</context></context-group> + <source xml:space="preserve">Error: Unable to produce descriptors for this legacy wallet. Make sure the wallet is unlocked first</source> + <context-group purpose="location"><context context-type="linenumber">81</context></context-group> </trans-unit> <trans-unit id="_msg1020"> - <source xml:space="preserve">Corrupted block database detected</source> - <context-group purpose="location"><context context-type="linenumber">188</context></context-group> + <source xml:space="preserve">Failed to rename invalid peers.dat file. Please move or delete it and try again.</source> + <context-group purpose="location"><context context-type="linenumber">84</context></context-group> </trans-unit> <trans-unit id="_msg1021"> - <source xml:space="preserve">Could not find asmap file %s</source> - <context-group purpose="location"><context context-type="linenumber">189</context></context-group> + <source xml:space="preserve">Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6</source> + <context-group purpose="location"><context context-type="linenumber">93</context></context-group> </trans-unit> <trans-unit id="_msg1022"> - <source xml:space="preserve">Could not parse asmap file %s</source> - <context-group purpose="location"><context context-type="linenumber">190</context></context-group> + <source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is explicitly forbidden: -onion=0</source> + <context-group purpose="location"><context context-type="linenumber">114</context></context-group> </trans-unit> <trans-unit id="_msg1023"> - <source xml:space="preserve">Disk space is too low!</source> - <context-group purpose="location"><context context-type="linenumber">191</context></context-group> + <source xml:space="preserve">Outbound connections restricted to Tor (-onlynet=onion) but the proxy for reaching the Tor network is not provided: none of -proxy, -onion or -listenonion is given</source> + <context-group purpose="location"><context context-type="linenumber">117</context></context-group> </trans-unit> <trans-unit id="_msg1024"> - <source xml:space="preserve">Do you want to rebuild the block database now?</source> - <context-group purpose="location"><context context-type="linenumber">192</context></context-group> + <source xml:space="preserve">Unrecognized descriptor found. Loading wallet %s + +The wallet might had been created on a newer version. +Please try running the latest software version. +</source> + <context-group purpose="location"><context context-type="linenumber">176</context></context-group> </trans-unit> <trans-unit id="_msg1025"> - <source xml:space="preserve">Done loading</source> - <context-group purpose="location"><context context-type="linenumber">193</context></context-group> + <source xml:space="preserve">Unsupported category-specific logging level -loglevel=%s. Expected -loglevel=<category>:<loglevel>. Valid categories: %s. Valid loglevels: %s.</source> + <context-group purpose="location"><context context-type="linenumber">181</context></context-group> </trans-unit> <trans-unit id="_msg1026"> - <source xml:space="preserve">Dump file %s does not exist.</source> - <context-group purpose="location"><context context-type="linenumber">194</context></context-group> + <source xml:space="preserve"> +Unable to cleanup failed migration</source> + <context-group purpose="location"><context context-type="linenumber">205</context></context-group> </trans-unit> <trans-unit id="_msg1027"> - <source xml:space="preserve">Error creating %s</source> - <context-group purpose="location"><context context-type="linenumber">195</context></context-group> + <source xml:space="preserve"> +Unable to restore backup of wallet.</source> + <context-group purpose="location"><context context-type="linenumber">208</context></context-group> </trans-unit> <trans-unit id="_msg1028"> - <source xml:space="preserve">Error initializing block database</source> - <context-group purpose="location"><context context-type="linenumber">196</context></context-group> + <source xml:space="preserve">Config setting for %s only applied on %s network when in [%s] section.</source> + <context-group purpose="location"><context context-type="linenumber">218</context></context-group> </trans-unit> <trans-unit id="_msg1029"> - <source xml:space="preserve">Error initializing wallet database environment %s!</source> - <context-group purpose="location"><context context-type="linenumber">197</context></context-group> + <source xml:space="preserve">Copyright (C) %i-%i</source> + <context-group purpose="location"><context context-type="linenumber">219</context></context-group> </trans-unit> <trans-unit id="_msg1030"> - <source xml:space="preserve">Error loading %s</source> - <context-group purpose="location"><context context-type="linenumber">198</context></context-group> + <source xml:space="preserve">Corrupted block database detected</source> + <context-group purpose="location"><context context-type="linenumber">220</context></context-group> </trans-unit> <trans-unit id="_msg1031"> - <source xml:space="preserve">Error loading %s: Private keys can only be disabled during creation</source> - <context-group purpose="location"><context context-type="linenumber">199</context></context-group> + <source xml:space="preserve">Could not find asmap file %s</source> + <context-group purpose="location"><context context-type="linenumber">221</context></context-group> </trans-unit> <trans-unit id="_msg1032"> - <source xml:space="preserve">Error loading %s: Wallet corrupted</source> - <context-group purpose="location"><context context-type="linenumber">200</context></context-group> + <source xml:space="preserve">Could not parse asmap file %s</source> + <context-group purpose="location"><context context-type="linenumber">222</context></context-group> </trans-unit> <trans-unit id="_msg1033"> - <source xml:space="preserve">Error loading %s: Wallet requires newer version of %s</source> - <context-group purpose="location"><context context-type="linenumber">201</context></context-group> + <source xml:space="preserve">Disk space is too low!</source> + <context-group purpose="location"><context context-type="linenumber">223</context></context-group> </trans-unit> <trans-unit id="_msg1034"> - <source xml:space="preserve">Error loading block database</source> - <context-group purpose="location"><context context-type="linenumber">202</context></context-group> + <source xml:space="preserve">Do you want to rebuild the block database now?</source> + <context-group purpose="location"><context context-type="linenumber">224</context></context-group> </trans-unit> <trans-unit id="_msg1035"> - <source xml:space="preserve">Error opening block database</source> - <context-group purpose="location"><context context-type="linenumber">203</context></context-group> + <source xml:space="preserve">Done loading</source> + <context-group purpose="location"><context context-type="linenumber">225</context></context-group> </trans-unit> <trans-unit id="_msg1036"> - <source xml:space="preserve">Error reading from database, shutting down.</source> - <context-group purpose="location"><context context-type="linenumber">204</context></context-group> + <source xml:space="preserve">Dump file %s does not exist.</source> + <context-group purpose="location"><context context-type="linenumber">226</context></context-group> </trans-unit> <trans-unit id="_msg1037"> - <source xml:space="preserve">Error reading next record from wallet database</source> - <context-group purpose="location"><context context-type="linenumber">205</context></context-group> + <source xml:space="preserve">Error creating %s</source> + <context-group purpose="location"><context context-type="linenumber">227</context></context-group> </trans-unit> <trans-unit id="_msg1038"> - <source xml:space="preserve">Error: Couldn't create cursor into database</source> - <context-group purpose="location"><context context-type="linenumber">206</context></context-group> + <source xml:space="preserve">Error initializing block database</source> + <context-group purpose="location"><context context-type="linenumber">228</context></context-group> </trans-unit> <trans-unit id="_msg1039"> - <source xml:space="preserve">Error: Disk space is low for %s</source> - <context-group purpose="location"><context context-type="linenumber">207</context></context-group> + <source xml:space="preserve">Error initializing wallet database environment %s!</source> + <context-group purpose="location"><context context-type="linenumber">229</context></context-group> </trans-unit> <trans-unit id="_msg1040"> - <source xml:space="preserve">Error: Dumpfile checksum does not match. Computed %s, expected %s</source> - <context-group purpose="location"><context context-type="linenumber">208</context></context-group> + <source xml:space="preserve">Error loading %s</source> + <context-group purpose="location"><context context-type="linenumber">230</context></context-group> </trans-unit> <trans-unit id="_msg1041"> - <source xml:space="preserve">Error: Got key that was not hex: %s</source> - <context-group purpose="location"><context context-type="linenumber">209</context></context-group> + <source xml:space="preserve">Error loading %s: Private keys can only be disabled during creation</source> + <context-group purpose="location"><context context-type="linenumber">231</context></context-group> </trans-unit> <trans-unit id="_msg1042"> - <source xml:space="preserve">Error: Got value that was not hex: %s</source> - <context-group purpose="location"><context context-type="linenumber">210</context></context-group> + <source xml:space="preserve">Error loading %s: Wallet corrupted</source> + <context-group purpose="location"><context context-type="linenumber">232</context></context-group> </trans-unit> <trans-unit id="_msg1043"> - <source xml:space="preserve">Error: Keypool ran out, please call keypoolrefill first</source> - <context-group purpose="location"><context context-type="linenumber">211</context></context-group> + <source xml:space="preserve">Error loading %s: Wallet requires newer version of %s</source> + <context-group purpose="location"><context context-type="linenumber">233</context></context-group> </trans-unit> <trans-unit id="_msg1044"> - <source xml:space="preserve">Error: Missing checksum</source> - <context-group purpose="location"><context context-type="linenumber">212</context></context-group> + <source xml:space="preserve">Error loading block database</source> + <context-group purpose="location"><context context-type="linenumber">234</context></context-group> </trans-unit> <trans-unit id="_msg1045"> - <source xml:space="preserve">Error: No %s addresses available.</source> - <context-group purpose="location"><context context-type="linenumber">213</context></context-group> + <source xml:space="preserve">Error opening block database</source> + <context-group purpose="location"><context context-type="linenumber">235</context></context-group> </trans-unit> <trans-unit id="_msg1046"> - <source xml:space="preserve">Error: Unable to parse version %u as a uint32_t</source> - <context-group purpose="location"><context context-type="linenumber">214</context></context-group> + <source xml:space="preserve">Error reading from database, shutting down.</source> + <context-group purpose="location"><context context-type="linenumber">236</context></context-group> </trans-unit> <trans-unit id="_msg1047"> - <source xml:space="preserve">Error: Unable to write record to new wallet</source> - <context-group purpose="location"><context context-type="linenumber">215</context></context-group> + <source xml:space="preserve">Error reading next record from wallet database</source> + <context-group purpose="location"><context context-type="linenumber">237</context></context-group> </trans-unit> <trans-unit id="_msg1048"> - <source xml:space="preserve">Failed to listen on any port. Use -listen=0 if you want this.</source> - <context-group purpose="location"><context context-type="linenumber">216</context></context-group> + <source xml:space="preserve">Error: Could not add watchonly tx to watchonly wallet</source> + <context-group purpose="location"><context context-type="linenumber">238</context></context-group> </trans-unit> <trans-unit id="_msg1049"> - <source xml:space="preserve">Failed to rescan the wallet during initialization</source> - <context-group purpose="location"><context context-type="linenumber">217</context></context-group> + <source xml:space="preserve">Error: Could not delete watchonly transactions</source> + <context-group purpose="location"><context context-type="linenumber">239</context></context-group> </trans-unit> <trans-unit id="_msg1050"> - <source xml:space="preserve">Failed to verify database</source> - <context-group purpose="location"><context context-type="linenumber">218</context></context-group> + <source xml:space="preserve">Error: Couldn't create cursor into database</source> + <context-group purpose="location"><context context-type="linenumber">240</context></context-group> </trans-unit> <trans-unit id="_msg1051"> - <source xml:space="preserve">Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> - <context-group purpose="location"><context context-type="linenumber">219</context></context-group> + <source xml:space="preserve">Error: Disk space is low for %s</source> + <context-group purpose="location"><context context-type="linenumber">241</context></context-group> </trans-unit> <trans-unit id="_msg1052"> - <source xml:space="preserve">Ignoring duplicate -wallet %s.</source> - <context-group purpose="location"><context context-type="linenumber">220</context></context-group> + <source xml:space="preserve">Error: Dumpfile checksum does not match. Computed %s, expected %s</source> + <context-group purpose="location"><context context-type="linenumber">242</context></context-group> </trans-unit> <trans-unit id="_msg1053"> - <source xml:space="preserve">Importing…</source> - <context-group purpose="location"><context context-type="linenumber">221</context></context-group> + <source xml:space="preserve">Error: Failed to create new watchonly wallet</source> + <context-group purpose="location"><context context-type="linenumber">243</context></context-group> </trans-unit> <trans-unit id="_msg1054"> - <source xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</source> - <context-group purpose="location"><context context-type="linenumber">222</context></context-group> + <source xml:space="preserve">Error: Got key that was not hex: %s</source> + <context-group purpose="location"><context context-type="linenumber">244</context></context-group> </trans-unit> <trans-unit id="_msg1055"> - <source xml:space="preserve">Initialization sanity check failed. %s is shutting down.</source> - <context-group purpose="location"><context context-type="linenumber">223</context></context-group> + <source xml:space="preserve">Error: Got value that was not hex: %s</source> + <context-group purpose="location"><context context-type="linenumber">245</context></context-group> </trans-unit> <trans-unit id="_msg1056"> - <source xml:space="preserve">Input not found or already spent</source> - <context-group purpose="location"><context context-type="linenumber">224</context></context-group> + <source xml:space="preserve">Error: Keypool ran out, please call keypoolrefill first</source> + <context-group purpose="location"><context context-type="linenumber">246</context></context-group> </trans-unit> <trans-unit id="_msg1057"> - <source xml:space="preserve">Insufficient funds</source> - <context-group purpose="location"><context context-type="linenumber">225</context></context-group> + <source xml:space="preserve">Error: Missing checksum</source> + <context-group purpose="location"><context context-type="linenumber">247</context></context-group> </trans-unit> <trans-unit id="_msg1058"> - <source xml:space="preserve">Invalid -i2psam address or hostname: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">226</context></context-group> + <source xml:space="preserve">Error: No %s addresses available.</source> + <context-group purpose="location"><context context-type="linenumber">248</context></context-group> </trans-unit> <trans-unit id="_msg1059"> - <source xml:space="preserve">Invalid -onion address or hostname: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">227</context></context-group> + <source xml:space="preserve">Error: Not all watchonly txs could be deleted</source> + <context-group purpose="location"><context context-type="linenumber">249</context></context-group> </trans-unit> <trans-unit id="_msg1060"> - <source xml:space="preserve">Invalid -proxy address or hostname: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">228</context></context-group> + <source xml:space="preserve">Error: This wallet already uses SQLite</source> + <context-group purpose="location"><context context-type="linenumber">250</context></context-group> </trans-unit> <trans-unit id="_msg1061"> - <source xml:space="preserve">Invalid P2P permission: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">229</context></context-group> + <source xml:space="preserve">Error: This wallet is already a descriptor wallet</source> + <context-group purpose="location"><context context-type="linenumber">251</context></context-group> </trans-unit> <trans-unit id="_msg1062"> - <source xml:space="preserve">Invalid amount for -%s=<amount>: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">230</context></context-group> + <source xml:space="preserve">Error: Unable to begin reading all records in the database</source> + <context-group purpose="location"><context context-type="linenumber">252</context></context-group> </trans-unit> <trans-unit id="_msg1063"> - <source xml:space="preserve">Invalid amount for -discardfee=<amount>: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">231</context></context-group> + <source xml:space="preserve">Error: Unable to make a backup of your wallet</source> + <context-group purpose="location"><context context-type="linenumber">253</context></context-group> </trans-unit> <trans-unit id="_msg1064"> - <source xml:space="preserve">Invalid amount for -fallbackfee=<amount>: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">232</context></context-group> + <source xml:space="preserve">Error: Unable to parse version %u as a uint32_t</source> + <context-group purpose="location"><context context-type="linenumber">254</context></context-group> </trans-unit> <trans-unit id="_msg1065"> - <source xml:space="preserve">Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> - <context-group purpose="location"><context context-type="linenumber">233</context></context-group> + <source xml:space="preserve">Error: Unable to read all records in the database</source> + <context-group purpose="location"><context context-type="linenumber">255</context></context-group> </trans-unit> <trans-unit id="_msg1066"> - <source xml:space="preserve">Invalid netmask specified in -whitelist: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">234</context></context-group> + <source xml:space="preserve">Error: Unable to remove watchonly address book data</source> + <context-group purpose="location"><context context-type="linenumber">256</context></context-group> </trans-unit> <trans-unit id="_msg1067"> - <source xml:space="preserve">Listening for incoming connections failed (listen returned error %s)</source> - <context-group purpose="location"><context context-type="linenumber">235</context></context-group> + <source xml:space="preserve">Error: Unable to write record to new wallet</source> + <context-group purpose="location"><context context-type="linenumber">257</context></context-group> </trans-unit> <trans-unit id="_msg1068"> - <source xml:space="preserve">Loading P2P addresses…</source> - <context-group purpose="location"><context context-type="linenumber">236</context></context-group> + <source xml:space="preserve">Failed to listen on any port. Use -listen=0 if you want this.</source> + <context-group purpose="location"><context context-type="linenumber">258</context></context-group> </trans-unit> <trans-unit id="_msg1069"> - <source xml:space="preserve">Loading banlist…</source> - <context-group purpose="location"><context context-type="linenumber">237</context></context-group> + <source xml:space="preserve">Failed to rescan the wallet during initialization</source> + <context-group purpose="location"><context context-type="linenumber">259</context></context-group> </trans-unit> <trans-unit id="_msg1070"> - <source xml:space="preserve">Loading block index…</source> - <context-group purpose="location"><context context-type="linenumber">238</context></context-group> + <source xml:space="preserve">Failed to verify database</source> + <context-group purpose="location"><context context-type="linenumber">260</context></context-group> </trans-unit> <trans-unit id="_msg1071"> - <source xml:space="preserve">Loading wallet…</source> - <context-group purpose="location"><context context-type="linenumber">239</context></context-group> + <source xml:space="preserve">Fee rate (%s) is lower than the minimum fee rate setting (%s)</source> + <context-group purpose="location"><context context-type="linenumber">261</context></context-group> </trans-unit> <trans-unit id="_msg1072"> - <source xml:space="preserve">Missing amount</source> - <context-group purpose="location"><context context-type="linenumber">240</context></context-group> + <source xml:space="preserve">Ignoring duplicate -wallet %s.</source> + <context-group purpose="location"><context context-type="linenumber">262</context></context-group> </trans-unit> <trans-unit id="_msg1073"> - <source xml:space="preserve">Missing solving data for estimating transaction size</source> - <context-group purpose="location"><context context-type="linenumber">241</context></context-group> + <source xml:space="preserve">Importing…</source> + <context-group purpose="location"><context context-type="linenumber">263</context></context-group> </trans-unit> <trans-unit id="_msg1074"> - <source xml:space="preserve">Need to specify a port with -whitebind: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">242</context></context-group> + <source xml:space="preserve">Incorrect or no genesis block found. Wrong datadir for network?</source> + <context-group purpose="location"><context context-type="linenumber">264</context></context-group> </trans-unit> <trans-unit id="_msg1075"> - <source xml:space="preserve">No addresses available</source> - <context-group purpose="location"><context context-type="linenumber">243</context></context-group> + <source xml:space="preserve">Initialization sanity check failed. %s is shutting down.</source> + <context-group purpose="location"><context context-type="linenumber">265</context></context-group> </trans-unit> <trans-unit id="_msg1076"> - <source xml:space="preserve">Not enough file descriptors available.</source> - <context-group purpose="location"><context context-type="linenumber">244</context></context-group> + <source xml:space="preserve">Input not found or already spent</source> + <context-group purpose="location"><context context-type="linenumber">266</context></context-group> </trans-unit> <trans-unit id="_msg1077"> - <source xml:space="preserve">Prune cannot be configured with a negative value.</source> - <context-group purpose="location"><context context-type="linenumber">245</context></context-group> + <source xml:space="preserve">Insufficient funds</source> + <context-group purpose="location"><context context-type="linenumber">267</context></context-group> </trans-unit> <trans-unit id="_msg1078"> - <source xml:space="preserve">Prune mode is incompatible with -txindex.</source> - <context-group purpose="location"><context context-type="linenumber">246</context></context-group> + <source xml:space="preserve">Invalid -i2psam address or hostname: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">268</context></context-group> </trans-unit> <trans-unit id="_msg1079"> - <source xml:space="preserve">Pruning blockstore…</source> - <context-group purpose="location"><context context-type="linenumber">247</context></context-group> + <source xml:space="preserve">Invalid -onion address or hostname: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">269</context></context-group> </trans-unit> <trans-unit id="_msg1080"> - <source xml:space="preserve">Reducing -maxconnections from %d to %d, because of system limitations.</source> - <context-group purpose="location"><context context-type="linenumber">248</context></context-group> + <source xml:space="preserve">Invalid -proxy address or hostname: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">270</context></context-group> </trans-unit> <trans-unit id="_msg1081"> - <source xml:space="preserve">Replaying blocks…</source> - <context-group purpose="location"><context context-type="linenumber">249</context></context-group> + <source xml:space="preserve">Invalid P2P permission: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">271</context></context-group> </trans-unit> <trans-unit id="_msg1082"> - <source xml:space="preserve">Rescanning…</source> - <context-group purpose="location"><context context-type="linenumber">250</context></context-group> + <source xml:space="preserve">Invalid amount for -%s=<amount>: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">272</context></context-group> </trans-unit> <trans-unit id="_msg1083"> - <source xml:space="preserve">SQLiteDatabase: Failed to execute statement to verify database: %s</source> - <context-group purpose="location"><context context-type="linenumber">251</context></context-group> + <source xml:space="preserve">Invalid amount for -discardfee=<amount>: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">273</context></context-group> </trans-unit> <trans-unit id="_msg1084"> - <source xml:space="preserve">SQLiteDatabase: Failed to prepare statement to verify database: %s</source> - <context-group purpose="location"><context context-type="linenumber">252</context></context-group> + <source xml:space="preserve">Invalid amount for -fallbackfee=<amount>: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">274</context></context-group> </trans-unit> <trans-unit id="_msg1085"> - <source xml:space="preserve">SQLiteDatabase: Failed to read database verification error: %s</source> - <context-group purpose="location"><context context-type="linenumber">253</context></context-group> + <source xml:space="preserve">Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)</source> + <context-group purpose="location"><context context-type="linenumber">275</context></context-group> </trans-unit> <trans-unit id="_msg1086"> - <source xml:space="preserve">SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> - <context-group purpose="location"><context context-type="linenumber">254</context></context-group> + <source xml:space="preserve">Invalid netmask specified in -whitelist: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">276</context></context-group> </trans-unit> <trans-unit id="_msg1087"> - <source xml:space="preserve">Section [%s] is not recognized.</source> - <context-group purpose="location"><context context-type="linenumber">255</context></context-group> + <source xml:space="preserve">Listening for incoming connections failed (listen returned error %s)</source> + <context-group purpose="location"><context context-type="linenumber">277</context></context-group> </trans-unit> <trans-unit id="_msg1088"> - <source xml:space="preserve">Signing transaction failed</source> - <context-group purpose="location"><context context-type="linenumber">256</context></context-group> + <source xml:space="preserve">Loading P2P addresses…</source> + <context-group purpose="location"><context context-type="linenumber">278</context></context-group> </trans-unit> <trans-unit id="_msg1089"> - <source xml:space="preserve">Specified -walletdir "%s" does not exist</source> - <context-group purpose="location"><context context-type="linenumber">257</context></context-group> + <source xml:space="preserve">Loading banlist…</source> + <context-group purpose="location"><context context-type="linenumber">279</context></context-group> </trans-unit> <trans-unit id="_msg1090"> - <source xml:space="preserve">Specified -walletdir "%s" is a relative path</source> - <context-group purpose="location"><context context-type="linenumber">258</context></context-group> + <source xml:space="preserve">Loading block index…</source> + <context-group purpose="location"><context context-type="linenumber">280</context></context-group> </trans-unit> <trans-unit id="_msg1091"> - <source xml:space="preserve">Specified -walletdir "%s" is not a directory</source> - <context-group purpose="location"><context context-type="linenumber">259</context></context-group> + <source xml:space="preserve">Loading wallet…</source> + <context-group purpose="location"><context context-type="linenumber">281</context></context-group> </trans-unit> <trans-unit id="_msg1092"> - <source xml:space="preserve">Specified blocks directory "%s" does not exist.</source> - <context-group purpose="location"><context context-type="linenumber">260</context></context-group> + <source xml:space="preserve">Missing amount</source> + <context-group purpose="location"><context context-type="linenumber">282</context></context-group> </trans-unit> <trans-unit id="_msg1093"> - <source xml:space="preserve">Starting network threads…</source> - <context-group purpose="location"><context context-type="linenumber">261</context></context-group> + <source xml:space="preserve">Missing solving data for estimating transaction size</source> + <context-group purpose="location"><context context-type="linenumber">283</context></context-group> </trans-unit> <trans-unit id="_msg1094"> - <source xml:space="preserve">The source code is available from %s.</source> - <context-group purpose="location"><context context-type="linenumber">262</context></context-group> + <source xml:space="preserve">Need to specify a port with -whitebind: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">284</context></context-group> </trans-unit> <trans-unit id="_msg1095"> - <source xml:space="preserve">The specified config file %s does not exist</source> - <context-group purpose="location"><context context-type="linenumber">263</context></context-group> + <source xml:space="preserve">No addresses available</source> + <context-group purpose="location"><context context-type="linenumber">285</context></context-group> </trans-unit> <trans-unit id="_msg1096"> - <source xml:space="preserve">The transaction amount is too small to pay the fee</source> - <context-group purpose="location"><context context-type="linenumber">264</context></context-group> + <source xml:space="preserve">Not enough file descriptors available.</source> + <context-group purpose="location"><context context-type="linenumber">286</context></context-group> </trans-unit> <trans-unit id="_msg1097"> - <source xml:space="preserve">The wallet will avoid paying less than the minimum relay fee.</source> - <context-group purpose="location"><context context-type="linenumber">265</context></context-group> + <source xml:space="preserve">Prune cannot be configured with a negative value.</source> + <context-group purpose="location"><context context-type="linenumber">287</context></context-group> </trans-unit> <trans-unit id="_msg1098"> - <source xml:space="preserve">This is experimental software.</source> - <context-group purpose="location"><context context-type="linenumber">266</context></context-group> + <source xml:space="preserve">Prune mode is incompatible with -txindex.</source> + <context-group purpose="location"><context context-type="linenumber">288</context></context-group> </trans-unit> <trans-unit id="_msg1099"> - <source xml:space="preserve">This is the minimum transaction fee you pay on every transaction.</source> - <context-group purpose="location"><context context-type="linenumber">267</context></context-group> + <source xml:space="preserve">Pruning blockstore…</source> + <context-group purpose="location"><context context-type="linenumber">289</context></context-group> </trans-unit> <trans-unit id="_msg1100"> - <source xml:space="preserve">This is the transaction fee you will pay if you send a transaction.</source> - <context-group purpose="location"><context context-type="linenumber">268</context></context-group> + <source xml:space="preserve">Reducing -maxconnections from %d to %d, because of system limitations.</source> + <context-group purpose="location"><context context-type="linenumber">290</context></context-group> </trans-unit> <trans-unit id="_msg1101"> - <source xml:space="preserve">Transaction amount too small</source> - <context-group purpose="location"><context context-type="linenumber">269</context></context-group> + <source xml:space="preserve">Replaying blocks…</source> + <context-group purpose="location"><context context-type="linenumber">291</context></context-group> </trans-unit> <trans-unit id="_msg1102"> - <source xml:space="preserve">Transaction amounts must not be negative</source> - <context-group purpose="location"><context context-type="linenumber">270</context></context-group> + <source xml:space="preserve">Rescanning…</source> + <context-group purpose="location"><context context-type="linenumber">292</context></context-group> </trans-unit> <trans-unit id="_msg1103"> - <source xml:space="preserve">Transaction change output index out of range</source> - <context-group purpose="location"><context context-type="linenumber">271</context></context-group> + <source xml:space="preserve">SQLiteDatabase: Failed to execute statement to verify database: %s</source> + <context-group purpose="location"><context context-type="linenumber">293</context></context-group> </trans-unit> <trans-unit id="_msg1104"> - <source xml:space="preserve">Transaction has too long of a mempool chain</source> - <context-group purpose="location"><context context-type="linenumber">272</context></context-group> + <source xml:space="preserve">SQLiteDatabase: Failed to prepare statement to verify database: %s</source> + <context-group purpose="location"><context context-type="linenumber">294</context></context-group> </trans-unit> <trans-unit id="_msg1105"> - <source xml:space="preserve">Transaction must have at least one recipient</source> - <context-group purpose="location"><context context-type="linenumber">273</context></context-group> + <source xml:space="preserve">SQLiteDatabase: Failed to read database verification error: %s</source> + <context-group purpose="location"><context context-type="linenumber">295</context></context-group> </trans-unit> <trans-unit id="_msg1106"> - <source xml:space="preserve">Transaction needs a change address, but we can't generate it.</source> - <context-group purpose="location"><context context-type="linenumber">274</context></context-group> + <source xml:space="preserve">SQLiteDatabase: Unexpected application id. Expected %u, got %u</source> + <context-group purpose="location"><context context-type="linenumber">296</context></context-group> </trans-unit> <trans-unit id="_msg1107"> - <source xml:space="preserve">Transaction too large</source> - <context-group purpose="location"><context context-type="linenumber">275</context></context-group> + <source xml:space="preserve">Section [%s] is not recognized.</source> + <context-group purpose="location"><context context-type="linenumber">297</context></context-group> </trans-unit> <trans-unit id="_msg1108"> - <source xml:space="preserve">Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> - <context-group purpose="location"><context context-type="linenumber">276</context></context-group> + <source xml:space="preserve">Signing transaction failed</source> + <context-group purpose="location"><context context-type="linenumber">298</context></context-group> </trans-unit> <trans-unit id="_msg1109"> - <source xml:space="preserve">Unable to bind to %s on this computer (bind returned error %s)</source> - <context-group purpose="location"><context context-type="linenumber">277</context></context-group> + <source xml:space="preserve">Specified -walletdir "%s" does not exist</source> + <context-group purpose="location"><context context-type="linenumber">299</context></context-group> </trans-unit> <trans-unit id="_msg1110"> - <source xml:space="preserve">Unable to bind to %s on this computer. %s is probably already running.</source> - <context-group purpose="location"><context context-type="linenumber">278</context></context-group> + <source xml:space="preserve">Specified -walletdir "%s" is a relative path</source> + <context-group purpose="location"><context context-type="linenumber">300</context></context-group> </trans-unit> <trans-unit id="_msg1111"> - <source xml:space="preserve">Unable to create the PID file '%s': %s</source> - <context-group purpose="location"><context context-type="linenumber">279</context></context-group> + <source xml:space="preserve">Specified -walletdir "%s" is not a directory</source> + <context-group purpose="location"><context context-type="linenumber">301</context></context-group> </trans-unit> <trans-unit id="_msg1112"> - <source xml:space="preserve">Unable to find UTXO for external input</source> - <context-group purpose="location"><context context-type="linenumber">280</context></context-group> + <source xml:space="preserve">Specified blocks directory "%s" does not exist.</source> + <context-group purpose="location"><context context-type="linenumber">302</context></context-group> </trans-unit> <trans-unit id="_msg1113"> - <source xml:space="preserve">Unable to generate initial keys</source> - <context-group purpose="location"><context context-type="linenumber">281</context></context-group> + <source xml:space="preserve">Starting network threads…</source> + <context-group purpose="location"><context context-type="linenumber">303</context></context-group> </trans-unit> <trans-unit id="_msg1114"> - <source xml:space="preserve">Unable to generate keys</source> - <context-group purpose="location"><context context-type="linenumber">282</context></context-group> + <source xml:space="preserve">The source code is available from %s.</source> + <context-group purpose="location"><context context-type="linenumber">304</context></context-group> </trans-unit> <trans-unit id="_msg1115"> - <source xml:space="preserve">Unable to open %s for writing</source> - <context-group purpose="location"><context context-type="linenumber">283</context></context-group> + <source xml:space="preserve">The specified config file %s does not exist</source> + <context-group purpose="location"><context context-type="linenumber">305</context></context-group> </trans-unit> <trans-unit id="_msg1116"> - <source xml:space="preserve">Unable to parse -maxuploadtarget: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">284</context></context-group> + <source xml:space="preserve">The transaction amount is too small to pay the fee</source> + <context-group purpose="location"><context context-type="linenumber">306</context></context-group> </trans-unit> <trans-unit id="_msg1117"> - <source xml:space="preserve">Unable to start HTTP server. See debug log for details.</source> - <context-group purpose="location"><context context-type="linenumber">285</context></context-group> + <source xml:space="preserve">The wallet will avoid paying less than the minimum relay fee.</source> + <context-group purpose="location"><context context-type="linenumber">307</context></context-group> </trans-unit> <trans-unit id="_msg1118"> - <source xml:space="preserve">Unknown -blockfilterindex value %s.</source> - <context-group purpose="location"><context context-type="linenumber">286</context></context-group> + <source xml:space="preserve">This is experimental software.</source> + <context-group purpose="location"><context context-type="linenumber">308</context></context-group> </trans-unit> <trans-unit id="_msg1119"> - <source xml:space="preserve">Unknown address type '%s'</source> - <context-group purpose="location"><context context-type="linenumber">287</context></context-group> + <source xml:space="preserve">This is the minimum transaction fee you pay on every transaction.</source> + <context-group purpose="location"><context context-type="linenumber">309</context></context-group> </trans-unit> <trans-unit id="_msg1120"> - <source xml:space="preserve">Unknown change type '%s'</source> - <context-group purpose="location"><context context-type="linenumber">288</context></context-group> + <source xml:space="preserve">This is the transaction fee you will pay if you send a transaction.</source> + <context-group purpose="location"><context context-type="linenumber">310</context></context-group> </trans-unit> <trans-unit id="_msg1121"> - <source xml:space="preserve">Unknown network specified in -onlynet: '%s'</source> - <context-group purpose="location"><context context-type="linenumber">289</context></context-group> + <source xml:space="preserve">Transaction amount too small</source> + <context-group purpose="location"><context context-type="linenumber">311</context></context-group> </trans-unit> <trans-unit id="_msg1122"> - <source xml:space="preserve">Unknown new rules activated (versionbit %i)</source> - <context-group purpose="location"><context context-type="linenumber">290</context></context-group> + <source xml:space="preserve">Transaction amounts must not be negative</source> + <context-group purpose="location"><context context-type="linenumber">312</context></context-group> </trans-unit> <trans-unit id="_msg1123"> - <source xml:space="preserve">Unsupported logging category %s=%s.</source> - <context-group purpose="location"><context context-type="linenumber">291</context></context-group> + <source xml:space="preserve">Transaction change output index out of range</source> + <context-group purpose="location"><context context-type="linenumber">313</context></context-group> </trans-unit> <trans-unit id="_msg1124"> - <source xml:space="preserve">User Agent comment (%s) contains unsafe characters.</source> - <context-group purpose="location"><context context-type="linenumber">292</context></context-group> + <source xml:space="preserve">Transaction has too long of a mempool chain</source> + <context-group purpose="location"><context context-type="linenumber">314</context></context-group> </trans-unit> <trans-unit id="_msg1125"> - <source xml:space="preserve">Verifying blocks…</source> - <context-group purpose="location"><context context-type="linenumber">293</context></context-group> + <source xml:space="preserve">Transaction must have at least one recipient</source> + <context-group purpose="location"><context context-type="linenumber">315</context></context-group> </trans-unit> <trans-unit id="_msg1126"> - <source xml:space="preserve">Verifying wallet(s)…</source> - <context-group purpose="location"><context context-type="linenumber">294</context></context-group> + <source xml:space="preserve">Transaction needs a change address, but we can't generate it.</source> + <context-group purpose="location"><context context-type="linenumber">316</context></context-group> </trans-unit> <trans-unit id="_msg1127"> + <source xml:space="preserve">Transaction too large</source> + <context-group purpose="location"><context context-type="linenumber">317</context></context-group> + </trans-unit> + <trans-unit id="_msg1128"> + <source xml:space="preserve">Unable to allocate memory for -maxsigcachesize: '%s' MiB</source> + <context-group purpose="location"><context context-type="linenumber">318</context></context-group> + </trans-unit> + <trans-unit id="_msg1129"> + <source xml:space="preserve">Unable to bind to %s on this computer (bind returned error %s)</source> + <context-group purpose="location"><context context-type="linenumber">319</context></context-group> + </trans-unit> + <trans-unit id="_msg1130"> + <source xml:space="preserve">Unable to bind to %s on this computer. %s is probably already running.</source> + <context-group purpose="location"><context context-type="linenumber">320</context></context-group> + </trans-unit> + <trans-unit id="_msg1131"> + <source xml:space="preserve">Unable to create the PID file '%s': %s</source> + <context-group purpose="location"><context context-type="linenumber">321</context></context-group> + </trans-unit> + <trans-unit id="_msg1132"> + <source xml:space="preserve">Unable to find UTXO for external input</source> + <context-group purpose="location"><context context-type="linenumber">322</context></context-group> + </trans-unit> + <trans-unit id="_msg1133"> + <source xml:space="preserve">Unable to generate initial keys</source> + <context-group purpose="location"><context context-type="linenumber">323</context></context-group> + </trans-unit> + <trans-unit id="_msg1134"> + <source xml:space="preserve">Unable to generate keys</source> + <context-group purpose="location"><context context-type="linenumber">324</context></context-group> + </trans-unit> + <trans-unit id="_msg1135"> + <source xml:space="preserve">Unable to open %s for writing</source> + <context-group purpose="location"><context context-type="linenumber">325</context></context-group> + </trans-unit> + <trans-unit id="_msg1136"> + <source xml:space="preserve">Unable to parse -maxuploadtarget: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">326</context></context-group> + </trans-unit> + <trans-unit id="_msg1137"> + <source xml:space="preserve">Unable to start HTTP server. See debug log for details.</source> + <context-group purpose="location"><context context-type="linenumber">327</context></context-group> + </trans-unit> + <trans-unit id="_msg1138"> + <source xml:space="preserve">Unable to unload the wallet before migrating</source> + <context-group purpose="location"><context context-type="linenumber">328</context></context-group> + </trans-unit> + <trans-unit id="_msg1139"> + <source xml:space="preserve">Unknown -blockfilterindex value %s.</source> + <context-group purpose="location"><context context-type="linenumber">329</context></context-group> + </trans-unit> + <trans-unit id="_msg1140"> + <source xml:space="preserve">Unknown address type '%s'</source> + <context-group purpose="location"><context context-type="linenumber">330</context></context-group> + </trans-unit> + <trans-unit id="_msg1141"> + <source xml:space="preserve">Unknown change type '%s'</source> + <context-group purpose="location"><context context-type="linenumber">331</context></context-group> + </trans-unit> + <trans-unit id="_msg1142"> + <source xml:space="preserve">Unknown network specified in -onlynet: '%s'</source> + <context-group purpose="location"><context context-type="linenumber">332</context></context-group> + </trans-unit> + <trans-unit id="_msg1143"> + <source xml:space="preserve">Unknown new rules activated (versionbit %i)</source> + <context-group purpose="location"><context context-type="linenumber">333</context></context-group> + </trans-unit> + <trans-unit id="_msg1144"> + <source xml:space="preserve">Unsupported global logging level -loglevel=%s. Valid values: %s.</source> + <context-group purpose="location"><context context-type="linenumber">334</context></context-group> + </trans-unit> + <trans-unit id="_msg1145"> + <source xml:space="preserve">Unsupported logging category %s=%s.</source> + <context-group purpose="location"><context context-type="linenumber">335</context></context-group> + </trans-unit> + <trans-unit id="_msg1146"> + <source xml:space="preserve">User Agent comment (%s) contains unsafe characters.</source> + <context-group purpose="location"><context context-type="linenumber">336</context></context-group> + </trans-unit> + <trans-unit id="_msg1147"> + <source xml:space="preserve">Verifying blocks…</source> + <context-group purpose="location"><context context-type="linenumber">337</context></context-group> + </trans-unit> + <trans-unit id="_msg1148"> + <source xml:space="preserve">Verifying wallet(s)…</source> + <context-group purpose="location"><context context-type="linenumber">338</context></context-group> + </trans-unit> + <trans-unit id="_msg1149"> <source xml:space="preserve">Wallet needed to be rewritten: restart %s to complete</source> - <context-group purpose="location"><context context-type="linenumber">295</context></context-group> + <context-group purpose="location"><context context-type="linenumber">339</context></context-group> </trans-unit> </group> </body></file> diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index f57915e805..d1daf06732 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -767,7 +767,7 @@ static RPCHelpMan pruneblockchain() ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - CChainState& active_chainstate = chainman.ActiveChainstate(); + Chainstate& active_chainstate = chainman.ActiveChainstate(); CChain& active_chain = active_chainstate.m_chain; int heightParam = request.params[0].getInt<int>(); @@ -833,9 +833,9 @@ static std::optional<kernel::CCoinsStats> GetUTXOStats(CCoinsView* view, node::B // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested if ((hash_type == kernel::CoinStatsHashType::MUHASH || hash_type == kernel::CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) { if (pindex) { - return g_coin_stats_index->LookUpStats(pindex); + return g_coin_stats_index->LookUpStats(*pindex); } else { - CBlockIndex* block_index = WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())); + CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock()))); return g_coin_stats_index->LookUpStats(block_index); } } @@ -908,7 +908,7 @@ static RPCHelpMan gettxoutsetinfo() NodeContext& node = EnsureAnyNodeContext(request.context); ChainstateManager& chainman = EnsureChainman(node); - CChainState& active_chainstate = chainman.ActiveChainstate(); + Chainstate& active_chainstate = chainman.ActiveChainstate(); active_chainstate.ForceFlushStateToDisk(); CCoinsView* coins_view; @@ -1048,7 +1048,7 @@ static RPCHelpMan gettxout() fMempool = request.params[2].get_bool(); Coin coin; - CChainState& active_chainstate = chainman.ActiveChainstate(); + Chainstate& active_chainstate = chainman.ActiveChainstate(); CCoinsViewCache* coins_view = &active_chainstate.CoinsTip(); if (fMempool) { @@ -1105,7 +1105,7 @@ static RPCHelpMan verifychain() ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - CChainState& active_chainstate = chainman.ActiveChainstate(); + Chainstate& active_chainstate = chainman.ActiveChainstate(); return CVerifyDB().VerifyDB( active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth); }, @@ -1233,7 +1233,7 @@ RPCHelpMan getblockchaininfo() const ArgsManager& args{EnsureAnyArgsman(request.context)}; ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - CChainState& active_chainstate = chainman.ActiveChainstate(); + Chainstate& active_chainstate = chainman.ActiveChainstate(); const CBlockIndex& tip{*CHECK_NONFATAL(active_chainstate.m_chain.Tip())}; const int height{tip.nHeight}; @@ -1328,7 +1328,7 @@ static RPCHelpMan getdeploymentinfo() { const ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - const CChainState& active_chainstate = chainman.ActiveChainstate(); + const Chainstate& active_chainstate = chainman.ActiveChainstate(); const CBlockIndex* blockindex; if (request.params[0].isNull()) { @@ -2148,7 +2148,7 @@ static RPCHelpMan scantxoutset() { ChainstateManager& chainman = EnsureChainman(node); LOCK(cs_main); - CChainState& active_chainstate = chainman.ActiveChainstate(); + Chainstate& active_chainstate = chainman.ActiveChainstate(); active_chainstate.ForceFlushStateToDisk(); pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor()); tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip()); @@ -2328,7 +2328,7 @@ static RPCHelpMan dumptxoutset() UniValue CreateUTXOSnapshot( NodeContext& node, - CChainState& chainstate, + Chainstate& chainstate, AutoFile& afile, const fs::path& path, const fs::path& temppath) diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index a332fd4892..6cdb5fa48b 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -20,7 +20,7 @@ extern RecursiveMutex cs_main; class CBlock; class CBlockIndex; -class CChainState; +class Chainstate; class UniValue; namespace node { struct NodeContext; @@ -54,7 +54,7 @@ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], */ UniValue CreateUTXOSnapshot( node::NodeContext& node, - CChainState& chainstate, + Chainstate& chainstate, AutoFile& afile, const fs::path& path, const fs::path& tmppath); diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index db09a0c7b6..5c1770704d 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -168,7 +168,7 @@ static RPCHelpMan testmempoolaccept() NodeContext& node = EnsureAnyNodeContext(request.context); CTxMemPool& mempool = EnsureMemPool(node); ChainstateManager& chainman = EnsureChainman(node); - CChainState& chainstate = chainman.ActiveChainstate(); + Chainstate& chainstate = chainman.ActiveChainstate(); const PackageMempoolAcceptResult package_result = [&] { LOCK(::cs_main); if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true); @@ -810,7 +810,7 @@ static RPCHelpMan submitpackage() NodeContext& node = EnsureAnyNodeContext(request.context); CTxMemPool& mempool = EnsureMemPool(node); - CChainState& chainstate = EnsureChainman(node).ActiveChainstate(); + Chainstate& chainstate = EnsureChainman(node).ActiveChainstate(); const auto package_result = WITH_LOCK(::cs_main, return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/ false)); // First catch any errors. diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 1ad704a490..354af22ef4 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -598,7 +598,7 @@ static RPCHelpMan getblocktemplate() std::string strMode = "template"; UniValue lpval = NullUniValue; std::set<std::string> setClientRules; - CChainState& active_chainstate = chainman.ActiveChainstate(); + Chainstate& active_chainstate = chainman.ActiveChainstate(); CChain& active_chain = active_chainstate.m_chain; if (!request.params[0].isNull()) { diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index e221b3462d..d701a180ab 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -947,7 +947,8 @@ static RPCHelpMan addpeeraddress() bool success{false}; if (LookupHost(addr_string, net_addr, false)) { - CAddress address{{net_addr, port}, ServiceFlags{NODE_NETWORK | NODE_WITNESS}}; + CService service{net_addr, port}; + CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS}}; address.nTime = Now<NodeSeconds>(); // The source address is set equal to the address. This is equivalent to the peer // announcing itself. diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 7ffb499330..f365de7d0c 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -51,7 +51,7 @@ using node::GetTransaction; using node::NodeContext; using node::PSBTAnalysis; -static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, CChainState& active_chainstate) +static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, Chainstate& active_chainstate) { // Call into TxToUniv() in bitcoin-common to decode the transaction hex. // diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index e9987d73be..83a352dbea 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -21,8 +21,6 @@ #include <mutex> #include <unordered_map> -using SteadyClock = std::chrono::steady_clock; - static GlobalMutex g_rpc_warmup_mutex; static std::atomic<bool> g_rpc_running{false}; static bool fRPCInWarmup GUARDED_BY(g_rpc_warmup_mutex) = true; diff --git a/src/rpc/txoutproof.cpp b/src/rpc/txoutproof.cpp index dcf6c6bee1..cd8b49bfe1 100644 --- a/src/rpc/txoutproof.cpp +++ b/src/rpc/txoutproof.cpp @@ -66,7 +66,7 @@ static RPCHelpMan gettxoutproof() } } else { LOCK(cs_main); - CChainState& active_chainstate = chainman.ActiveChainstate(); + Chainstate& active_chainstate = chainman.ActiveChainstate(); // Loop through txids and try to find which block they're in. Exit loop once a block is found. for (const auto& tx : setTxids) { diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 24ab21a947..43935650fa 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -50,7 +50,8 @@ void RPCTypeCheck(const UniValue& params, void RPCTypeCheckArgument(const UniValue& value, const UniValueType& typeExpected) { if (!typeExpected.typeAny && value.type() != typeExpected.type) { - throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected.type), uvTypeName(value.type()))); + throw JSONRPCError(RPC_TYPE_ERROR, + strprintf("JSON value of type %s is not of expected type %s", uvTypeName(value.type()), uvTypeName(typeExpected.type))); } } diff --git a/src/script/miniscript.h b/src/script/miniscript.h index f783d1dafc..ab25fa67b7 100644 --- a/src/script/miniscript.h +++ b/src/script/miniscript.h @@ -276,6 +276,8 @@ struct StackSize { StackSize(MaxInt<uint32_t> in_sat, MaxInt<uint32_t> in_dsat) : sat(in_sat), dsat(in_dsat) {}; }; +struct NoDupCheck {}; + } // namespace internal //! A node in a miniscript expression. @@ -301,8 +303,13 @@ private: const Type typ; //! Cached script length (computed by CalcScriptLen). const size_t scriptlen; - //! Whether a public key appears more than once in this node. - const bool duplicate_key; + //! Whether a public key appears more than once in this node. This value is initialized + //! by all constructors except the NoDupCheck ones. The NoDupCheck ones skip the + //! computation, requiring it to be done manually by invoking DuplicateKeyCheck(). + //! DuplicateKeyCheck(), or a non-NoDupCheck constructor, will compute has_duplicate_keys + //! for all subnodes as well. + mutable std::optional<bool> has_duplicate_keys; + //! Compute the length of the script for this miniscript (including children). size_t CalcScriptLen() const { @@ -654,6 +661,7 @@ public: return TreeEvalMaybe<std::string>(false, downfn, upfn); } +private: internal::Ops CalcOps() const { switch (fragment) { case Fragment::JUST_1: return {0, 0, {}}; @@ -777,11 +785,14 @@ public: assert(false); } - /** Check whether any key is repeated. +public: + /** Update duplicate key information in this Node. + * * This uses a custom key comparator provided by the context in order to still detect duplicates * for more complicated types. */ - template<typename Ctx> bool ContainsDuplicateKey(const Ctx& ctx) const { + template<typename Ctx> void DuplicateKeyCheck(const Ctx& ctx) const + { // We cannot use a lambda here, as lambdas are non assignable, and the set operations // below require moving the comparators around. struct Comp { @@ -789,31 +800,55 @@ public: Comp(const Ctx& ctx) : ctx_ptr(&ctx) {} bool operator()(const Key& a, const Key& b) const { return ctx_ptr->KeyCompare(a, b); } }; - using set = std::set<Key, Comp>; - auto upfn = [this, &ctx](const Node& node, Span<set> subs) -> std::optional<set> { - if (&node != this && node.duplicate_key) return {}; + // state in the recursive computation: + // - std::nullopt means "this node has duplicates" + // - an std::set means "this node has no duplicate keys, and they are: ...". + using keyset = std::set<Key, Comp>; + using state = std::optional<keyset>; + + auto upfn = [&ctx](const Node& node, Span<state> subs) -> state { + // If this node is already known to have duplicates, nothing left to do. + if (node.has_duplicate_keys.has_value() && *node.has_duplicate_keys) return {}; + + // Check if one of the children is already known to have duplicates. + for (auto& sub : subs) { + if (!sub.has_value()) { + node.has_duplicate_keys = true; + return {}; + } + } + // Start building the set of keys involved in this node and children. + // Start by keys in this node directly. size_t keys_count = node.keys.size(); - set key_set{node.keys.begin(), node.keys.end(), Comp(ctx)}; - if (key_set.size() != keys_count) return {}; + keyset key_set{node.keys.begin(), node.keys.end(), Comp(ctx)}; + if (key_set.size() != keys_count) { + // It already has duplicates; bail out. + node.has_duplicate_keys = true; + return {}; + } - for (auto& sub: subs) { - keys_count += sub.size(); + // Merge the keys from the children into this set. + for (auto& sub : subs) { + keys_count += sub->size(); // Small optimization: std::set::merge is linear in the size of the second arg but // logarithmic in the size of the first. - if (key_set.size() < sub.size()) std::swap(key_set, sub); - key_set.merge(sub); - if (key_set.size() != keys_count) return {}; + if (key_set.size() < sub->size()) std::swap(key_set, *sub); + key_set.merge(*sub); + if (key_set.size() != keys_count) { + node.has_duplicate_keys = true; + return {}; + } } + node.has_duplicate_keys = false; return key_set; }; - return !TreeEvalMaybe<set>(upfn); + TreeEval<state>(upfn); } -public: //! Return the size of the script for this expression (faster than ToScript().size()). size_t ScriptSize() const { return scriptlen; } @@ -858,7 +893,7 @@ public: bool CheckTimeLocksMix() const { return GetType() << "k"_mst; } //! Check whether there is no duplicate key across this fragment and all its sub-fragments. - bool CheckDuplicateKey() const { return !duplicate_key; } + bool CheckDuplicateKey() const { return has_duplicate_keys && !*has_duplicate_keys; } //! Whether successful non-malleable satisfactions are guaranteed to be valid. bool ValidSatisfactions() const { return IsValid() && CheckOpsLimit() && CheckStackSize(); } @@ -872,13 +907,21 @@ public: //! Equality testing. bool operator==(const Node<Key>& arg) const { return Compare(*this, arg) == 0; } - // Constructors with various argument combinations. - template <typename Ctx> Node(const Ctx& ctx, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<unsigned char> arg, uint32_t val = 0) : fragment(nt), k(val), data(std::move(arg)), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()), duplicate_key(ContainsDuplicateKey(ctx)) {} - template <typename Ctx> Node(const Ctx& ctx, Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0) : fragment(nt), k(val), data(std::move(arg)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()), duplicate_key(ContainsDuplicateKey(ctx)) {} - template <typename Ctx> Node(const Ctx& ctx, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<Key> key, uint32_t val = 0) : fragment(nt), k(val), keys(std::move(key)), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()), duplicate_key(ContainsDuplicateKey(ctx)) {} - template <typename Ctx> Node(const Ctx& ctx, Fragment nt, std::vector<Key> key, uint32_t val = 0) : fragment(nt), k(val), keys(std::move(key)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()), duplicate_key(ContainsDuplicateKey(ctx)) {} - template <typename Ctx> Node(const Ctx& ctx, Fragment nt, std::vector<NodeRef<Key>> sub, uint32_t val = 0) : fragment(nt), k(val), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()), duplicate_key(ContainsDuplicateKey(ctx)) {} - template <typename Ctx> Node(const Ctx& ctx, Fragment nt, uint32_t val = 0) : fragment(nt), k(val), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()), duplicate_key(ContainsDuplicateKey(ctx)) {} + // Constructors with various argument combinations, which bypass the duplicate key check. + Node(internal::NoDupCheck, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<unsigned char> arg, uint32_t val = 0) : fragment(nt), k(val), data(std::move(arg)), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {} + Node(internal::NoDupCheck, Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0) : fragment(nt), k(val), data(std::move(arg)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {} + Node(internal::NoDupCheck, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<Key> key, uint32_t val = 0) : fragment(nt), k(val), keys(std::move(key)), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {} + Node(internal::NoDupCheck, Fragment nt, std::vector<Key> key, uint32_t val = 0) : fragment(nt), k(val), keys(std::move(key)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {} + Node(internal::NoDupCheck, Fragment nt, std::vector<NodeRef<Key>> sub, uint32_t val = 0) : fragment(nt), k(val), subs(std::move(sub)), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {} + Node(internal::NoDupCheck, Fragment nt, uint32_t val = 0) : fragment(nt), k(val), ops(CalcOps()), ss(CalcStackSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {} + + // Constructors with various argument combinations, which do perform the duplicate key check. + template <typename Ctx> Node(const Ctx& ctx, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<unsigned char> arg, uint32_t val = 0) : Node(internal::NoDupCheck{}, nt, std::move(sub), std::move(arg), val) { DuplicateKeyCheck(ctx); } + template <typename Ctx> Node(const Ctx& ctx, Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0) : Node(internal::NoDupCheck{}, nt, std::move(arg), val) { DuplicateKeyCheck(ctx);} + template <typename Ctx> Node(const Ctx& ctx, Fragment nt, std::vector<NodeRef<Key>> sub, std::vector<Key> key, uint32_t val = 0) : Node(internal::NoDupCheck{}, nt, std::move(sub), std::move(key), val) { DuplicateKeyCheck(ctx); } + template <typename Ctx> Node(const Ctx& ctx, Fragment nt, std::vector<Key> key, uint32_t val = 0) : Node(internal::NoDupCheck{}, nt, std::move(key), val) { DuplicateKeyCheck(ctx); } + template <typename Ctx> Node(const Ctx& ctx, Fragment nt, std::vector<NodeRef<Key>> sub, uint32_t val = 0) : Node(internal::NoDupCheck{}, nt, std::move(sub), val) { DuplicateKeyCheck(ctx); } + template <typename Ctx> Node(const Ctx& ctx, Fragment nt, uint32_t val = 0) : Node(internal::NoDupCheck{}, nt, val) { DuplicateKeyCheck(ctx); } }; namespace internal { @@ -965,15 +1008,15 @@ std::optional<std::pair<std::vector<unsigned char>, int>> ParseHexStrEnd(Span<co } /** BuildBack pops the last two elements off `constructed` and wraps them in the specified Fragment */ -template<typename Key, typename Ctx> -void BuildBack(const Ctx& ctx, Fragment nt, std::vector<NodeRef<Key>>& constructed, const bool reverse = false) +template<typename Key> +void BuildBack(Fragment nt, std::vector<NodeRef<Key>>& constructed, const bool reverse = false) { NodeRef<Key> child = std::move(constructed.back()); constructed.pop_back(); if (reverse) { - constructed.back() = MakeNodeRef<Key>(ctx, nt, Vector(std::move(child), std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, nt, Vector(std::move(child), std::move(constructed.back()))); } else { - constructed.back() = MakeNodeRef<Key>(ctx, nt, Vector(std::move(constructed.back()), std::move(child))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, nt, Vector(std::move(constructed.back()), std::move(child))); } } @@ -987,6 +1030,18 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) { using namespace spanparsing; + // Account for the minimum script size for all parsed fragments so far. It "borrows" 1 + // script byte from all leaf nodes, counting it instead whenever a space for a recursive + // expression is added (through andor, and_*, or_*, thresh). This guarantees that all fragments + // increment the script_size by at least one, except for: + // - "0", "1": these leafs are only a single byte, so their subtracted-from increment is 0. + // This is not an issue however, as "space" for them has to be created by combinators, + // which do increment script_size. + // - "v:": the v wrapper adds nothing as in some cases it results in no opcode being added + // (instead transforming another opcode into its VERIFY form). However, the v: wrapper has + // to be interleaved with other fragments to be valid, so this is not a concern. + size_t script_size{1}; + // The two integers are used to hold state for thresh() std::vector<std::tuple<ParseContext, int64_t, int64_t>> to_parse; std::vector<NodeRef<Key>> constructed; @@ -994,14 +1049,16 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1); while (!to_parse.empty()) { + if (script_size > MAX_STANDARD_P2WSH_SCRIPT_SIZE) return {}; + // Get the current context we are decoding within auto [cur_context, n, k] = to_parse.back(); to_parse.pop_back(); switch (cur_context) { case ParseContext::WRAPPED_EXPR: { - int colon_index = -1; - for (int i = 1; i < (int)in.size(); ++i) { + std::optional<size_t> colon_index{}; + for (size_t i = 1; i < in.size(); ++i) { if (in[i] == ':') { colon_index = i; break; @@ -1009,106 +1066,131 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) if (in[i] < 'a' || in[i] > 'z') break; } // If there is no colon, this loop won't execute - for (int j = 0; j < colon_index; ++j) { + bool last_was_v{false}; + for (size_t j = 0; colon_index && j < *colon_index; ++j) { + if (script_size > MAX_STANDARD_P2WSH_SCRIPT_SIZE) return {}; if (in[j] == 'a') { + script_size += 2; to_parse.emplace_back(ParseContext::ALT, -1, -1); } else if (in[j] == 's') { + script_size += 1; to_parse.emplace_back(ParseContext::SWAP, -1, -1); } else if (in[j] == 'c') { + script_size += 1; to_parse.emplace_back(ParseContext::CHECK, -1, -1); } else if (in[j] == 'd') { + script_size += 3; to_parse.emplace_back(ParseContext::DUP_IF, -1, -1); } else if (in[j] == 'j') { + script_size += 4; to_parse.emplace_back(ParseContext::NON_ZERO, -1, -1); } else if (in[j] == 'n') { + script_size += 1; to_parse.emplace_back(ParseContext::ZERO_NOTEQUAL, -1, -1); } else if (in[j] == 'v') { + // do not permit "...vv...:"; it's not valid, and also doesn't trigger early + // failure as script_size isn't incremented. + if (last_was_v) return {}; to_parse.emplace_back(ParseContext::VERIFY, -1, -1); } else if (in[j] == 'u') { + script_size += 4; to_parse.emplace_back(ParseContext::WRAP_U, -1, -1); } else if (in[j] == 't') { + script_size += 1; to_parse.emplace_back(ParseContext::WRAP_T, -1, -1); } else if (in[j] == 'l') { // The l: wrapper is equivalent to or_i(0,X) - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::JUST_0)); + script_size += 4; + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::JUST_0)); to_parse.emplace_back(ParseContext::OR_I, -1, -1); } else { return {}; } + last_was_v = (in[j] == 'v'); } to_parse.emplace_back(ParseContext::EXPR, -1, -1); - in = in.subspan(colon_index + 1); + if (colon_index) in = in.subspan(*colon_index + 1); break; } case ParseContext::EXPR: { if (Const("0", in)) { - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::JUST_0)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::JUST_0)); } else if (Const("1", in)) { - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::JUST_1)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::JUST_1)); } else if (Const("pk(", in)) { auto res = ParseKeyEnd<Key, Ctx>(in, ctx); if (!res) return {}; auto& [key, key_size] = *res; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::WRAP_C, Vector(MakeNodeRef<Key>(ctx, Fragment::PK_K, Vector(std::move(key)))))); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_C, Vector(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::PK_K, Vector(std::move(key)))))); in = in.subspan(key_size + 1); + script_size += 34; } else if (Const("pkh(", in)) { auto res = ParseKeyEnd<Key>(in, ctx); if (!res) return {}; auto& [key, key_size] = *res; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::WRAP_C, Vector(MakeNodeRef<Key>(ctx, Fragment::PK_H, Vector(std::move(key)))))); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_C, Vector(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::PK_H, Vector(std::move(key)))))); in = in.subspan(key_size + 1); + script_size += 24; } else if (Const("pk_k(", in)) { auto res = ParseKeyEnd<Key>(in, ctx); if (!res) return {}; auto& [key, key_size] = *res; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::PK_K, Vector(std::move(key)))); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::PK_K, Vector(std::move(key)))); in = in.subspan(key_size + 1); + script_size += 33; } else if (Const("pk_h(", in)) { auto res = ParseKeyEnd<Key>(in, ctx); if (!res) return {}; auto& [key, key_size] = *res; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::PK_H, Vector(std::move(key)))); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::PK_H, Vector(std::move(key)))); in = in.subspan(key_size + 1); + script_size += 23; } else if (Const("sha256(", in)) { auto res = ParseHexStrEnd(in, 32, ctx); if (!res) return {}; auto& [hash, hash_size] = *res; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::SHA256, std::move(hash))); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::SHA256, std::move(hash))); in = in.subspan(hash_size + 1); + script_size += 38; } else if (Const("ripemd160(", in)) { auto res = ParseHexStrEnd(in, 20, ctx); if (!res) return {}; auto& [hash, hash_size] = *res; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::RIPEMD160, std::move(hash))); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::RIPEMD160, std::move(hash))); in = in.subspan(hash_size + 1); + script_size += 26; } else if (Const("hash256(", in)) { auto res = ParseHexStrEnd(in, 32, ctx); if (!res) return {}; auto& [hash, hash_size] = *res; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::HASH256, std::move(hash))); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::HASH256, std::move(hash))); in = in.subspan(hash_size + 1); + script_size += 38; } else if (Const("hash160(", in)) { auto res = ParseHexStrEnd(in, 20, ctx); if (!res) return {}; auto& [hash, hash_size] = *res; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::HASH160, std::move(hash))); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::HASH160, std::move(hash))); in = in.subspan(hash_size + 1); + script_size += 26; } else if (Const("after(", in)) { int arg_size = FindNextChar(in, ')'); if (arg_size < 1) return {}; int64_t num; if (!ParseInt64(std::string(in.begin(), in.begin() + arg_size), &num)) return {}; if (num < 1 || num >= 0x80000000L) return {}; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::AFTER, num)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::AFTER, num)); in = in.subspan(arg_size + 1); + script_size += 1 + (num > 16) + (num > 0x7f) + (num > 0x7fff) + (num > 0x7fffff); } else if (Const("older(", in)) { int arg_size = FindNextChar(in, ')'); if (arg_size < 1) return {}; int64_t num; if (!ParseInt64(std::string(in.begin(), in.begin() + arg_size), &num)) return {}; if (num < 1 || num >= 0x80000000L) return {}; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::OLDER, num)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::OLDER, num)); in = in.subspan(arg_size + 1); + script_size += 1 + (num > 16) + (num > 0x7f) + (num > 0x7fff) + (num > 0x7fffff); } else if (Const("multi(", in)) { // Get threshold int next_comma = FindNextChar(in, ','); @@ -1128,7 +1210,8 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) } if (keys.size() < 1 || keys.size() > 20) return {}; if (k < 1 || k > (int64_t)keys.size()) return {}; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::MULTI, std::move(keys), k)); + script_size += 2 + (keys.size() > 16) + (k > 16) + 34 * keys.size(); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::MULTI, std::move(keys), k)); } else if (Const("thresh(", in)) { int next_comma = FindNextChar(in, ','); if (next_comma < 1) return {}; @@ -1138,6 +1221,7 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) // n = 1 here because we read the first WRAPPED_EXPR before reaching THRESH to_parse.emplace_back(ParseContext::THRESH, 1, k); to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1); + script_size += 2 + (k > 16); } else if (Const("andor(", in)) { to_parse.emplace_back(ParseContext::ANDOR, -1, -1); to_parse.emplace_back(ParseContext::CLOSE_BRACKET, -1, -1); @@ -1146,21 +1230,29 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1); to_parse.emplace_back(ParseContext::COMMA, -1, -1); to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1); + script_size += 5; } else { if (Const("and_n(", in)) { to_parse.emplace_back(ParseContext::AND_N, -1, -1); + script_size += 5; } else if (Const("and_b(", in)) { to_parse.emplace_back(ParseContext::AND_B, -1, -1); + script_size += 2; } else if (Const("and_v(", in)) { to_parse.emplace_back(ParseContext::AND_V, -1, -1); + script_size += 1; } else if (Const("or_b(", in)) { to_parse.emplace_back(ParseContext::OR_B, -1, -1); + script_size += 2; } else if (Const("or_c(", in)) { to_parse.emplace_back(ParseContext::OR_C, -1, -1); + script_size += 3; } else if (Const("or_d(", in)) { to_parse.emplace_back(ParseContext::OR_D, -1, -1); + script_size += 4; } else if (Const("or_i(", in)) { to_parse.emplace_back(ParseContext::OR_I, -1, -1); + script_size += 4; } else { return {}; } @@ -1172,69 +1264,70 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) break; } case ParseContext::ALT: { - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_A, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_A, Vector(std::move(constructed.back()))); break; } case ParseContext::SWAP: { - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_S, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_S, Vector(std::move(constructed.back()))); break; } case ParseContext::CHECK: { - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_C, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_C, Vector(std::move(constructed.back()))); break; } case ParseContext::DUP_IF: { - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_D, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_D, Vector(std::move(constructed.back()))); break; } case ParseContext::NON_ZERO: { - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_J, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_J, Vector(std::move(constructed.back()))); break; } case ParseContext::ZERO_NOTEQUAL: { - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_N, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_N, Vector(std::move(constructed.back()))); break; } case ParseContext::VERIFY: { - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_V, Vector(std::move(constructed.back()))); + script_size += (constructed.back()->GetType() << "x"_mst); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_V, Vector(std::move(constructed.back()))); break; } case ParseContext::WRAP_U: { - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::OR_I, Vector(std::move(constructed.back()), MakeNodeRef<Key>(ctx, Fragment::JUST_0))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::OR_I, Vector(std::move(constructed.back()), MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::JUST_0))); break; } case ParseContext::WRAP_T: { - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::AND_V, Vector(std::move(constructed.back()), MakeNodeRef<Key>(ctx, Fragment::JUST_1))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::AND_V, Vector(std::move(constructed.back()), MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::JUST_1))); break; } case ParseContext::AND_B: { - BuildBack(ctx, Fragment::AND_B, constructed); + BuildBack(Fragment::AND_B, constructed); break; } case ParseContext::AND_N: { auto mid = std::move(constructed.back()); constructed.pop_back(); - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), MakeNodeRef<Key>(ctx, Fragment::JUST_0))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), MakeNodeRef<Key>(ctx, Fragment::JUST_0))); break; } case ParseContext::AND_V: { - BuildBack(ctx, Fragment::AND_V, constructed); + BuildBack(Fragment::AND_V, constructed); break; } case ParseContext::OR_B: { - BuildBack(ctx, Fragment::OR_B, constructed); + BuildBack(Fragment::OR_B, constructed); break; } case ParseContext::OR_C: { - BuildBack(ctx, Fragment::OR_C, constructed); + BuildBack(Fragment::OR_C, constructed); break; } case ParseContext::OR_D: { - BuildBack(ctx, Fragment::OR_D, constructed); + BuildBack(Fragment::OR_D, constructed); break; } case ParseContext::OR_I: { - BuildBack(ctx, Fragment::OR_I, constructed); + BuildBack(Fragment::OR_I, constructed); break; } case ParseContext::ANDOR: { @@ -1242,7 +1335,7 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) constructed.pop_back(); auto mid = std::move(constructed.back()); constructed.pop_back(); - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::ANDOR, Vector(std::move(constructed.back()), std::move(mid), std::move(right))); break; } case ParseContext::THRESH: { @@ -1251,6 +1344,7 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) in = in.subspan(1); to_parse.emplace_back(ParseContext::THRESH, n+1, k); to_parse.emplace_back(ParseContext::WRAPPED_EXPR, -1, -1); + script_size += 2; } else if (in[0] == ')') { if (k > n) return {}; in = in.subspan(1); @@ -1261,7 +1355,7 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) constructed.pop_back(); } std::reverse(subs.begin(), subs.end()); - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::THRESH, std::move(subs), k)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::THRESH, std::move(subs), k)); } else { return {}; } @@ -1282,8 +1376,11 @@ inline NodeRef<Key> Parse(Span<const char> in, const Ctx& ctx) // Sanity checks on the produced miniscript assert(constructed.size() == 1); + assert(constructed[0]->ScriptSize() == script_size); if (in.size() > 0) return {}; - return std::move(constructed.front()); + const NodeRef<Key> tl_node = std::move(constructed.front()); + tl_node->DuplicateKeyCheck(ctx); + return tl_node; } /** Decode a script into opcode/push pairs. @@ -1394,12 +1491,12 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx) // Constants if (in[0].first == OP_1) { ++in; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::JUST_1)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::JUST_1)); break; } if (in[0].first == OP_0) { ++in; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::JUST_0)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::JUST_0)); break; } // Public keys @@ -1407,14 +1504,14 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx) auto key = ctx.FromPKBytes(in[0].second.begin(), in[0].second.end()); if (!key) return {}; ++in; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::PK_K, Vector(std::move(*key)))); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::PK_K, Vector(std::move(*key)))); break; } if (last - in >= 5 && in[0].first == OP_VERIFY && in[1].first == OP_EQUAL && in[3].first == OP_HASH160 && in[4].first == OP_DUP && in[2].second.size() == 20) { auto key = ctx.FromPKHBytes(in[2].second.begin(), in[2].second.end()); if (!key) return {}; in += 5; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::PK_H, Vector(std::move(*key)))); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::PK_H, Vector(std::move(*key)))); break; } // Time locks @@ -1422,31 +1519,31 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx) if (last - in >= 2 && in[0].first == OP_CHECKSEQUENCEVERIFY && (num = ParseScriptNumber(in[1]))) { in += 2; if (*num < 1 || *num > 0x7FFFFFFFL) return {}; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::OLDER, *num)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::OLDER, *num)); break; } if (last - in >= 2 && in[0].first == OP_CHECKLOCKTIMEVERIFY && (num = ParseScriptNumber(in[1]))) { in += 2; if (num < 1 || num > 0x7FFFFFFFL) return {}; - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::AFTER, *num)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::AFTER, *num)); break; } // Hashes if (last - in >= 7 && in[0].first == OP_EQUAL && in[3].first == OP_VERIFY && in[4].first == OP_EQUAL && (num = ParseScriptNumber(in[5])) && num == 32 && in[6].first == OP_SIZE) { if (in[2].first == OP_SHA256 && in[1].second.size() == 32) { - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::SHA256, in[1].second)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::SHA256, in[1].second)); in += 7; break; } else if (in[2].first == OP_RIPEMD160 && in[1].second.size() == 20) { - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::RIPEMD160, in[1].second)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::RIPEMD160, in[1].second)); in += 7; break; } else if (in[2].first == OP_HASH256 && in[1].second.size() == 32) { - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::HASH256, in[1].second)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::HASH256, in[1].second)); in += 7; break; } else if (in[2].first == OP_HASH160 && in[1].second.size() == 20) { - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::HASH160, in[1].second)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::HASH160, in[1].second)); in += 7; break; } @@ -1467,7 +1564,7 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx) if (!k || *k < 1 || *k > *n) return {}; in += 3 + *n; std::reverse(keys.begin(), keys.end()); - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::MULTI, std::move(keys), *k)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::MULTI, std::move(keys), *k)); break; } /** In the following wrappers, we only need to push SINGLE_BKV_EXPR rather @@ -1562,63 +1659,63 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx) case DecodeContext::SWAP: { if (in >= last || in[0].first != OP_SWAP || constructed.empty()) return {}; ++in; - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_S, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_S, Vector(std::move(constructed.back()))); break; } case DecodeContext::ALT: { if (in >= last || in[0].first != OP_TOALTSTACK || constructed.empty()) return {}; ++in; - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_A, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_A, Vector(std::move(constructed.back()))); break; } case DecodeContext::CHECK: { if (constructed.empty()) return {}; - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_C, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_C, Vector(std::move(constructed.back()))); break; } case DecodeContext::DUP_IF: { if (constructed.empty()) return {}; - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_D, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_D, Vector(std::move(constructed.back()))); break; } case DecodeContext::VERIFY: { if (constructed.empty()) return {}; - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_V, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_V, Vector(std::move(constructed.back()))); break; } case DecodeContext::NON_ZERO: { if (constructed.empty()) return {}; - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_J, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_J, Vector(std::move(constructed.back()))); break; } case DecodeContext::ZERO_NOTEQUAL: { if (constructed.empty()) return {}; - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::WRAP_N, Vector(std::move(constructed.back()))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::WRAP_N, Vector(std::move(constructed.back()))); break; } case DecodeContext::AND_V: { if (constructed.size() < 2) return {}; - BuildBack(ctx, Fragment::AND_V, constructed, /*reverse=*/true); + BuildBack(Fragment::AND_V, constructed, /*reverse=*/true); break; } case DecodeContext::AND_B: { if (constructed.size() < 2) return {}; - BuildBack(ctx, Fragment::AND_B, constructed, /*reverse=*/true); + BuildBack(Fragment::AND_B, constructed, /*reverse=*/true); break; } case DecodeContext::OR_B: { if (constructed.size() < 2) return {}; - BuildBack(ctx, Fragment::OR_B, constructed, /*reverse=*/true); + BuildBack(Fragment::OR_B, constructed, /*reverse=*/true); break; } case DecodeContext::OR_C: { if (constructed.size() < 2) return {}; - BuildBack(ctx, Fragment::OR_C, constructed, /*reverse=*/true); + BuildBack(Fragment::OR_C, constructed, /*reverse=*/true); break; } case DecodeContext::OR_D: { if (constructed.size() < 2) return {}; - BuildBack(ctx, Fragment::OR_D, constructed, /*reverse=*/true); + BuildBack(Fragment::OR_D, constructed, /*reverse=*/true); break; } case DecodeContext::ANDOR: { @@ -1628,7 +1725,7 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx) NodeRef<Key> right = std::move(constructed.back()); constructed.pop_back(); NodeRef<Key> mid = std::move(constructed.back()); - constructed.back() = MakeNodeRef<Key>(ctx, Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))); + constructed.back() = MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::ANDOR, Vector(std::move(left), std::move(mid), std::move(right))); break; } case DecodeContext::THRESH_W: { @@ -1652,7 +1749,7 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx) constructed.pop_back(); subs.push_back(std::move(sub)); } - constructed.push_back(MakeNodeRef<Key>(ctx, Fragment::THRESH, std::move(subs), k)); + constructed.push_back(MakeNodeRef<Key>(internal::NoDupCheck{}, Fragment::THRESH, std::move(subs), k)); break; } case DecodeContext::ENDIF: { @@ -1702,7 +1799,7 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx) if (in >= last) return {}; if (in[0].first == OP_IF) { ++in; - BuildBack(ctx, Fragment::OR_I, constructed, /*reverse=*/true); + BuildBack(Fragment::OR_I, constructed, /*reverse=*/true); } else if (in[0].first == OP_NOTIF) { ++in; to_parse.emplace_back(DecodeContext::ANDOR, -1, -1); @@ -1717,6 +1814,7 @@ inline NodeRef<Key> DecodeScript(I& in, I last, const Ctx& ctx) } if (constructed.size() != 1) return {}; const NodeRef<Key> tl_node = std::move(constructed.front()); + tl_node->DuplicateKeyCheck(ctx); // Note that due to how ComputeType works (only assign the type to the node if the // subs' types are valid) this would fail if any node of tree is badly typed. if (!tl_node->IsValidTopLevel()) return {}; @@ -1733,6 +1831,8 @@ inline NodeRef<typename Ctx::Key> FromString(const std::string& str, const Ctx& template<typename Ctx> inline NodeRef<typename Ctx::Key> FromScript(const CScript& script, const Ctx& ctx) { using namespace internal; + // A too large Script is necessarily invalid, don't bother parsing it. + if (script.size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE) return {}; auto decomposed = DecomposeScript(script); if (!decomposed) return {}; auto it = decomposed->begin(); diff --git a/src/sync.h b/src/sync.h index 7ec4b668ac..c34d969041 100644 --- a/src/sync.h +++ b/src/sync.h @@ -261,7 +261,7 @@ inline RecursiveMutex* MaybeCheckNotHeld(RecursiveMutex* cs) LOCKS_EXCLUDED(cs) #define LOCK(cs) DebugLock<decltype(cs)> UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) #define LOCK2(cs1, cs2) \ DebugLock<decltype(cs1)> criticalblock1(MaybeCheckNotHeld(cs1), #cs1, __FILE__, __LINE__); \ - DebugLock<decltype(cs2)> criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__); + DebugLock<decltype(cs2)> criticalblock2(MaybeCheckNotHeld(cs2), #cs2, __FILE__, __LINE__) #define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__, true) #define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp index 132c4e53e7..2a6a777cfe 100644 --- a/src/test/coinstatsindex_tests.cpp +++ b/src/test/coinstatsindex_tests.cpp @@ -5,6 +5,7 @@ #include <chainparams.h> #include <index/coinstatsindex.h> #include <interfaces/chain.h> +#include <kernel/coinstats.h> #include <test/util/setup_common.h> #include <test/util/validation.h> #include <util/time.h> @@ -38,7 +39,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) } // CoinStatsIndex should not be found before it is started. - BOOST_CHECK(!coin_stats_index.LookUpStats(block_index)); + BOOST_CHECK(!coin_stats_index.LookUpStats(*block_index)); // BlockUntilSyncedToCurrentChain should return false before CoinStatsIndex // is started. @@ -54,10 +55,10 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) LOCK(cs_main); genesis_block_index = m_node.chainman->ActiveChain().Genesis(); } - BOOST_CHECK(coin_stats_index.LookUpStats(genesis_block_index)); + BOOST_CHECK(coin_stats_index.LookUpStats(*genesis_block_index)); // Check that CoinStatsIndex updates with new blocks. - BOOST_CHECK(coin_stats_index.LookUpStats(block_index)); + BOOST_CHECK(coin_stats_index.LookUpStats(*block_index)); const CScript script_pub_key{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG}; std::vector<CMutableTransaction> noTxns; @@ -71,7 +72,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) LOCK(cs_main); new_block_index = m_node.chainman->ActiveChain().Tip(); } - BOOST_CHECK(coin_stats_index.LookUpStats(new_block_index)); + BOOST_CHECK(coin_stats_index.LookUpStats(*new_block_index)); BOOST_CHECK(block_index != new_block_index); @@ -85,7 +86,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) // make sure index is not corrupted and is able to reload. BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup) { - CChainState& chainstate = Assert(m_node.chainman)->ActiveChainstate(); + Chainstate& chainstate = Assert(m_node.chainman)->ActiveChainstate(); const CChainParams& params = Params(); { CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20}; diff --git a/src/test/fuzz/mempool_utils.h b/src/test/fuzz/mempool_utils.h index bfe12e30ba..c172e8c4b7 100644 --- a/src/test/fuzz/mempool_utils.h +++ b/src/test/fuzz/mempool_utils.h @@ -7,7 +7,7 @@ #include <validation.h> -class DummyChainState final : public CChainState +class DummyChainState final : public Chainstate { public: void SetMempool(CTxMemPool* mempool) diff --git a/src/test/fuzz/tx_pool.cpp b/src/test/fuzz/tx_pool.cpp index 3191367870..283a146369 100644 --- a/src/test/fuzz/tx_pool.cpp +++ b/src/test/fuzz/tx_pool.cpp @@ -85,7 +85,7 @@ void SetMempoolConstraints(ArgsManager& args, FuzzedDataProvider& fuzzed_data_pr ToString(fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999))); } -void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, CChainState& chainstate) +void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, Chainstate& chainstate) { WITH_LOCK(::cs_main, tx_pool.check(chainstate.CoinsTip(), chainstate.m_chain.Height() + 1)); { @@ -108,7 +108,7 @@ void Finish(FuzzedDataProvider& fuzzed_data_provider, MockedTxPool& tx_pool, CCh SyncWithValidationInterfaceQueue(); } -void MockTime(FuzzedDataProvider& fuzzed_data_provider, const CChainState& chainstate) +void MockTime(FuzzedDataProvider& fuzzed_data_provider, const Chainstate& chainstate) { const auto time = ConsumeTime(fuzzed_data_provider, chainstate.m_chain.Tip()->GetMedianTimePast() + 1, diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp index 95e8476b77..9387c01e73 100644 --- a/src/test/miniscript_tests.cpp +++ b/src/test/miniscript_tests.cpp @@ -296,6 +296,9 @@ BOOST_AUTO_TEST_CASE(fixed_tests) // Same when the duplicates are on different levels in the tree const auto ms_dup4 = miniscript::FromString("thresh(2,pkh(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65),s:pk(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),a:and_b(dv:older(1),s:pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)))", CONVERTER); BOOST_CHECK(ms_dup4 && !ms_dup4->IsSane() && !ms_dup4->CheckDuplicateKey()); + // Sanity check the opposite is true, too. An otherwise sane Miniscript with no duplicate keys is sane. + const auto ms_nondup = miniscript::FromString("pk(03d30199d74fb5a22d47b6e054e2f378cedacffcb89904a61d75d0dbd407143e65)", CONVERTER); + BOOST_CHECK(ms_nondup && ms_nondup->CheckDuplicateKey() && ms_nondup->IsSane()); // Test we find the first insane sub closer to be a leaf node. This fragment is insane for two reasons: // 1. It can be spent without a signature // 2. It contains timelock mixes diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index f6642d3218..12905f6b70 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -840,7 +840,7 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message) const int64_t time{0}; const CNetMsgMaker msg_maker{PROTOCOL_VERSION}; - // Force CChainState::IsInitialBlockDownload() to return false. + // Force Chainstate::IsInitialBlockDownload() to return false. // Otherwise PushAddress() isn't called by PeerManager::ProcessMessage(). TestChainState& chainstate = *static_cast<TestChainState*>(&m_node.chainman->ActiveChainstate()); diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h index 13e0e684b8..2f0021b114 100644 --- a/src/test/util/chainstate.h +++ b/src/test/util/chainstate.h @@ -7,6 +7,7 @@ #include <clientversion.h> #include <fs.h> +#include <logging.h> #include <node/context.h> #include <node/utxo_snapshot.h> #include <rpc/blockchain.h> @@ -14,8 +15,6 @@ #include <univalue.h> -#include <boost/test/unit_test.hpp> - const auto NoMalleation = [](AutoFile& file, node::SnapshotMetadata& meta){}; /** @@ -36,8 +35,8 @@ CreateAndActivateUTXOSnapshot(node::NodeContext& node, const fs::path root, F ma UniValue result = CreateUTXOSnapshot( node, node.chainman->ActiveChainstate(), auto_outfile, snapshot_path, snapshot_path); - BOOST_TEST_MESSAGE( - "Wrote UTXO snapshot to " << fs::PathToString(snapshot_path.make_preferred()) << ": " << result.write()); + LogPrintf( + "Wrote UTXO snapshot to %s: %s", fs::PathToString(snapshot_path.make_preferred()), result.write()); // Read the written snapshot in and then activate it. // diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index c3989a12fe..74b055ee45 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -296,7 +296,7 @@ void TestChain100Setup::mineBlocks(int num_blocks) CBlock TestChain100Setup::CreateBlock( const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey, - CChainState& chainstate) + Chainstate& chainstate) { CBlock block = BlockAssembler{chainstate, nullptr}.CreateNewBlock(scriptPubKey)->block; @@ -314,7 +314,7 @@ CBlock TestChain100Setup::CreateBlock( CBlock TestChain100Setup::CreateAndProcessBlock( const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey, - CChainState* chainstate) + Chainstate* chainstate) { if (!chainstate) { chainstate = &Assert(m_node.chainman)->ActiveChainstate(); diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index ed2c5db7e6..136ee1fd62 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -134,7 +134,7 @@ struct TestChain100Setup : public TestingSetup { */ CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey, - CChainState* chainstate = nullptr); + Chainstate* chainstate = nullptr); /** * Create a new block with just given transactions, coinbase paying to @@ -143,7 +143,7 @@ struct TestChain100Setup : public TestingSetup { CBlock CreateBlock( const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey, - CChainState& chainstate); + Chainstate& chainstate); //! Mine a series of new blocks on the active chain. void mineBlocks(int num_blocks); diff --git a/src/test/util/validation.h b/src/test/util/validation.h index b0bc717b6c..cbe7745b81 100644 --- a/src/test/util/validation.h +++ b/src/test/util/validation.h @@ -9,7 +9,7 @@ class CValidationInterface; -struct TestChainState : public CChainState { +struct TestChainState : public Chainstate { /** Reset the ibd cache to its initial state */ void ResetIbd(); /** Toggle IsInitialBlockDownload from true to false */ diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp index 98294b9028..347a967b33 100644 --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -18,7 +18,7 @@ BOOST_FIXTURE_TEST_SUITE(validation_chainstate_tests, ChainTestingSetup) -//! Test resizing coins-related CChainState caches during runtime. +//! Test resizing coins-related Chainstate caches during runtime. //! BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) { @@ -38,7 +38,7 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) return outp; }; - CChainState& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool)); + Chainstate& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool)); c1.InitCoinsDB( /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23)); @@ -106,8 +106,8 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup) BOOST_CHECK_EQUAL(chainman.GetAll().size(), 2); - CChainState& background_cs{*[&] { - for (CChainState* cs : chainman.GetAll()) { + Chainstate& background_cs{*[&] { + for (Chainstate* cs : chainman.GetAll()) { if (cs != &chainman.ActiveChainstate()) { return cs; } diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 7b7bd05b5c..24ad9458c9 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -32,13 +32,13 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) ChainstateManager& manager = *m_node.chainman; CTxMemPool& mempool = *m_node.mempool; - std::vector<CChainState*> chainstates; + std::vector<Chainstate*> chainstates; BOOST_CHECK(!manager.SnapshotBlockhash().has_value()); // Create a legacy (IBD) chainstate. // - CChainState& c1 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(&mempool)); + Chainstate& c1 = WITH_LOCK(::cs_main, return manager.InitializeChainstate(&mempool)); chainstates.push_back(&c1); c1.InitCoinsDB( /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); @@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) // Create a snapshot-based chainstate. // const uint256 snapshot_blockhash = GetRandHash(); - CChainState& c2 = WITH_LOCK(::cs_main, return manager.InitializeChainstate( + Chainstate& c2 = WITH_LOCK(::cs_main, return manager.InitializeChainstate( &mempool, snapshot_blockhash)); chainstates.push_back(&c2); @@ -111,11 +111,11 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) manager.m_total_coinsdb_cache = max_cache; manager.m_total_coinstip_cache = max_cache; - std::vector<CChainState*> chainstates; + std::vector<Chainstate*> chainstates; // Create a legacy (IBD) chainstate. // - CChainState& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool)); + Chainstate& c1 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool)); chainstates.push_back(&c1); c1.InitCoinsDB( /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); @@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) // Create a snapshot-based chainstate. // - CChainState& c2 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool, GetRandHash())); + Chainstate& c2 = WITH_LOCK(cs_main, return manager.InitializeChainstate(&mempool, GetRandHash())); chainstates.push_back(&c2); c2.InitCoinsDB( /*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false); @@ -250,7 +250,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup) LOCK(::cs_main); int chains_tested{0}; - for (CChainState* chainstate : chainman.GetAll()) { + for (Chainstate* chainstate : chainman.GetAll()) { BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString()); CCoinsViewCache& coinscache = chainstate->CoinsTip(); @@ -283,7 +283,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup) size_t coins_in_background{0}; size_t coins_missing_from_background{0}; - for (CChainState* chainstate : chainman.GetAll()) { + for (Chainstate* chainstate : chainman.GetAll()) { BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString()); CCoinsViewCache& coinscache = chainstate->CoinsTip(); bool is_background = chainstate != &chainman.ActiveChainstate(); @@ -326,7 +326,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup) { ChainstateManager& chainman = *Assert(m_node.chainman); CTxMemPool& mempool = *m_node.mempool; - CChainState& cs1 = chainman.ActiveChainstate(); + Chainstate& cs1 = chainman.ActiveChainstate(); int num_indexes{0}; int num_assumed_valid{0}; @@ -338,7 +338,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup) CBlockIndex* assumed_tip{WITH_LOCK(chainman.GetMutex(), return chainman.ActiveChain().Tip())}; auto reload_all_block_indexes = [&]() { - for (CChainState* cs : chainman.GetAll()) { + for (Chainstate* cs : chainman.GetAll()) { LOCK(::cs_main); cs->UnloadBlockIndex(); BOOST_CHECK(cs->setBlockIndexCandidates.empty()); @@ -373,7 +373,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_loadblockindex, TestChain100Setup) BOOST_CHECK_EQUAL(expected_assumed_valid, num_assumed_valid); - CChainState& cs2 = WITH_LOCK(::cs_main, + Chainstate& cs2 = WITH_LOCK(::cs_main, return chainman.InitializeChainstate(&mempool, GetRandHash())); reload_all_block_indexes(); diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp index 74b2af6858..c06e6c8d3b 100644 --- a/src/test/validation_flush_tests.cpp +++ b/src/test/validation_flush_tests.cpp @@ -13,11 +13,11 @@ BOOST_FIXTURE_TEST_SUITE(validation_flush_tests, TestingSetup) //! Test utilities for detecting when we need to flush the coins cache based //! on estimated memory usage. //! -//! @sa CChainState::GetCoinsCacheSizeState() +//! @sa Chainstate::GetCoinsCacheSizeState() //! BOOST_AUTO_TEST_CASE(getcoinscachesizestate) { - CChainState& chainstate{m_node.chainman->ActiveChainstate()}; + Chainstate& chainstate{m_node.chainman->ActiveChainstate()}; constexpr bool is_64_bit = sizeof(void*) == 8; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index b151953d0d..e1288b7346 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -24,38 +24,6 @@ #include <cmath> #include <optional> -// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index. -struct update_descendant_state -{ - update_descendant_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount) : - modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount) - {} - - void operator() (CTxMemPoolEntry &e) - { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); } - - private: - int64_t modifySize; - CAmount modifyFee; - int64_t modifyCount; -}; - -struct update_ancestor_state -{ - update_ancestor_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount, int64_t _modifySigOpsCost) : - modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount), modifySigOpsCost(_modifySigOpsCost) - {} - - void operator() (CTxMemPoolEntry &e) - { e.UpdateAncestorState(modifySize, modifyFee, modifyCount, modifySigOpsCost); } - - private: - int64_t modifySize; - CAmount modifyFee; - int64_t modifyCount; - int64_t modifySigOpsCost; -}; - bool TestLockPointValidity(CChain& active_chain, const LockPoints& lp) { AssertLockHeld(cs_main); @@ -146,7 +114,9 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendan modifyCount++; 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())); + mapTx.modify(mapTx.iterator_to(descendant), [=](CTxMemPoolEntry& e) { + e.UpdateAncestorState(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. @@ -155,7 +125,7 @@ void CTxMemPool::UpdateForDescendants(txiter updateIt, cacheMap& cachedDescendan } } } - mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount)); + mapTx.modify(updateIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(modifySize, modifyFee, modifyCount); }); } void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256>& vHashesToUpdate) @@ -347,7 +317,7 @@ void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors const int64_t updateSize = updateCount * it->GetTxSize(); const CAmount updateFee = updateCount * it->GetModifiedFee(); for (txiter ancestorIt : setAncestors) { - mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount)); + mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e) { e.UpdateDescendantState(updateSize, updateFee, updateCount); }); } } @@ -362,7 +332,7 @@ void CTxMemPool::UpdateEntryForAncestors(txiter it, const setEntries &setAncesto updateFee += ancestorIt->GetModifiedFee(); updateSigOpsCost += ancestorIt->GetSigOpCost(); } - mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, updateSigOpsCost)); + mapTx.modify(it, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(updateSize, updateFee, updateCount, updateSigOpsCost); }); } void CTxMemPool::UpdateChildrenForRemoval(txiter it) @@ -393,7 +363,7 @@ void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove, b CAmount modifyFee = -removeIt->GetModifiedFee(); int modifySigOps = -removeIt->GetSigOpCost(); for (txiter dit : setDescendants) { - mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, -1, modifySigOps)); + mapTx.modify(dit, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(modifySize, modifyFee, -1, modifySigOps); }); } } } @@ -942,14 +912,14 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD std::string dummy; CalculateMemPoolAncestors(*it, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy, false); for (txiter ancestorIt : setAncestors) { - mapTx.modify(ancestorIt, update_descendant_state(0, nFeeDelta, 0)); + mapTx.modify(ancestorIt, [=](CTxMemPoolEntry& e){ e.UpdateDescendantState(0, nFeeDelta, 0);}); } // Now update all descendants' modified fees with ancestors setEntries setDescendants; CalculateDescendants(it, setDescendants); setDescendants.erase(it); for (txiter descendantIt : setDescendants) { - mapTx.modify(descendantIt, update_ancestor_state(0, nFeeDelta, 0, 0)); + mapTx.modify(descendantIt, [=](CTxMemPoolEntry& e){ e.UpdateAncestorState(0, nFeeDelta, 0, 0); }); } ++nTransactionsUpdated; } diff --git a/src/txmempool.h b/src/txmempool.h index d06816ba97..cd15d069b1 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -35,7 +35,7 @@ class CBlockIndex; class CChain; -class CChainState; +class Chainstate; extern RecursiveMutex cs_main; /** Fake height value used in Coin to signify they are only in the memory pool (since 0.8) */ diff --git a/src/uint256.h b/src/uint256.h index 5c3a2f5409..e74b9ff7b1 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_UINT256_H #define BITCOIN_UINT256_H +#include <crypto/common.h> #include <span.h> #include <assert.h> @@ -84,15 +85,7 @@ public: uint64_t GetUint64(int pos) const { - const uint8_t* ptr = m_data + pos * 8; - return ((uint64_t)ptr[0]) | \ - ((uint64_t)ptr[1]) << 8 | \ - ((uint64_t)ptr[2]) << 16 | \ - ((uint64_t)ptr[3]) << 24 | \ - ((uint64_t)ptr[4]) << 32 | \ - ((uint64_t)ptr[5]) << 40 | \ - ((uint64_t)ptr[6]) << 48 | \ - ((uint64_t)ptr[7]) << 56; + return ReadLE64(m_data + pos * 8); } template<typename Stream> diff --git a/src/util/system.cpp b/src/util/system.cpp index 1953a9f836..c3c6cbfef6 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -831,7 +831,7 @@ std::string HelpMessageOpt(const std::string &option, const std::string &message std::string("\n\n"); } -static std::string FormatException(const std::exception* pex, const char* pszThread) +static std::string FormatException(const std::exception* pex, std::string_view thread_name) { #ifdef WIN32 char pszModule[MAX_PATH] = ""; @@ -841,15 +841,15 @@ static std::string FormatException(const std::exception* pex, const char* pszThr #endif if (pex) return strprintf( - "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread); + "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, thread_name); else return strprintf( - "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); + "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, thread_name); } -void PrintExceptionContinue(const std::exception* pex, const char* pszThread) +void PrintExceptionContinue(const std::exception* pex, std::string_view thread_name) { - std::string message = FormatException(pex, pszThread); + std::string message = FormatException(pex, thread_name); LogPrintf("\n\n************************\n%s\n", message); tfm::format(std::cerr, "\n\n************************\n%s\n", message); } diff --git a/src/util/system.h b/src/util/system.h index 756e6642f2..c8e1de6700 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -51,7 +51,7 @@ bool error(const char* fmt, const Args&... args) return false; } -void PrintExceptionContinue(const std::exception *pex, const char* pszThread); +void PrintExceptionContinue(const std::exception* pex, std::string_view thread_name); /** * Ensure file contents are fully committed to disk, using a platform-specific diff --git a/src/util/thread.cpp b/src/util/thread.cpp index f9f427ba20..ae98abdb3d 100644 --- a/src/util/thread.cpp +++ b/src/util/thread.cpp @@ -10,10 +10,12 @@ #include <exception> #include <functional> +#include <string> +#include <utility> -void util::TraceThread(const char* thread_name, std::function<void()> thread_func) +void util::TraceThread(std::string_view thread_name, std::function<void()> thread_func) { - util::ThreadRename(thread_name); + util::ThreadRename(std::string{thread_name}); try { LogPrintf("%s thread start\n", thread_name); thread_func(); diff --git a/src/util/thread.h b/src/util/thread.h index ca2eccc0c3..b80bf046a0 100644 --- a/src/util/thread.h +++ b/src/util/thread.h @@ -6,12 +6,13 @@ #define BITCOIN_UTIL_THREAD_H #include <functional> +#include <string> namespace util { /** * A wrapper for do-something-once thread functions. */ -void TraceThread(const char* thread_name, std::function<void()> thread_func); +void TraceThread(std::string_view thread_name, std::function<void()> thread_func); } // namespace util diff --git a/src/validation.cpp b/src/validation.cpp index 3e17d4cd87..fb29ca3ae7 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -131,7 +131,7 @@ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; uint256 hashAssumeValid; arith_uint256 nMinimumChainWork; -const CBlockIndex* CChainState::FindForkInGlobalIndex(const CBlockLocator& locator) const +const CBlockIndex* Chainstate::FindForkInGlobalIndex(const CBlockLocator& locator) const { AssertLockHeld(cs_main); @@ -273,7 +273,7 @@ static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache) coins_cache.Uncache(removed); } -static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +static bool IsCurrentForFeeEstimation(Chainstate& active_chainstate) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); if (active_chainstate.IsInitialBlockDownload()) @@ -286,7 +286,7 @@ static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_ return true; } -void CChainState::MaybeUpdateMempoolForReorg( +void Chainstate::MaybeUpdateMempoolForReorg( DisconnectedBlockTransactions& disconnectpool, bool fAddToMempool) { @@ -424,7 +424,7 @@ namespace { class MemPoolAccept { public: - explicit MemPoolAccept(CTxMemPool& mempool, CChainState& active_chainstate) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&active_chainstate.CoinsTip(), m_pool), m_active_chainstate(active_chainstate), + explicit MemPoolAccept(CTxMemPool& mempool, Chainstate& active_chainstate) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&active_chainstate.CoinsTip(), m_pool), m_active_chainstate(active_chainstate), m_limit_ancestors(m_pool.m_limits.ancestor_count), m_limit_ancestor_size(m_pool.m_limits.ancestor_size_vbytes), m_limit_descendants(m_pool.m_limits.descendant_count), @@ -658,7 +658,7 @@ private: CCoinsViewMemPool m_viewmempool; CCoinsView m_dummy; - CChainState& m_active_chainstate; + Chainstate& m_active_chainstate; // The package limits in effect at the time of invocation. const size_t m_limit_ancestors; @@ -1411,7 +1411,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package& package, } // anon namespace -MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTransactionRef& tx, +MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTransactionRef& tx, int64_t accept_time, bool bypass_limits, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { @@ -1438,7 +1438,7 @@ MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTr return result; } -PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTxMemPool& pool, +PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxMemPool& pool, const Package& package, bool test_accept) { AssertLockHeld(cs_main); @@ -1497,7 +1497,7 @@ void CoinsViews::InitCache() m_cacheview = std::make_unique<CCoinsViewCache>(&m_catcherview); } -CChainState::CChainState( +Chainstate::Chainstate( CTxMemPool* mempool, BlockManager& blockman, ChainstateManager& chainman, @@ -1508,7 +1508,7 @@ CChainState::CChainState( m_chainman(chainman), m_from_snapshot_blockhash(from_snapshot_blockhash) {} -void CChainState::InitCoinsDB( +void Chainstate::InitCoinsDB( size_t cache_size_bytes, bool in_memory, bool should_wipe, @@ -1522,7 +1522,7 @@ void CChainState::InitCoinsDB( leveldb_name, cache_size_bytes, in_memory, should_wipe); } -void CChainState::InitCoinsCache(size_t cache_size_bytes) +void Chainstate::InitCoinsCache(size_t cache_size_bytes) { AssertLockHeld(::cs_main); assert(m_coins_views != nullptr); @@ -1532,10 +1532,10 @@ void CChainState::InitCoinsCache(size_t cache_size_bytes) // Note that though this is marked const, we may end up modifying `m_cached_finished_ibd`, which // is a performance-related implementation detail. This function must be marked -// `const` so that `CValidationInterface` clients (which are given a `const CChainState*`) +// `const` so that `CValidationInterface` clients (which are given a `const Chainstate*`) // can call it. // -bool CChainState::IsInitialBlockDownload() const +bool Chainstate::IsInitialBlockDownload() const { // Optimization: pre-test latch before taking the lock. if (m_cached_finished_ibd.load(std::memory_order_relaxed)) @@ -1577,7 +1577,7 @@ static void AlertNotify(const std::string& strMessage) #endif } -void CChainState::CheckForkWarningConditions() +void Chainstate::CheckForkWarningConditions() { AssertLockHeld(cs_main); @@ -1596,7 +1596,7 @@ void CChainState::CheckForkWarningConditions() } // Called both upon regular invalid block discovery *and* InvalidateBlock -void CChainState::InvalidChainFound(CBlockIndex* pindexNew) +void Chainstate::InvalidChainFound(CBlockIndex* pindexNew) { AssertLockHeld(cs_main); if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) { @@ -1619,7 +1619,7 @@ void CChainState::InvalidChainFound(CBlockIndex* pindexNew) // Same as InvalidChainFound, above, except not called directly from InvalidateBlock, // which does its own setBlockIndexCandidates management. -void CChainState::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) +void Chainstate::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) { AssertLockHeld(cs_main); if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { @@ -1824,7 +1824,7 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out) /** Undo the effects of this block (with given index) on the UTXO set represented by coins. * When FAILED is returned, view is left in an indeterminate state. */ -DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) +DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) { AssertLockHeld(::cs_main); bool fClean = true; @@ -1977,7 +1977,7 @@ static int64_t nBlocksTotal = 0; /** Apply the effects of this block (with given index) on the UTXO set represented by coins. * Validity checks that depend on the UTXO set are also done; ConnectBlock() * can fail if those validity checks fail (among other reasons). */ -bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, +bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) { AssertLockHeld(cs_main); @@ -2289,7 +2289,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, return true; } -CoinsCacheSizeState CChainState::GetCoinsCacheSizeState() +CoinsCacheSizeState Chainstate::GetCoinsCacheSizeState() { AssertLockHeld(::cs_main); return this->GetCoinsCacheSizeState( @@ -2297,7 +2297,7 @@ CoinsCacheSizeState CChainState::GetCoinsCacheSizeState() m_mempool ? m_mempool->m_max_size_bytes : 0); } -CoinsCacheSizeState CChainState::GetCoinsCacheSizeState( +CoinsCacheSizeState Chainstate::GetCoinsCacheSizeState( size_t max_coins_cache_size_bytes, size_t max_mempool_size_bytes) { @@ -2321,7 +2321,7 @@ CoinsCacheSizeState CChainState::GetCoinsCacheSizeState( return CoinsCacheSizeState::OK; } -bool CChainState::FlushStateToDisk( +bool Chainstate::FlushStateToDisk( BlockValidationState &state, FlushStateMode mode, int nManualPruneHeight) @@ -2464,7 +2464,7 @@ bool CChainState::FlushStateToDisk( return true; } -void CChainState::ForceFlushStateToDisk() +void Chainstate::ForceFlushStateToDisk() { BlockValidationState state; if (!this->FlushStateToDisk(state, FlushStateMode::ALWAYS)) { @@ -2472,7 +2472,7 @@ void CChainState::ForceFlushStateToDisk() } } -void CChainState::PruneAndFlush() +void Chainstate::PruneAndFlush() { BlockValidationState state; m_blockman.m_check_for_pruning = true; @@ -2519,7 +2519,7 @@ static void UpdateTipLog( !warning_messages.empty() ? strprintf(" warning='%s'", warning_messages) : ""); } -void CChainState::UpdateTip(const CBlockIndex* pindexNew) +void Chainstate::UpdateTip(const CBlockIndex* pindexNew) { AssertLockHeld(::cs_main); const auto& coins_tip = this->CoinsTip(); @@ -2575,7 +2575,7 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew) * disconnectpool (note that the caller is responsible for mempool consistency * in any case). */ -bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTransactions* disconnectpool) +bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTransactions* disconnectpool) { AssertLockHeld(cs_main); if (m_mempool) AssertLockHeld(m_mempool->cs); @@ -2691,7 +2691,7 @@ public: * * The block is added to connectTrace if connection succeeds. */ -bool CChainState::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) +bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) { AssertLockHeld(cs_main); if (m_mempool) AssertLockHeld(m_mempool->cs); @@ -2759,7 +2759,7 @@ 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* Chainstate::FindMostWorkChain() { AssertLockHeld(::cs_main); do { @@ -2818,7 +2818,7 @@ CBlockIndex* CChainState::FindMostWorkChain() } /** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */ -void CChainState::PruneBlockIndexCandidates() { +void Chainstate::PruneBlockIndexCandidates() { // Note that we can't delete the current block itself, as we may need to return to it later in case a // reorganization to a better block fails. std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin(); @@ -2835,7 +2835,7 @@ void CChainState::PruneBlockIndexCandidates() { * * @returns true unless a system error occurred */ -bool CChainState::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) +bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) { AssertLockHeld(cs_main); if (m_mempool) AssertLockHeld(m_mempool->cs); @@ -2927,7 +2927,7 @@ static SynchronizationState GetSynchronizationState(bool init) return SynchronizationState::INIT_DOWNLOAD; } -static bool NotifyHeaderTip(CChainState& chainstate) LOCKS_EXCLUDED(cs_main) { +static bool NotifyHeaderTip(Chainstate& chainstate) LOCKS_EXCLUDED(cs_main) { bool fNotify = false; bool fInitialBlockDownload = false; static CBlockIndex* pindexHeaderOld = nullptr; @@ -2957,7 +2957,7 @@ static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) { } } -bool CChainState::ActivateBestChain(BlockValidationState& state, std::shared_ptr<const CBlock> pblock) +bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<const CBlock> pblock) { AssertLockNotHeld(m_chainstate_mutex); @@ -3059,7 +3059,7 @@ bool CChainState::ActivateBestChain(BlockValidationState& state, std::shared_ptr return true; } -bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) +bool Chainstate::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) { AssertLockNotHeld(m_chainstate_mutex); AssertLockNotHeld(::cs_main); @@ -3090,7 +3090,7 @@ bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex return ActivateBestChain(state, std::shared_ptr<const CBlock>()); } -bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex) +bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pindex) { AssertLockNotHeld(m_chainstate_mutex); AssertLockNotHeld(::cs_main); @@ -3233,7 +3233,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind return true; } -void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { +void Chainstate::ResetBlockFailureFlags(CBlockIndex *pindex) { AssertLockHeld(cs_main); int nHeight = pindex->nHeight; @@ -3266,7 +3266,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { } /** 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) +void Chainstate::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos) { AssertLockHeld(cs_main); pindexNew->nTx = block.vtx.size(); @@ -3737,7 +3737,7 @@ void ChainstateManager::ReportHeadersPresync(const arith_uint256& work, int64_t } /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ -bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock, bool min_pow_checked) +bool Chainstate::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock, bool min_pow_checked) { const CBlock& block = *pblock; @@ -3862,7 +3862,7 @@ bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& blo MempoolAcceptResult ChainstateManager::ProcessTransaction(const CTransactionRef& tx, bool test_accept) { AssertLockHeld(cs_main); - CChainState& active_chainstate = ActiveChainstate(); + Chainstate& active_chainstate = ActiveChainstate(); if (!active_chainstate.GetMempool()) { TxValidationState state; state.Invalid(TxValidationResult::TX_NO_MEMPOOL, "no-mempool"); @@ -3875,7 +3875,7 @@ MempoolAcceptResult ChainstateManager::ProcessTransaction(const CTransactionRef& bool TestBlockValidity(BlockValidationState& state, const CChainParams& chainparams, - CChainState& chainstate, + Chainstate& chainstate, const CBlock& block, CBlockIndex* pindexPrev, const std::function<NodeClock::time_point()>& adjusted_time_callback, @@ -3907,7 +3907,7 @@ bool TestBlockValidity(BlockValidationState& state, } /* This function is called from the RPC code for pruneblockchain */ -void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight) +void PruneBlockFilesManual(Chainstate& active_chainstate, int nManualPruneHeight) { BlockValidationState state; if (!active_chainstate.FlushStateToDisk( @@ -3916,14 +3916,14 @@ void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeigh } } -void CChainState::LoadMempool(const fs::path& load_path, FopenFn mockable_fopen_function) +void Chainstate::LoadMempool(const fs::path& load_path, FopenFn mockable_fopen_function) { if (!m_mempool) return; ::LoadMempool(*m_mempool, load_path, *this, mockable_fopen_function); m_mempool->SetLoadTried(!ShutdownRequested()); } -bool CChainState::LoadChainTip() +bool Chainstate::LoadChainTip() { AssertLockHeld(cs_main); const CCoinsViewCache& coins_cache = CoinsTip(); @@ -3962,7 +3962,7 @@ CVerifyDB::~CVerifyDB() } bool CVerifyDB::VerifyDB( - CChainState& chainstate, + Chainstate& chainstate, const Consensus::Params& consensus_params, CCoinsView& coinsview, int nCheckLevel, int nCheckDepth) @@ -4078,7 +4078,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) +bool Chainstate::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs) { AssertLockHeld(cs_main); // TODO: merge with ConnectBlock @@ -4099,7 +4099,7 @@ bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& i return true; } -bool CChainState::ReplayBlocks() +bool Chainstate::ReplayBlocks() { LOCK(cs_main); @@ -4167,7 +4167,7 @@ bool CChainState::ReplayBlocks() return true; } -bool CChainState::NeedsRedownload() const +bool Chainstate::NeedsRedownload() const { AssertLockHeld(cs_main); @@ -4185,7 +4185,7 @@ bool CChainState::NeedsRedownload() const return false; } -void CChainState::UnloadBlockIndex() +void Chainstate::UnloadBlockIndex() { AssertLockHeld(::cs_main); nBlockSequenceId = 1; @@ -4254,7 +4254,7 @@ bool ChainstateManager::LoadBlockIndex() // 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 : GetAll()) { + for (Chainstate* chainstate : GetAll()) { if (chainstate->reliesOnAssumedValid() || pindex->nHeight < first_assumed_valid_height) { chainstate->setBlockIndexCandidates.insert(pindex); @@ -4283,7 +4283,7 @@ bool ChainstateManager::LoadBlockIndex() return true; } -bool CChainState::LoadGenesisBlock() +bool Chainstate::LoadGenesisBlock() { LOCK(cs_main); @@ -4309,7 +4309,7 @@ bool CChainState::LoadGenesisBlock() return true; } -void CChainState::LoadExternalBlockFile( +void Chainstate::LoadExternalBlockFile( FILE* fileIn, FlatFilePos* dbp, std::multimap<uint256, FlatFilePos>* blocks_with_unknown_parent) @@ -4319,7 +4319,7 @@ void CChainState::LoadExternalBlockFile( // Either both should be specified (-reindex), or neither (-loadblock). assert(!dbp == !blocks_with_unknown_parent); - int64_t nStart = GetTimeMillis(); + const auto start{SteadyClock::now()}; int nLoaded = 0; try { @@ -4433,10 +4433,10 @@ void CChainState::LoadExternalBlockFile( } catch (const std::runtime_error& e) { AbortNode(std::string("System error: ") + e.what()); } - LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart); + LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); } -void CChainState::CheckBlockIndex() +void Chainstate::CheckBlockIndex() { if (!fCheckBlockIndex) { return; @@ -4658,7 +4658,7 @@ void CChainState::CheckBlockIndex() assert(nNodes == forward.size()); } -std::string CChainState::ToString() +std::string Chainstate::ToString() { AssertLockHeld(::cs_main); CBlockIndex* tip = m_chain.Tip(); @@ -4667,7 +4667,7 @@ std::string CChainState::ToString() tip ? tip->nHeight : -1, tip ? tip->GetBlockHash().ToString() : "null"); } -bool CChainState::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size) +bool Chainstate::ResizeCoinsCaches(size_t coinstip_size, size_t coinsdb_size) { AssertLockHeld(::cs_main); if (coinstip_size == m_coinstip_cache_size_bytes && @@ -4728,10 +4728,10 @@ std::optional<uint256> ChainstateManager::SnapshotBlockhash() const return std::nullopt; } -std::vector<CChainState*> ChainstateManager::GetAll() +std::vector<Chainstate*> ChainstateManager::GetAll() { LOCK(::cs_main); - std::vector<CChainState*> out; + std::vector<Chainstate*> out; if (!IsSnapshotValidated() && m_ibd_chainstate) { out.push_back(m_ibd_chainstate.get()); @@ -4744,18 +4744,18 @@ std::vector<CChainState*> ChainstateManager::GetAll() return out; } -CChainState& ChainstateManager::InitializeChainstate( +Chainstate& 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 = + std::unique_ptr<Chainstate>& to_modify = is_snapshot ? m_snapshot_chainstate : m_ibd_chainstate; if (to_modify) { throw std::logic_error("should not be overwriting a chainstate"); } - to_modify.reset(new CChainState(mempool, m_blockman, *this, snapshot_blockhash)); + to_modify.reset(new Chainstate(mempool, m_blockman, *this, snapshot_blockhash)); // Snapshot chainstates and initial IBD chaintates always become active. if (is_snapshot || (!is_snapshot && !m_active_chainstate)) { @@ -4825,7 +4825,7 @@ bool ChainstateManager::ActivateSnapshot( } auto snapshot_chainstate = WITH_LOCK(::cs_main, - return std::make_unique<CChainState>( + return std::make_unique<Chainstate>( /*mempool=*/nullptr, m_blockman, *this, base_blockhash)); { @@ -4875,7 +4875,7 @@ static void FlushSnapshotToDisk(CCoinsViewCache& coins_cache, bool snapshot_load } bool ChainstateManager::PopulateAndValidateSnapshot( - CChainState& snapshot_chainstate, + Chainstate& snapshot_chainstate, AutoFile& coins_file, const SnapshotMetadata& metadata) { @@ -4969,7 +4969,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( // Important that we set this. This and the coins_cache accesses above are // sort of a layer violation, but either we reach into the innards of - // CCoinsViewCache here or we have to invert some of the CChainState to + // CCoinsViewCache here or we have to invert some of the Chainstate to // embed them in a snapshot-activation-specific CCoinsViewCache bulk load // method. coins_cache.SetBestBlock(base_blockhash); @@ -5048,7 +5048,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( index->nStatus |= BLOCK_ASSUMED_VALID; } - // Fake BLOCK_OPT_WITNESS so that CChainState::NeedsRedownload() + // Fake BLOCK_OPT_WITNESS so that Chainstate::NeedsRedownload() // won't ask to rewind the entire assumed-valid chain on startup. if (DeploymentActiveAt(*index, *this, Consensus::DEPLOYMENT_SEGWIT)) { index->nStatus |= BLOCK_OPT_WITNESS; @@ -5071,7 +5071,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot( return true; } -CChainState& ChainstateManager::ActiveChainstate() const +Chainstate& ChainstateManager::ActiveChainstate() const { LOCK(::cs_main); assert(m_active_chainstate); diff --git a/src/validation.h b/src/validation.h index 7f5039aaea..9ba206855f 100644 --- a/src/validation.h +++ b/src/validation.h @@ -43,7 +43,7 @@ #include <utility> #include <vector> -class CChainState; +class Chainstate; class CBlockTreeDB; class CTxMemPool; class ChainstateManager; @@ -127,7 +127,7 @@ bool AbortNode(BlockValidationState& state, const std::string& strMessage, const double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex* pindex); /** Prune block files up to a given height */ -void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight); +void PruneBlockFilesManual(Chainstate& active_chainstate, int nManualPruneHeight); /** * Validation result for a single transaction mempool acceptance. @@ -240,7 +240,7 @@ struct PackageMempoolAcceptResult * * @returns a MempoolAcceptResult indicating whether the transaction was accepted/rejected with reason. */ -MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTransactionRef& tx, +MempoolAcceptResult AcceptToMemoryPool(Chainstate& active_chainstate, const CTransactionRef& tx, int64_t accept_time, bool bypass_limits, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -252,7 +252,7 @@ MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTr * If a transaction fails, validation will exit early and some results may be missing. It is also * possible for the package to be partially submitted. */ -PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTxMemPool& pool, +PackageMempoolAcceptResult ProcessNewPackage(Chainstate& active_chainstate, CTxMemPool& pool, const Package& txns, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -333,7 +333,7 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu /** Check a block is completely valid from start to finish (only works on top of our current best block) */ bool TestBlockValidity(BlockValidationState& state, const CChainParams& chainparams, - CChainState& chainstate, + Chainstate& chainstate, const CBlock& block, CBlockIndex* pindexPrev, const std::function<NodeClock::time_point()>& adjusted_time_callback, @@ -352,7 +352,7 @@ public: CVerifyDB(); ~CVerifyDB(); bool VerifyDB( - CChainState& chainstate, + Chainstate& chainstate, const Consensus::Params& consensus_params, CCoinsView& coinsview, int nCheckLevel, @@ -368,7 +368,7 @@ enum DisconnectResult class ConnectTrace; -/** @see CChainState::FlushStateToDisk */ +/** @see Chainstate::FlushStateToDisk */ enum class FlushStateMode { NONE, IF_NEEDED, @@ -421,7 +421,7 @@ enum class CoinsCacheSizeState }; /** - * CChainState stores and provides an API to update our local knowledge of the + * Chainstate stores and provides an API to update our local knowledge of the * current best chain. * * Eventually, the API here is targeted at being exposed externally as a @@ -434,7 +434,7 @@ enum class CoinsCacheSizeState * whereas block information and metadata independent of the current tip is * kept in `BlockManager`. */ -class CChainState +class Chainstate { protected: /** @@ -472,7 +472,7 @@ protected: public: //! Reference to a BlockManager instance which itself is shared across all - //! CChainState instances. + //! Chainstate instances. node::BlockManager& m_blockman; /** Chain parameters for this chainstate */ @@ -484,7 +484,7 @@ public: //! chainstate within deeply nested method calls. ChainstateManager& m_chainman; - explicit CChainState( + explicit Chainstate( CTxMemPool* mempool, node::BlockManager& blockman, ChainstateManager& chainman, @@ -814,7 +814,7 @@ private: //! This is especially important when, e.g., calling ActivateBestChain() //! on all chainstates because we are not able to hold ::cs_main going into //! that call. - std::unique_ptr<CChainState> m_ibd_chainstate GUARDED_BY(::cs_main); + std::unique_ptr<Chainstate> m_ibd_chainstate GUARDED_BY(::cs_main); //! A chainstate initialized on the basis of a UTXO snapshot. If this is //! non-null, it is always our active chainstate. @@ -825,7 +825,7 @@ private: //! This is especially important when, e.g., calling ActivateBestChain() //! on all chainstates because we are not able to hold ::cs_main going into //! that call. - std::unique_ptr<CChainState> m_snapshot_chainstate GUARDED_BY(::cs_main); + std::unique_ptr<Chainstate> m_snapshot_chainstate GUARDED_BY(::cs_main); //! Points to either the ibd or snapshot chainstate; indicates our //! most-work chain. @@ -836,7 +836,7 @@ private: //! This is especially important when, e.g., calling ActivateBestChain() //! on all chainstates because we are not able to hold ::cs_main going into //! that call. - CChainState* m_active_chainstate GUARDED_BY(::cs_main) {nullptr}; + Chainstate* m_active_chainstate GUARDED_BY(::cs_main) {nullptr}; //! If true, the assumed-valid chainstate has been fully validated //! by the background validation chainstate. @@ -846,7 +846,7 @@ private: //! Internal helper for ActivateSnapshot(). [[nodiscard]] bool PopulateAndValidateSnapshot( - CChainState& snapshot_chainstate, + Chainstate& snapshot_chainstate, AutoFile& coins_file, const node::SnapshotMetadata& metadata); @@ -862,7 +862,7 @@ private: BlockValidationState& state, CBlockIndex** ppindex, bool min_pow_checked) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - friend CChainState; + friend Chainstate; /** Most recent headers presync progress update, for rate-limiting. */ std::chrono::time_point<std::chrono::steady_clock> m_last_presync_update GUARDED_BY(::cs_main) {}; @@ -936,19 +936,19 @@ public: // constructor //! @param[in] snapshot_blockhash If given, signify that this chainstate //! is based on a snapshot. - CChainState& InitializeChainstate( + Chainstate& InitializeChainstate( CTxMemPool* mempool, const std::optional<uint256>& snapshot_blockhash = std::nullopt) LIFETIMEBOUND EXCLUSIVE_LOCKS_REQUIRED(::cs_main); //! Get all chainstates currently being used. - std::vector<CChainState*> GetAll(); + std::vector<Chainstate*> GetAll(); //! Construct and activate a Chainstate on the basis of UTXO snapshot data. //! //! Steps: //! - //! - Initialize an unused CChainState. + //! - Initialize an unused Chainstate. //! - Load its `CoinsViews` contents from `coins_file`. //! - Verify that the hash of the resulting coinsdb matches the expected hash //! per assumeutxo chain parameters. @@ -961,7 +961,7 @@ public: AutoFile& coins_file, const node::SnapshotMetadata& metadata, bool in_memory); //! The most-work chain. - CChainState& ActiveChainstate() const; + Chainstate& ActiveChainstate() const; CChain& ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChainstate().m_chain; } int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Height(); } CBlockIndex* ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { return ActiveChain().Tip(); } diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index deb1293cd4..3a9d277f65 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -533,7 +533,7 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip) void BerkeleyEnvironment::Flush(bool fShutdown) { - int64_t nStart = GetTimeMillis(); + const auto start{SteadyClock::now()}; // Flush log data to the actual data file on all files that are not in use LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: [%s] Flush(%s)%s\n", strPath, fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started"); if (!fDbEnvInit) @@ -561,7 +561,7 @@ void BerkeleyEnvironment::Flush(bool fShutdown) no_dbs_accessed = false; } } - LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart); + LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); if (fShutdown) { char** listp; if (no_dbs_accessed) { @@ -591,14 +591,14 @@ bool BerkeleyDatabase::PeriodicFlush() const std::string strFile = fs::PathToString(m_filename); LogPrint(BCLog::WALLETDB, "Flushing %s\n", strFile); - int64_t nStart = GetTimeMillis(); + const auto start{SteadyClock::now()}; // Flush wallet file so it's self contained env->CloseDb(m_filename); env->CheckpointLSN(strFile); m_refcount = -1; - LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); + LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); return true; } diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 98925e6b10..9cf2b677e6 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -560,8 +560,12 @@ public: options.create_flags = wallet_creation_flags; options.create_passphrase = passphrase; bilingual_str error; - util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, CreateWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))}; - return wallet ? std::move(wallet) : util::Error{error}; + std::unique_ptr<Wallet> wallet{MakeWallet(m_context, CreateWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))}; + if (wallet) { + return {std::move(wallet)}; + } else { + return util::Error{error}; + } } util::Result<std::unique_ptr<Wallet>> loadWallet(const std::string& name, std::vector<bilingual_str>& warnings) override { @@ -570,15 +574,23 @@ public: ReadDatabaseArgs(*m_context.args, options); options.require_existing = true; bilingual_str error; - util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, LoadWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))}; - return wallet ? std::move(wallet) : util::Error{error}; + std::unique_ptr<Wallet> wallet{MakeWallet(m_context, LoadWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))}; + if (wallet) { + return {std::move(wallet)}; + } else { + return util::Error{error}; + } } util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) override { DatabaseStatus status; bilingual_str error; - util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))}; - return wallet ? std::move(wallet) : util::Error{error}; + std::unique_ptr<Wallet> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))}; + if (wallet) { + return {std::move(wallet)}; + } else { + return util::Error{error}; + } } std::string getWalletDir() override { diff --git a/src/wallet/rpc/backup.cpp b/src/wallet/rpc/backup.cpp index 4c623fa1ba..35df151e84 100644 --- a/src/wallet/rpc/backup.cpp +++ b/src/wallet/rpc/backup.cpp @@ -295,7 +295,7 @@ RPCHelpMan importaddress() RescanWallet(*pwallet, reserver); { LOCK(pwallet->cs_wallet); - pwallet->ReacceptWalletTransactions(); + pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true); } } @@ -476,7 +476,7 @@ RPCHelpMan importpubkey() RescanWallet(*pwallet, reserver); { LOCK(pwallet->cs_wallet); - pwallet->ReacceptWalletTransactions(); + pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true); } } @@ -1397,7 +1397,7 @@ RPCHelpMan importmulti() int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */); { LOCK(pwallet->cs_wallet); - pwallet->ReacceptWalletTransactions(); + pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true); } if (pwallet->IsAbortingRescan()) { @@ -1691,7 +1691,7 @@ RPCHelpMan importdescriptors() int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver, true /* update */); { LOCK(pwallet->cs_wallet); - pwallet->ReacceptWalletTransactions(); + pwallet->ResubmitWalletTransactions(/*relay=*/false, /*force=*/true); } if (pwallet->IsAbortingRescan()) { diff --git a/src/wallet/rpc/spend.cpp b/src/wallet/rpc/spend.cpp index 18136c8e25..e38b13624c 100644 --- a/src/wallet/rpc/spend.cpp +++ b/src/wallet/rpc/spend.cpp @@ -1137,7 +1137,7 @@ RPCHelpMan send() {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", Cat<std::vector<RPCArg>>( { - {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."}, + {"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"},"Automatically include coins from the wallet to cover the target amount.\n"}, {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n" "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n" "If that happens, you will need to fund the transaction with different inputs and republish it."}, @@ -1264,11 +1264,15 @@ RPCHelpMan sendall() {"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch-only.\n" "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n" "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."}, - {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with send_max. A JSON array of JSON objects", + {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Use exactly the specified inputs to build the transaction. Specifying inputs is incompatible with send_max.", { - {"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"}, + {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", + { + {"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 'replaceable' and 'locktime' arguments"}, "The sequence number"}, + }, + }, }, }, {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, @@ -1398,6 +1402,10 @@ RPCHelpMan sendall() const CAmount fee_from_size{fee_rate.GetFee(tx_size.vsize)}; const CAmount effective_value{total_input_value - fee_from_size}; + if (fee_from_size > pwallet->m_default_max_tx_fee) { + throw JSONRPCError(RPC_WALLET_ERROR, TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED).original); + } + if (effective_value <= 0) { if (send_max) { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Total value of UTXO pool too low to pay for transaction, try using lower feerate."); @@ -1406,6 +1414,11 @@ RPCHelpMan sendall() } } + // If this transaction is too large, e.g. because the wallet has many UTXOs, it will be rejected by the node's mempool. + if (tx_size.weight > MAX_STANDARD_TX_WEIGHT) { + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction too large."); + } + CAmount output_amounts_claimed{0}; for (const CTxOut& out : rawTx.vout) { output_amounts_claimed += out.nValue; @@ -1578,7 +1591,7 @@ RPCHelpMan walletcreatefundedpsbt() {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", Cat<std::vector<RPCArg>>( { - {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."}, + {"add_inputs", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false when \"inputs\" are specified, true otherwise"}, "Automatically include coins from the wallet to cover the target amount.\n"}, {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n" "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n" "If that happens, you will need to fund the transaction with different inputs and republish it."}, diff --git a/src/wallet/test/walletload_tests.cpp b/src/wallet/test/walletload_tests.cpp new file mode 100644 index 0000000000..f45b69a418 --- /dev/null +++ b/src/wallet/test/walletload_tests.cpp @@ -0,0 +1,54 @@ +// Copyright (c) 2022 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php. + +#include <wallet/wallet.h> +#include <test/util/setup_common.h> + +#include <boost/test/unit_test.hpp> + +namespace wallet { + +BOOST_AUTO_TEST_SUITE(walletload_tests) + +class DummyDescriptor final : public Descriptor { +private: + std::string desc; +public: + explicit DummyDescriptor(const std::string& descriptor) : desc(descriptor) {}; + ~DummyDescriptor() = default; + + std::string ToString() const override { return desc; } + std::optional<OutputType> GetOutputType() const override { return OutputType::UNKNOWN; } + + bool IsRange() const override { return false; } + bool IsSolvable() const override { return false; } + bool IsSingleType() const override { return true; } + bool ToPrivateString(const SigningProvider& provider, std::string& out) const override { return false; } + bool ToNormalizedString(const SigningProvider& provider, std::string& out, const DescriptorCache* cache = nullptr) const override { return false; } + bool Expand(int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache = nullptr) const override { return false; }; + bool ExpandFromCache(int pos, const DescriptorCache& read_cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override { return false; } + void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const override {} +}; + +BOOST_FIXTURE_TEST_CASE(wallet_load_unknown_descriptor, TestingSetup) +{ + std::unique_ptr<WalletDatabase> database = CreateMockWalletDatabase(); + { + // Write unknown active descriptor + WalletBatch batch(*database, false); + std::string unknown_desc = "trx(tpubD6NzVbkrYhZ4Y4S7m6Y5s9GD8FqEMBy56AGphZXuagajudVZEnYyBahZMgHNCTJc2at82YX6s8JiL1Lohu5A3v1Ur76qguNH4QVQ7qYrBQx/86'/1'/0'/0/*)#8pn8tzdt"; + WalletDescriptor wallet_descriptor(std::make_shared<DummyDescriptor>(unknown_desc), 0, 0, 0, 0); + BOOST_CHECK(batch.WriteDescriptor(uint256(), wallet_descriptor)); + BOOST_CHECK(batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(OutputType::UNKNOWN), uint256(), false)); + } + + { + // Now try to load the wallet and verify the error. + const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", m_args, std::move(database))); + BOOST_CHECK_EQUAL(wallet->LoadWallet(), DBErrors::UNKNOWN_DESCRIPTOR); + } +} + +BOOST_AUTO_TEST_SUITE_END() +} // namespace wallet diff --git a/src/wallet/transaction.h b/src/wallet/transaction.h index 271d698e56..27983e356d 100644 --- a/src/wallet/transaction.h +++ b/src/wallet/transaction.h @@ -305,6 +305,13 @@ public: CWalletTx(CWalletTx const &) = delete; void operator=(CWalletTx const &x) = delete; }; + +struct WalletTxOrderComparator { + bool operator()(const CWalletTx* a, const CWalletTx* b) const + { + return a->nOrderPos < b->nOrderPos; + } +}; } // namespace wallet #endif // BITCOIN_WALLET_TRANSACTION_H diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index b25488f6a1..009c539a65 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -386,25 +386,31 @@ std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& b ReadDatabaseArgs(*context.args, options); options.require_existing = true; - if (!fs::exists(backup_file)) { - error = Untranslated("Backup file does not exist"); - status = DatabaseStatus::FAILED_INVALID_BACKUP_FILE; - return nullptr; - } - const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name)); + auto wallet_file = wallet_path / "wallet.dat"; + std::shared_ptr<CWallet> wallet; - if (fs::exists(wallet_path) || !TryCreateDirectories(wallet_path)) { - error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(wallet_path))); - status = DatabaseStatus::FAILED_ALREADY_EXISTS; - return nullptr; - } + try { + if (!fs::exists(backup_file)) { + error = Untranslated("Backup file does not exist"); + status = DatabaseStatus::FAILED_INVALID_BACKUP_FILE; + return nullptr; + } - auto wallet_file = wallet_path / "wallet.dat"; - fs::copy_file(backup_file, wallet_file, fs::copy_options::none); + if (fs::exists(wallet_path) || !TryCreateDirectories(wallet_path)) { + error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(wallet_path))); + status = DatabaseStatus::FAILED_ALREADY_EXISTS; + return nullptr; + } - auto wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings); + fs::copy_file(backup_file, wallet_file, fs::copy_options::none); + wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings); + } catch (const std::exception& e) { + assert(!wallet); + if (!error.empty()) error += Untranslated("\n"); + error += strprintf(Untranslated("Unexpected exception: %s"), e.what()); + } if (!wallet) { fs::remove(wallet_file); fs::remove(wallet_path); @@ -882,7 +888,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash) wtx.mapValue["replaced_by_txid"] = newHash.ToString(); - // Refresh mempool status without waiting for transactionRemovedFromMempool + // Refresh mempool status without waiting for transactionRemovedFromMempool or transactionAddedToMempool RefreshMempoolStatus(wtx, chain()); WalletBatch batch(GetDatabase()); @@ -1857,34 +1863,6 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc return result; } -void CWallet::ReacceptWalletTransactions() -{ - // If transactions aren't being broadcasted, don't let them into local mempool either - if (!fBroadcastTransactions) - return; - std::map<int64_t, CWalletTx*> mapSorted; - - // Sort pending wallet transactions based on their initial wallet insertion order - for (std::pair<const uint256, CWalletTx>& item : mapWallet) { - const uint256& wtxid = item.first; - CWalletTx& wtx = item.second; - assert(wtx.GetHash() == wtxid); - - int nDepth = GetTxDepthInMainChain(wtx); - - if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) { - mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); - } - } - - // Try to add wallet transactions to memory pool - for (const std::pair<const int64_t, CWalletTx*>& item : mapSorted) { - CWalletTx& wtx = *(item.second); - std::string unused_err_string; - SubmitTxMemoryPoolAndRelay(wtx, unused_err_string, false); - } -} - bool CWallet::SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, bool relay) const { AssertLockHeld(cs_wallet); @@ -1925,43 +1903,69 @@ std::set<uint256> CWallet::GetTxConflicts(const CWalletTx& wtx) const return result; } -// Rebroadcast transactions from the wallet. We do this on a random timer -// to slightly obfuscate which transactions come from our wallet. +// Resubmit transactions from the wallet to the mempool, optionally asking the +// mempool to relay them. On startup, we will do this for all unconfirmed +// transactions but will not ask the mempool to relay them. We do this on startup +// to ensure that our own mempool is aware of our transactions, and to also +// initialize m_next_resend so that the actual rebroadcast is scheduled. There +// is a privacy side effect here as not broadcasting on startup also means that we won't +// inform the world of our wallet's state, particularly if the wallet (or node) is not +// yet synced. // -// Ideally, we'd only resend transactions that we think should have been +// Otherwise this function is called periodically in order to relay our unconfirmed txs. +// We do this on a random timer to slightly obfuscate which transactions +// come from our wallet. +// +// TODO: Ideally, we'd only resend transactions that we think should have been // mined in the most recent block. Any transaction that wasn't in the top // blockweight of transactions in the mempool shouldn't have been mined, // and so is probably just sitting in the mempool waiting to be confirmed. // Rebroadcasting does nothing to speed up confirmation and only damages // privacy. -void CWallet::ResendWalletTransactions() +// +// The `force` option results in all unconfirmed transactions being submitted to +// the mempool. This does not necessarily result in those transactions being relayed, +// that depends on the `relay` option. Periodic rebroadcast uses the pattern +// relay=true force=false, while loading into the mempool +// (on start, or after import) uses relay=false force=true. +void CWallet::ResubmitWalletTransactions(bool relay, bool force) { + // Don't attempt to resubmit if the wallet is configured to not broadcast, + // even if forcing. + if (!fBroadcastTransactions) return; + // During reindex, importing and IBD, old wallet transactions become // unconfirmed. Don't resend them as that would spam other nodes. - if (!chain().isReadyToBroadcast()) return; + // We only allow forcing mempool submission when not relaying to avoid this spam. + if (!force && relay && !chain().isReadyToBroadcast()) return; // Do this infrequently and randomly to avoid giving away // that these are our transactions. - if (GetTime() < nNextResend || !fBroadcastTransactions) return; - bool fFirst = (nNextResend == 0); + if (!force && GetTime() < m_next_resend) return; // resend 12-36 hours from now, ~1 day on average. - nNextResend = GetTime() + (12 * 60 * 60) + GetRand(24 * 60 * 60); - if (fFirst) return; + m_next_resend = GetTime() + (12 * 60 * 60) + GetRand(24 * 60 * 60); int submitted_tx_count = 0; { // cs_wallet scope LOCK(cs_wallet); - // Relay transactions - for (std::pair<const uint256, CWalletTx>& item : mapWallet) { - CWalletTx& wtx = item.second; - // Attempt to rebroadcast all txes more than 5 minutes older than - // the last block. SubmitTxMemoryPoolAndRelay() will not rebroadcast - // any confirmed or conflicting txs. - if (wtx.nTimeReceived > m_best_block_time - 5 * 60) continue; + // First filter for the transactions we want to rebroadcast. + // We use a set with WalletTxOrderComparator so that rebroadcasting occurs in insertion order + std::set<CWalletTx*, WalletTxOrderComparator> to_submit; + for (auto& [txid, wtx] : mapWallet) { + // Only rebroadcast unconfirmed txs + if (!wtx.isUnconfirmed()) continue; + + // attempt to rebroadcast all txes more than 5 minutes older than + // the last block, or all txs if forcing. + if (!force && wtx.nTimeReceived > m_best_block_time - 5 * 60) continue; + to_submit.insert(&wtx); + } + // Now try submitting the transactions to the memory pool and (optionally) relay them. + for (auto wtx : to_submit) { std::string unused_err_string; - if (SubmitTxMemoryPoolAndRelay(wtx, unused_err_string, true)) ++submitted_tx_count; + if (SubmitTxMemoryPoolAndRelay(*wtx, unused_err_string, relay)) ++submitted_tx_count; } } // cs_wallet @@ -1975,7 +1979,7 @@ void CWallet::ResendWalletTransactions() void MaybeResendWalletTxs(WalletContext& context) { for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) { - pwallet->ResendWalletTransactions(); + pwallet->ResubmitWalletTransactions(/*relay=*/true, /*force=*/false); } } @@ -2788,7 +2792,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri ArgsManager& args = *Assert(context.args); const std::string& walletFile = database->Filename(); - int64_t nStart = GetTimeMillis(); + const auto start{SteadyClock::now()}; // TODO: Can't use std::make_shared because we need a custom deleter but // should be possible to use std::allocate_shared. const std::shared_ptr<CWallet> walletInstance(new CWallet(chain, name, args, std::move(database)), ReleaseWallet); @@ -2821,8 +2825,12 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri warnings.push_back(strprintf(_("Error reading %s! Transaction data may be missing or incorrect." " Rescanning wallet."), walletFile)); rescan_required = true; - } - else { + } else if (nLoadWalletRet == DBErrors::UNKNOWN_DESCRIPTOR) { + error = strprintf(_("Unrecognized descriptor found. Loading wallet %s\n\n" + "The wallet might had been created on a newer version.\n" + "Please try running the latest software version.\n"), walletFile); + return nullptr; + } else { error = strprintf(_("Error loading %s"), walletFile); return nullptr; } @@ -3005,7 +3013,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri walletInstance->m_spend_zero_conf_change = args.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); walletInstance->m_signal_rbf = args.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF); - walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", GetTimeMillis() - nStart); + walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start)); // Try to top up keypool. No-op if the wallet is locked. walletInstance->TopUpKeyPool(); @@ -3191,7 +3199,7 @@ void CWallet::postInitProcess() // Add wallet transactions that aren't already in a block to mempool // Do this here as mempool requires genesis block to be loaded - ReacceptWalletTransactions(); + ResubmitWalletTransactions(/*relay=*/false, /*force=*/true); // Update wallet transactions with current mempool transactions. chain().requestMempoolTransactions(*this); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index dc148512f8..6a1b76505c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -250,7 +250,7 @@ private: int nWalletVersion GUARDED_BY(cs_wallet){FEATURE_BASE}; /** The next scheduled rebroadcast of wallet transactions. */ - int64_t nNextResend = 0; + std::atomic<int64_t> m_next_resend{}; /** Whether this wallet will submit newly created transactions to the node's mempool and * prompt rebroadcasts (see ResendWalletTransactions()). */ bool fBroadcastTransactions = false; @@ -537,8 +537,7 @@ public: }; ScanResult ScanForWalletTransactions(const uint256& start_block, int start_height, std::optional<int> max_height, const WalletRescanReserver& reserver, bool fUpdate, const bool save_progress); void transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override; - void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - void ResendWalletTransactions(); + void ResubmitWalletTransactions(bool relay, bool force); OutputType TransactionChangeType(const std::optional<OutputType>& change_type, const std::vector<CRecipient>& vecSend) const; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 30406a22f9..6a8f0d2481 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -314,6 +314,7 @@ public: std::map<std::pair<uint256, CKeyID>, std::pair<CPubKey, std::vector<unsigned char>>> m_descriptor_crypt_keys; std::map<uint160, CHDChain> m_hd_chains; bool tx_corrupt{false}; + bool descriptor_unknown{false}; CWalletScanState() = default; }; @@ -627,7 +628,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, uint256 id; ssKey >> id; WalletDescriptor desc; - ssValue >> desc; + try { + ssValue >> desc; + } catch (const std::ios_base::failure& e) { + strErr = e.what(); + wss.descriptor_unknown = true; + return false; + } if (wss.m_descriptor_caches.count(id) == 0) { wss.m_descriptor_caches[id] = DescriptorCache(); } @@ -767,6 +774,12 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) DBErrors result = DBErrors::LOAD_OK; LOCK(pwallet->cs_wallet); + + // Last client version to open this wallet + int last_client = CLIENT_VERSION; + bool has_last_client = m_batch->Read(DBKeys::VERSION, last_client); + pwallet->WalletLogPrintf("Wallet file version = %d, last client version = %d\n", pwallet->GetVersion(), last_client); + try { int nMinVersion = 0; if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) { @@ -832,6 +845,13 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) // Set tx_corrupt back to false so that the error is only printed once (per corrupt tx) wss.tx_corrupt = false; result = DBErrors::CORRUPT; + } else if (wss.descriptor_unknown) { + strErr = strprintf("Error: Unrecognized descriptor found in wallet %s. ", pwallet->GetName()); + strErr += (last_client > CLIENT_VERSION) ? "The wallet might had been created on a newer version. " : + "The database might be corrupted or the software version is not compatible with one of your wallet descriptors. "; + strErr += "Please try running the latest software version"; + pwallet->WalletLogPrintf("%s\n", strErr); + return DBErrors::UNKNOWN_DESCRIPTOR; } else { // Leave other errors alone, if we try to fix them we might make things worse. fNoncriticalErrors = true; // ... but do warn the user there is something wrong. @@ -884,11 +904,6 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) if (result != DBErrors::LOAD_OK) return result; - // Last client version to open this wallet - int last_client = CLIENT_VERSION; - bool has_last_client = m_batch->Read(DBKeys::VERSION, last_client); - pwallet->WalletLogPrintf("Wallet file version = %d, last client version = %d\n", pwallet->GetVersion(), last_client); - pwallet->WalletLogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total. Unknown wallet records: %u\n", wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys, wss.m_unknown_records); diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 6aa25fae03..da6efe534b 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -51,7 +51,8 @@ enum class DBErrors EXTERNAL_SIGNER_SUPPORT_REQUIRED, LOAD_FAIL, NEED_REWRITE, - NEED_RESCAN + NEED_RESCAN, + UNKNOWN_DESCRIPTOR }; namespace DBKeys { diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp index 26618735f6..b9b7019a3c 100644 --- a/src/zmq/zmqnotificationinterface.cpp +++ b/src/zmq/zmqnotificationinterface.cpp @@ -8,7 +8,7 @@ #include <zmq.h> -#include <validation.h> +#include <primitives/block.h> #include <util/system.h> CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(nullptr) diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp index 011336bf72..51c8ad515e 100644 --- a/src/zmq/zmqpublishnotifier.cpp +++ b/src/zmq/zmqpublishnotifier.cpp @@ -11,7 +11,6 @@ #include <rpc/server.h> #include <streams.h> #include <util/system.h> -#include <validation.h> // For cs_main #include <zmq/zmqutil.h> #include <zmq.h> |