From 4e5327bc988b3928ab6c96d6407d28a91a347413 Mon Sep 17 00:00:00 2001 From: Hao Xu Date: Tue, 11 Aug 2026 19:29:36 +0800 Subject: [PATCH] fuzz: refactor: scope fake clocks to target phases Avoid exposing a process-wide FakeNodeClock accessor from the test utility module. Initialize separate scoped clocks for target setup and input processing, and pass the active clock to ResetChainmanAndMempool by reference. ResetChainmanAndMempool sets each scoped clock to the selected chain's genesis time. Avoid hard-coding the mainnet genesis timestamp when constructing these clocks, because the targets use REGTEST parameters and the value is overwritten during reset. Initialize each clock from the fuzz harness's existing mock time until ResetChainmanAndMempool sets the REGTEST genesis time. This commit does not change behavior. Co-authored-by: maflcko <6399679+maflcko@users.noreply.github.com> Co-authored-by: nervana21 <205626986+nervana21@users.noreply.github.com> --- src/test/fuzz/cmpctblock.cpp | 11 ++++++----- src/test/fuzz/process_message.cpp | 9 +++++---- src/test/fuzz/process_messages.cpp | 9 +++++---- src/test/fuzz/utxo_snapshot.cpp | 4 ++-- src/test/util/time.h | 6 ------ src/test/util/validation.cpp | 4 ++-- src/test/util/validation.h | 3 ++- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/test/fuzz/cmpctblock.cpp b/src/test/fuzz/cmpctblock.cpp index cb57a11efb7..497389a67de 100644 --- a/src/test/fuzz/cmpctblock.cpp +++ b/src/test/fuzz/cmpctblock.cpp @@ -119,12 +119,13 @@ extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; void initialize_cmpctblock() { + FakeNodeClock init_clock{}; // Uses the existing mock time static const auto testing_setup = MakeNoLogFileContext(); g_setup = testing_setup.get(); 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()); - g_mature_coinbase = ResetChainmanAndMempool(*g_setup); + g_mature_coinbase = ResetChainmanAndMempool(*g_setup, init_clock); } FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock) @@ -132,7 +133,7 @@ FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock) SeedRandomStateForTest(SeedRand::ZEROS); FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); - GetFakeNodeClock().set(1610000000s); // 2021-01-07, arbitrary + FakeNodeClock node_clock{1610000000s}; // 2021-01-07, arbitrary FakeSteadyClock steady_clock; auto setup = g_setup; @@ -422,10 +423,10 @@ FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock) [&]() { // Set mock time randomly or to tip's time. if (fuzzed_data_provider.ConsumeBool()) { - GetFakeNodeClock().set(ConsumeTime(fuzzed_data_provider)); + node_clock.set(ConsumeTime(fuzzed_data_provider)); } else { const NodeSeconds tip_time = WITH_LOCK(::cs_main, return chainman.ActiveChain().Tip()->Time()); - GetFakeNodeClock().set(tip_time); + node_clock.set(tip_time); } sent_net_msg = false; @@ -478,6 +479,6 @@ FUZZ_TARGET(cmpctblock, .init = initialize_cmpctblock) if (initial_index_size != end_index_size || initial_sequence != end_sequence) { MakeRandDeterministicDANGEROUS(uint256::ZERO); - g_mature_coinbase = ResetChainmanAndMempool(*g_setup); + g_mature_coinbase = ResetChainmanAndMempool(*g_setup, node_clock); } } diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp index e4f0a36dbee..a63f8a0a6ad 100644 --- a/src/test/fuzz/process_message.cpp +++ b/src/test/fuzz/process_message.cpp @@ -48,6 +48,7 @@ extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; void initialize_process_message() { + FakeNodeClock init_clock{}; // Uses the existing mock time if (const auto val{std::getenv("LIMIT_TO_MESSAGE_TYPE")}) { LIMIT_TO_MESSAGE_TYPE = val; Assert(std::count(ALL_NET_MESSAGE_TYPES.begin(), ALL_NET_MESSAGE_TYPES.end(), LIMIT_TO_MESSAGE_TYPE)); // Unknown message type passed @@ -59,7 +60,7 @@ void initialize_process_message() {}), }; g_setup = testing_setup.get(); - ResetChainmanAndMempool(*g_setup); + ResetChainmanAndMempool(*g_setup, init_clock); } FUZZ_TARGET(process_message, .init = initialize_process_message) @@ -73,7 +74,7 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) 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 + FakeNodeClock node_clock{1610000000s}; // 2021-01-07, arbitrary FakeSteadyClock steady_clock; chainman.ResetIbd(); chainman.DisableNextWrite(); @@ -107,7 +108,7 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) connman.AddTestNode(p2p_node); FillNode(fuzzed_data_provider, connman, p2p_node); - GetFakeNodeClock().set(ConsumeTime(fuzzed_data_provider)); + node_clock.set(ConsumeTime(fuzzed_data_provider)); CSerializedNetMsg net_msg; net_msg.m_type = random_message_type; @@ -136,6 +137,6 @@ FUZZ_TARGET(process_message, .init = initialize_process_message) 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); - ResetChainmanAndMempool(*g_setup); + ResetChainmanAndMempool(*g_setup, node_clock); } } diff --git a/src/test/fuzz/process_messages.cpp b/src/test/fuzz/process_messages.cpp index 983d2a5e14b..f893ebe43d8 100644 --- a/src/test/fuzz/process_messages.cpp +++ b/src/test/fuzz/process_messages.cpp @@ -43,13 +43,14 @@ extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; void initialize_process_messages() { + FakeNodeClock init_clock{}; // Uses the existing mock time static const auto testing_setup{ MakeNoLogFileContext( /*chain_type=*/ChainType::REGTEST, {}), }; g_setup = testing_setup.get(); - ResetChainmanAndMempool(*g_setup); + ResetChainmanAndMempool(*g_setup, init_clock); } FUZZ_TARGET(process_messages, .init = initialize_process_messages) @@ -63,7 +64,7 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) 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 + FakeNodeClock node_clock{1610000000s}; // 2021-01-07, arbitrary FakeSteadyClock steady_clock; chainman.ResetIbd(); chainman.DisableNextWrite(); @@ -107,7 +108,7 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) 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)); + node_clock.set(ConsumeTime(fuzzed_data_provider)); CSerializedNetMsg net_msg; net_msg.m_type = random_message_type; @@ -136,6 +137,6 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages) 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); - ResetChainmanAndMempool(*g_setup); + ResetChainmanAndMempool(*g_setup, node_clock); } } diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index e4098457916..a90dfc512fe 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; - GetFakeNodeClock().set(chain.back()->Time()); + FakeNodeClock node_clock{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()); - GetFakeNodeClock().set(ConsumeTime(fuzzed_data_provider, /*min=*/1296688602)); // regtest genesis block timestamp + FakeNodeClock node_clock{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 e20df3fa75b..213d7b2764c 100644 --- a/src/test/util/time.h +++ b/src/test/util/time.h @@ -76,10 +76,4 @@ 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 diff --git a/src/test/util/validation.cpp b/src/test/util/validation.cpp index 61a16657f58..7592ff2824d 100644 --- a/src/test/util/validation.cpp +++ b/src/test/util/validation.cpp @@ -105,9 +105,9 @@ void TestChainstateManager::ResetBestInvalid() m_best_invalid = nullptr; } -std::vector> ResetChainmanAndMempool(TestingSetup& setup) +std::vector> ResetChainmanAndMempool(TestingSetup& setup, FakeNodeClock& node_clock) { - GetFakeNodeClock().set(setup.m_node.chainman->GetParams().GenesisBlock().Time()); + node_clock.set(setup.m_node.chainman->GetParams().GenesisBlock().Time()); bilingual_str error{}; setup.m_node.mempool.reset(); diff --git a/src/test/util/validation.h b/src/test/util/validation.h index 87a2d2efe1a..91930b3dd73 100644 --- a/src/test/util/validation.h +++ b/src/test/util/validation.h @@ -16,6 +16,7 @@ namespace node { class BlockManager; } class CValidationInterface; +class FakeNodeClock; struct TestingSetup; struct TestBlockManager : public node::BlockManager { @@ -47,6 +48,6 @@ public: const CBlockIndex* pindex); }; -std::vector> ResetChainmanAndMempool(TestingSetup& setup); +std::vector> ResetChainmanAndMempool(TestingSetup& setup, FakeNodeClock& node_clock); #endif // BITCOIN_TEST_UTIL_VALIDATION_H