From 2a4ef42d34edf6499e4185c2fc7c6fed8b071ae7 Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Fri, 19 Jun 2026 19:31:43 +0800 Subject: [PATCH 1/5] fuzz: share a single FakeNodeClock in the chainman-resetting fuzz targets cmpctblock, process_message, process_messages, and utxo_snapshot rebuild the chainman from a helper called out of the target body, while the body itself holds or mutates mocktime through a FakeNodeClock. Since FakeNodeClock is a LimitOne type, the helper cannot hold one of its own and reaches for the SetMockTime() global mutator instead, so it is unclear which of the two owns mocktime. Add a GetFakeNodeClock() that returns a single process-wide FakeNodeClock and route these targets through it, replacing their local FakeNodeClock and genesis-time SetMockTime() calls. It is initialized with 0s rather than a default-constructed FakeNodeClock{}, which would read mocktime at whatever point the static happens to be constructed. Every user sets the time before use anyway. --- src/test/fuzz/cmpctblock.cpp | 8 ++++---- src/test/fuzz/process_message.cpp | 6 +++--- src/test/fuzz/process_messages.cpp | 6 +++--- src/test/fuzz/utxo_snapshot.cpp | 4 ++-- src/test/util/time.h | 6 ++++++ 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/test/fuzz/cmpctblock.cpp b/src/test/fuzz/cmpctblock.cpp index e2aea86a89e..ffa67d4bb63 100644 --- a/src/test/fuzz/cmpctblock.cpp +++ b/src/test/fuzz/cmpctblock.cpp @@ -109,7 +109,7 @@ public: void ResetChainmanAndMempool(TestingSetup& setup) { - SetMockTime(Params().GenesisBlock().Time()); + GetFakeNodeClock().set(Params().GenesisBlock().Time()); bilingual_str error{}; setup.m_node.mempool.reset(); @@ -163,7 +163,7 @@ FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock) SeedRandomStateForTest(SeedRand::ZEROS); FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - FakeNodeClock clock{1610000000s}; + GetFakeNodeClock().set(1610000000s); FakeSteadyClock steady_clock; auto setup = g_setup; @@ -453,10 +453,10 @@ FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock) [&]() { // Set mock time randomly or to tip's time. if (fuzzed_data_provider.ConsumeBool()) { - clock.set(ConsumeTime(fuzzed_data_provider)); + GetFakeNodeClock().set(ConsumeTime(fuzzed_data_provider)); } else { const NodeSeconds tip_time = WITH_LOCK(::cs_main, return chainman.ActiveChain().Tip()->Time()); - clock.set(tip_time); + GetFakeNodeClock().set(tip_time); } sent_net_msg = false; diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 7712ea6fcda..b4a08cfdd29 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -46,7 +46,7 @@ std::string_view LIMIT_TO_MESSAGE_TYPE{}; void ResetChainman(TestingSetup& setup) { - SetMockTime(setup.m_node.chainman->GetParams().GenesisBlock().Time()); + GetFakeNodeClock().set(setup.m_node.chainman->GetParams().GenesisBlock().Time()); setup.m_node.chainman.reset(); setup.m_make_chainman(); setup.LoadVerifyActivateChainstate(); @@ -83,7 +83,7 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) connman.Reset(); auto& chainman{static_cast(*node.chainman)}; const auto block_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())}; - FakeNodeClock clock{1610000000s}; // any time to successfully reset ibd + GetFakeNodeClock().set(1610000000s); // any time to successfully reset ibd FakeSteadyClock steady_clock; chainman.ResetIbd(); chainman.DisableNextWrite(); @@ -117,7 +117,7 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) connman.AddTestNode(p2p_node); FillNode(fuzzed_data_provider, connman, p2p_node); - clock.set(ConsumeTime(fuzzed_data_provider)); + GetFakeNodeClock().set(ConsumeTime(fuzzed_data_provider)); CSerializedNetMsg net_msg; net_msg.m_type = random_message_type; diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 89c03fa6183..cec2bc3fb5d 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -40,7 +40,7 @@ TestingSetup* g_setup; void ResetChainman(TestingSetup& setup) { - SetMockTime(setup.m_node.chainman->GetParams().GenesisBlock().Time()); + GetFakeNodeClock().set(setup.m_node.chainman->GetParams().GenesisBlock().Time()); setup.m_node.chainman.reset(); setup.m_make_chainman(); setup.LoadVerifyActivateChainstate(); @@ -72,7 +72,7 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) connman.Reset(); auto& chainman{static_cast(*node.chainman)}; const auto block_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())}; - FakeNodeClock clock{1610000000s}; // any time to successfully reset ibd + GetFakeNodeClock().set(1610000000s); // any time to successfully reset ibd FakeSteadyClock steady_clock; chainman.ResetIbd(); chainman.DisableNextWrite(); @@ -110,7 +110,7 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 30) { const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::MESSAGE_TYPE_SIZE).c_str()}; - clock.set(ConsumeTime(fuzzed_data_provider)); + GetFakeNodeClock().set(ConsumeTime(fuzzed_data_provider)); CSerializedNetMsg net_msg; net_msg.m_type = random_message_type; diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index 815517bc55c..e4098457916 100644 --- a/src/test/fuzz/utxo_snapshot.cpp +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -73,7 +73,7 @@ void initialize_chain() const auto params{CreateChainParams(ArgsManager{}, ChainType::REGTEST)}; static const auto chain{CreateBlockChain(2 * COINBASE_MATURITY, *params)}; g_chain = &chain; - SetMockTime(chain.back()->Time()); + GetFakeNodeClock().set(chain.back()->Time()); // Make sure we can generate a valid snapshot. sanity_check_snapshot(); @@ -104,7 +104,7 @@ void utxo_snapshot_fuzz(FuzzBufferType buffer) { SeedRandomStateForTest(SeedRand::ZEROS); FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - FakeNodeClock clock{ConsumeTime(fuzzed_data_provider, /*min=*/1296688602)}; // regtest genesis block timestamp + GetFakeNodeClock().set(ConsumeTime(fuzzed_data_provider, /*min=*/1296688602)); // regtest genesis block timestamp auto& setup{*g_setup}; bool dirty_chainman{false}; // Reuse the global chainman, but reset it when it is dirty auto& chainman{*setup.m_node.chainman}; diff --git a/src/test/util/time.h b/src/test/util/time.h index 213d7b2764c..e20df3fa75b 100644 --- a/src/test/util/time.h +++ b/src/test/util/time.h @@ -76,4 +76,10 @@ public: void operator-=(std::chrono::seconds d) { set(m_t -= d); } }; +inline FakeNodeClock& GetFakeNodeClock() +{ + static FakeNodeClock g_fake_node_clock{0s}; + return g_fake_node_clock; +} + #endif // BITCOIN_TEST_UTIL_TIME_H From 2a29cee68438e485b101e9a89c907f7a2ea38232 Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Fri, 19 Jun 2026 20:25:58 +0800 Subject: [PATCH 2/5] test: add helper to reset chainman and mempool Move the reusable chainman/mempool reset logic from the cmpctblock fuzz target into test util validation helpers. Return the mature coinbase outputs so cmpctblock can keep using them while other callers can ignore the result. --- src/test/fuzz/cmpctblock.cpp | 35 ++---------------------------- src/test/util/validation.cpp | 41 ++++++++++++++++++++++++++++++++++++ src/test/util/validation.h | 8 +++++++ 3 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/test/fuzz/cmpctblock.cpp b/src/test/fuzz/cmpctblock.cpp index ffa67d4bb63..5a67e8d9c96 100644 --- a/src/test/fuzz/cmpctblock.cpp +++ b/src/test/fuzz/cmpctblock.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -26,20 +25,17 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include #include #include #include -#include #include #include @@ -107,33 +103,6 @@ public: } }; -void ResetChainmanAndMempool(TestingSetup& setup) -{ - GetFakeNodeClock().set(Params().GenesisBlock().Time()); - - bilingual_str error{}; - setup.m_node.mempool.reset(); - setup.m_node.mempool = std::make_unique(MemPoolOptionsForTest(setup.m_node), error); - Assert(error.empty()); - - setup.m_node.chainman.reset(); - setup.m_make_chainman(); - setup.LoadVerifyActivateChainstate(); - - node::BlockCreateOptions options; - options.coinbase_output_script = P2WSH_OP_TRUE; - - g_mature_coinbase.clear(); - - for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) { - COutPoint prevout{MineBlock(setup.m_node, options)}; - if (i < COINBASE_MATURITY) { - LOCK(cs_main); - CAmount subsidy{setup.m_node.chainman->ActiveChainstate().CoinsTip().GetCoin(prevout)->out.nValue}; - g_mature_coinbase.emplace_back(prevout, subsidy); - } - } -} //! Used to run tasks in a std::thread to avoid DEBUG_LOCKORDER false positives. class ImmediateBackgroundTaskRunner : public util::TaskRunnerInterface @@ -155,7 +124,7 @@ void initialize_cmpctblock() g_nBits = Params().GenesisBlock().nBits; // Replace validation_signals before creating chainman and mempool so they use it. testing_setup->m_node.validation_signals = std::make_unique(std::make_unique()); - ResetChainmanAndMempool(*g_setup); + g_mature_coinbase = ResetChainmanAndMempool(*g_setup); } FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock) @@ -509,6 +478,6 @@ FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock) if (initial_index_size != end_index_size || initial_sequence != end_sequence) { MakeRandDeterministicDANGEROUS(uint256::ZERO); - ResetChainmanAndMempool(*g_setup); + g_mature_coinbase = ResetChainmanAndMempool(*g_setup); } } diff --git a/src/test/util/validation.cpp b/src/test/util/validation.cpp index 7e09597ea34..61a16657f58 100644 --- a/src/test/util/validation.cpp +++ b/src/test/util/validation.cpp @@ -4,12 +4,25 @@ #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include +#include + using kernel::ChainstateRole; void TestBlockManager::CleanupForFuzzing() @@ -91,3 +104,31 @@ void TestChainstateManager::ResetBestInvalid() { m_best_invalid = nullptr; } + +std::vector> ResetChainmanAndMempool(TestingSetup& setup) +{ + GetFakeNodeClock().set(setup.m_node.chainman->GetParams().GenesisBlock().Time()); + + bilingual_str error{}; + setup.m_node.mempool.reset(); + setup.m_node.mempool = std::make_unique(MemPoolOptionsForTest(setup.m_node), error); + Assert(error.empty()); + + setup.m_node.chainman.reset(); + setup.m_make_chainman(); + setup.LoadVerifyActivateChainstate(); + + node::BlockCreateOptions options; + options.coinbase_output_script = P2WSH_OP_TRUE; + + std::vector> mature_coinbase; + for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) { + COutPoint prevout{MineBlock(setup.m_node, options)}; + if (i < COINBASE_MATURITY) { + LOCK(cs_main); + CAmount subsidy{setup.m_node.chainman->ActiveChainstate().CoinsTip().GetCoin(prevout)->out.nValue}; + mature_coinbase.emplace_back(prevout, subsidy); + } + } + return mature_coinbase; +} diff --git a/src/test/util/validation.h b/src/test/util/validation.h index 1be3f6a64db..87a2d2efe1a 100644 --- a/src/test/util/validation.h +++ b/src/test/util/validation.h @@ -5,12 +5,18 @@ #ifndef BITCOIN_TEST_UTIL_VALIDATION_H #define BITCOIN_TEST_UTIL_VALIDATION_H +#include +#include #include +#include +#include + namespace node { class BlockManager; } class CValidationInterface; +struct TestingSetup; struct TestBlockManager : public node::BlockManager { /** Test-only method to clear internal state for fuzzing */ @@ -41,4 +47,6 @@ public: const CBlockIndex* pindex); }; +std::vector> ResetChainmanAndMempool(TestingSetup& setup); + #endif // BITCOIN_TEST_UTIL_VALIDATION_H From b11456386b266b8c0a319b6fad3481b8eeb155cf Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Fri, 12 Jun 2026 19:30:21 +0800 Subject: [PATCH 3/5] fuzz: let the test input toggle IBD in the p2p fuzz targets process_message, process_messages and p2p_handshake put the node in IBD via ResetIbd(), so net_processing returns early at the IsInitialBlockDownload() check and almost never exercises the non-IBD transaction-handling code paths behind it. Only ConnectTip() latches the node back out, through UpdateIBDStatus(). p2p_handshake connects no block, and in process_message the single message is the whole iteration, so for those two the non-IBD paths are out of reach entirely. process_messages could reach them if one of its messages carried a block building on the tip, but that is unlikely. For process_message(s), leaving IBD used to be controllable from the fuzz input via a jump_out_of_ibd bool that called JumpOutOfIbd(). Commit fa0a864b (#20908) dropped that toggle because mocktime made it redundant: back then IsInitialBlockDownload() evaluated the tip timestamp against the current mocked time on every call, so SetMockTime(ConsumeTime(...)) alone could drive the node in and out of IBD. That stopped working in #34253, which turned IsInitialBlockDownload() into a lock-free read of the cached m_cached_is_ibd flag, latched only by UpdateIBDStatus() on chain activation; mocktime no longer affects it. p2p_handshake never had such a toggle. Restore the toggle. In process_message (a single message), the bool is consumed last. In process_messages and p2p_handshake, the toggle lives inside the message loop, as it did before fa0a864b. A latched bool decides before each message whether to call JumpOutOfIbd(), so some messages can be handled under IBD and the rest after leaving it. Fixes: #34253 --- src/test/fuzz/p2p_handshake.cpp | 9 ++++++++- src/test/fuzz/process_message.cpp | 6 +++++- src/test/fuzz/process_messages.cpp | 8 +++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/test/fuzz/p2p_handshake.cpp b/src/test/fuzz/p2p_handshake.cpp index a71a61b85c9..9b657d68360 100644 --- a/src/test/fuzz/p2p_handshake.cpp +++ b/src/test/fuzz/p2p_handshake.cpp @@ -41,7 +41,7 @@ FUZZ_TARGET(p2p_handshake, .init = ::initialize) auto& node{g_setup->m_node}; auto& connman{static_cast(*node.connman)}; auto& chainman{static_cast(*node.chainman)}; - FakeNodeClock clock{1610000000s}; // any time to successfully reset ibd + FakeNodeClock clock{1610000000s}; // 2021-01-07, arbitrary FakeSteadyClock steady_clock; chainman.ResetIbd(); @@ -72,6 +72,10 @@ FUZZ_TARGET(p2p_handshake, .init = ::initialize) static_cast(fuzzed_data_provider.ConsumeIntegral())); } + // Toggle IBD from within the loop, so that some messages may be processed + // under IBD and the rest after leaving it. JumpOutOfIbd() latches, so guard + // it to call at most once. + bool jump_out_of_ibd{false}; LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 100) { CNode& connection = *PickValue(fuzzed_data_provider, peers); if (connection.fDisconnect || connection.fSuccessfullyConnected) { @@ -80,6 +84,9 @@ FUZZ_TARGET(p2p_handshake, .init = ::initialize) continue; } + if (!jump_out_of_ibd) jump_out_of_ibd = fuzzed_data_provider.ConsumeBool(); + if (jump_out_of_ibd && chainman.IsInitialBlockDownload()) chainman.JumpOutOfIbd(); + clock += std::chrono::seconds{ fuzzed_data_provider.ConsumeIntegralInRange( -std::chrono::seconds{10min}.count(), // Allow mocktime to go backwards slightly diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index b4a08cfdd29..932a4c2fa15 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -83,7 +83,7 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) connman.Reset(); auto& chainman{static_cast(*node.chainman)}; const auto block_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())}; - GetFakeNodeClock().set(1610000000s); // any time to successfully reset ibd + GetFakeNodeClock().set(1610000000s); // 2021-01-07, arbitrary FakeSteadyClock steady_clock; chainman.ResetIbd(); chainman.DisableNextWrite(); @@ -126,6 +126,10 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) connman.FlushSendBuffer(p2p_node); (void)connman.ReceiveMsgFrom(p2p_node, std::move(net_msg)); + if (fuzzed_data_provider.ConsumeBool()) { + chainman.JumpOutOfIbd(); + } + bool more_work{true}; while (more_work) { p2p_node.fPauseSend = false; diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index cec2bc3fb5d..094c956f777 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -72,7 +72,7 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) connman.Reset(); auto& chainman{static_cast(*node.chainman)}; const auto block_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())}; - GetFakeNodeClock().set(1610000000s); // any time to successfully reset ibd + GetFakeNodeClock().set(1610000000s); // 2021-01-07, arbitrary FakeSteadyClock steady_clock; chainman.ResetIbd(); chainman.DisableNextWrite(); @@ -107,7 +107,13 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) connman.AddTestNode(p2p_node); } + // Toggle IBD from within the loop, so that some messages may be processed + // under IBD and the rest after leaving it. JumpOutOfIbd() latches, so guard + // it to call at most once. + bool jump_out_of_ibd{false}; LIMITED_WHILE (fuzzed_data_provider.ConsumeBool(), 30) { + if (!jump_out_of_ibd) jump_out_of_ibd = fuzzed_data_provider.ConsumeBool(); + if (jump_out_of_ibd && chainman.IsInitialBlockDownload()) chainman.JumpOutOfIbd(); const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::MESSAGE_TYPE_SIZE).c_str()}; GetFakeNodeClock().set(ConsumeTime(fuzzed_data_provider)); From d522fd3196368d4be337bff7bc2a5f33ce3ed1c4 Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Wed, 17 Jun 2026 20:10:20 +0800 Subject: [PATCH 4/5] fuzz: prepare deterministic mempool rebuilds Reset the global PRNG before the dirty-state reset in process_message and process_messages. This prepares the reset path for the following change, which rebuilds the reused mempool together with the chainman. The mempool construction path consumes PRNG-backed state, so the rebuild should start from a fixed seed rather than from the RNG state left by the fuzz input. --- src/test/fuzz/process_message.cpp | 7 ++++++- src/test/fuzz/process_messages.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index 932a4c2fa15..b35c4021ae0 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,8 @@ void ResetChainman(TestingSetup& setup) } } // namespace +extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; + void initialize_process_message() { if (const auto val{std::getenv("LIMIT_TO_MESSAGE_TYPE")}) { @@ -143,7 +146,9 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) node.validation_signals->UnregisterValidationInterface(node.peerman.get()); node.connman->StopNodes(); if (block_index_size != WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())) { - // Reuse the global chainman, but reset it when it is dirty + // Reuse the global chainman, but reset it when it is dirty. Reset the + // rng first, so ResetChainman() consumes it from a fixed seed. + MakeRandDeterministicDANGEROUS(uint256::ZERO); ResetChainman(*g_setup); } } diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 094c956f777..9a1f28af92c 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,8 @@ void ResetChainman(TestingSetup& setup) } } // namespace +extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; + void initialize_process_messages() { static const auto testing_setup{ @@ -142,7 +145,9 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) node.validation_signals->UnregisterValidationInterface(node.peerman.get()); node.connman->StopNodes(); if (block_index_size != WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())) { - // Reuse the global chainman, but reset it when it is dirty + // Reuse the global chainman, but reset it when it is dirty. Reset the + // rng first, so ResetChainman() consumes it from a fixed seed. + MakeRandDeterministicDANGEROUS(uint256::ZERO); ResetChainman(*g_setup); } } From 87b080fe2b66036184a54a0bfc320498dd416d74 Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Fri, 19 Jun 2026 20:31:11 +0800 Subject: [PATCH 5/5] fuzz: reset the reused mempool in process_message(s) The mempool is reused across iterations of process_message and process_messages, but it was never reset, so a transaction accepted into the mempool by one input would leak into the next iteration. A random payload can produce a transaction that passes AcceptToMemoryPool. Rebuild the mempool together with the chainman in ResetChainmanAndMempool(), called when either the block index grew or the mempool was modified. The mempool is bound to the chainman at chainman construction (ChainstateLoadOptions::mempool), so the two must be reset together: the mempool is rebuilt first, then the chainman, which re-binds the fresh mempool. This mirrors the cmpctblock harness. --- src/test/fuzz/process_message.cpp | 25 ++++++------------------- src/test/fuzz/process_messages.cpp | 26 +++++++------------------- 2 files changed, 13 insertions(+), 38 deletions(-) diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index b35c4021ae0..e4f0a36dbee 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -4,11 +4,9 @@ #include #include -#include #include #include #include -#include #include #include #include @@ -17,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -45,17 +42,6 @@ namespace { TestingSetup* g_setup; std::string_view LIMIT_TO_MESSAGE_TYPE{}; -void ResetChainman(TestingSetup& setup) -{ - GetFakeNodeClock().set(setup.m_node.chainman->GetParams().GenesisBlock().Time()); - setup.m_node.chainman.reset(); - setup.m_make_chainman(); - setup.LoadVerifyActivateChainstate(); - for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { - node::BlockCreateOptions options; - MineBlock(setup.m_node, options); - } -} } // namespace extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; @@ -73,7 +59,7 @@ void initialize_process_message() {}), }; g_setup = testing_setup.get(); - ResetChainman(*g_setup); + ResetChainmanAndMempool(*g_setup); } FUZZ_TARGET(process_message, .init = initialize_process_message) @@ -86,6 +72,7 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) connman.Reset(); auto& chainman{static_cast(*node.chainman)}; const auto block_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())}; + const auto initial_sequence{WITH_LOCK(node.mempool->cs, return node.mempool->GetSequence())}; GetFakeNodeClock().set(1610000000s); // 2021-01-07, arbitrary FakeSteadyClock steady_clock; chainman.ResetIbd(); @@ -145,10 +132,10 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) node.validation_signals->SyncWithValidationInterfaceQueue(); node.validation_signals->UnregisterValidationInterface(node.peerman.get()); node.connman->StopNodes(); - if (block_index_size != WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())) { - // Reuse the global chainman, but reset it when it is dirty. Reset the - // rng first, so ResetChainman() consumes it from a fixed seed. + const auto end_sequence{WITH_LOCK(node.mempool->cs, return node.mempool->GetSequence())}; + if (block_index_size != WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size()) || initial_sequence != end_sequence) { + // Reuse the global chainman and mempool, but reset them when dirty. MakeRandDeterministicDANGEROUS(uint256::ZERO); - ResetChainman(*g_setup); + ResetChainmanAndMempool(*g_setup); } } diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 9a1f28af92c..983d2a5e14b 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -4,11 +4,9 @@ #include #include -#include #include #include #include -#include #include #include #include @@ -17,13 +15,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -39,17 +37,6 @@ namespace { TestingSetup* g_setup; -void ResetChainman(TestingSetup& setup) -{ - GetFakeNodeClock().set(setup.m_node.chainman->GetParams().GenesisBlock().Time()); - setup.m_node.chainman.reset(); - setup.m_make_chainman(); - setup.LoadVerifyActivateChainstate(); - node::BlockCreateOptions options; - for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { - MineBlock(setup.m_node, options); - } -} } // namespace extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; @@ -62,7 +49,7 @@ void initialize_process_messages() {}), }; g_setup = testing_setup.get(); - ResetChainman(*g_setup); + ResetChainmanAndMempool(*g_setup); } FUZZ_TARGET(process_messages, .init = initialize_process_messages) @@ -75,6 +62,7 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) connman.Reset(); auto& chainman{static_cast(*node.chainman)}; const auto block_index_size{WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())}; + const auto initial_sequence{WITH_LOCK(node.mempool->cs, return node.mempool->GetSequence())}; GetFakeNodeClock().set(1610000000s); // 2021-01-07, arbitrary FakeSteadyClock steady_clock; chainman.ResetIbd(); @@ -144,10 +132,10 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) node.validation_signals->SyncWithValidationInterfaceQueue(); node.validation_signals->UnregisterValidationInterface(node.peerman.get()); node.connman->StopNodes(); - if (block_index_size != WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size())) { - // Reuse the global chainman, but reset it when it is dirty. Reset the - // rng first, so ResetChainman() consumes it from a fixed seed. + const auto end_sequence{WITH_LOCK(node.mempool->cs, return node.mempool->GetSequence())}; + if (block_index_size != WITH_LOCK(chainman.GetMutex(), return chainman.BlockIndex().size()) || initial_sequence != end_sequence) { + // Reuse the global chainman and mempool, but reset them when dirty. MakeRandDeterministicDANGEROUS(uint256::ZERO); - ResetChainman(*g_setup); + ResetChainmanAndMempool(*g_setup); } }