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>
This commit is contained in:
Hao Xu
2026-08-11 19:29:36 +08:00
parent e33410d888
commit 4e5327bc98
7 changed files with 22 additions and 24 deletions

View File

@@ -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<TestingSetup>();
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<ValidationSignals>(std::make_unique<ImmediateBackgroundTaskRunner>());
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);
}
}

View File

@@ -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<TestChainstateManager&>(*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);
}
}

View File

@@ -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<TestingSetup>(
/*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<TestChainstateManager&>(*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);
}
}

View File

@@ -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};

View File

@@ -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

View File

@@ -105,9 +105,9 @@ void TestChainstateManager::ResetBestInvalid()
m_best_invalid = nullptr;
}
std::vector<std::pair<COutPoint, CAmount>> ResetChainmanAndMempool(TestingSetup& setup)
std::vector<std::pair<COutPoint, CAmount>> 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();

View File

@@ -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<std::pair<COutPoint, CAmount>> ResetChainmanAndMempool(TestingSetup& setup);
std::vector<std::pair<COutPoint, CAmount>> ResetChainmanAndMempool(TestingSetup& setup, FakeNodeClock& node_clock);
#endif // BITCOIN_TEST_UTIL_VALIDATION_H