diff --git a/src/test/fuzz/p2p_headers_presync.cpp b/src/test/fuzz/p2p_headers_presync.cpp index b86d03442dd..e22087303a5 100644 --- a/src/test/fuzz/p2p_headers_presync.cpp +++ b/src/test/fuzz/p2p_headers_presync.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace { @@ -20,9 +21,7 @@ class HeadersSyncSetup : public TestingSetup std::vector m_connections; public: - HeadersSyncSetup(const ChainType chain_type = ChainType::MAIN, - TestOpts opts = {}) - : TestingSetup(chain_type, opts) + HeadersSyncSetup(const ChainType chain_type, TestOpts opts) : TestingSetup(chain_type, opts) { PeerManager::Options peerman_opts; node::ApplyArgsManOptions(*m_node.args, peerman_opts); @@ -116,9 +115,9 @@ CBlock ConsumeBlock(FuzzedDataProvider& fuzzed_data_provider, const uint256& pre return block; } -void FinalizeHeader(CBlockHeader& header) +void FinalizeHeader(CBlockHeader& header, const ChainstateManager& chainman) { - while (!CheckProofOfWork(header.GetHash(), header.nBits, Params().GetConsensus())) { + while (!CheckProofOfWork(header.GetHash(), header.nBits, chainman.GetParams().GetConsensus())) { ++(header.nNonce); } } @@ -144,17 +143,20 @@ FUZZ_TARGET(p2p_headers_presync, .init = initialize) FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; - CBlockHeader base{Params().GenesisBlock()}; + CBlockHeader base{chainman.GetParams().GenesisBlock()}; SetMockTime(base.nTime); // The chain is just a single block, so this is equal to 1 size_t original_index_size{WITH_LOCK(cs_main, return chainman.m_blockman.m_block_index.size())}; + arith_uint256 total_work{WITH_LOCK(cs_main, return chainman.m_best_header->nChainWork)}; + + std::vector all_headers; LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 100) { auto finalized_block = [&]() { CBlock block = ConsumeBlock(fuzzed_data_provider, base.GetHash(), base.nBits); - FinalizeHeader(block); + FinalizeHeader(block, chainman); return block; }; @@ -167,10 +169,12 @@ FUZZ_TARGET(p2p_headers_presync, .init = initialize) headers.resize(FUZZ_MAX_HEADERS_RESULTS); for (CBlock& header : headers) { header = ConsumeHeader(fuzzed_data_provider, base.GetHash(), base.nBits); - FinalizeHeader(header); + FinalizeHeader(header, chainman); base = header; } + all_headers.insert(all_headers.end(), headers.begin(), headers.end()); + auto headers_msg = NetMsg::Make(NetMsgType::HEADERS, TX_WITH_WITNESS(headers)); g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg)); }, @@ -179,6 +183,8 @@ FUZZ_TARGET(p2p_headers_presync, .init = initialize) auto block = finalized_block(); CBlockHeaderAndShortTxIDs cmpct_block{block, fuzzed_data_provider.ConsumeIntegral()}; + all_headers.push_back(block); + auto headers_msg = NetMsg::Make(NetMsgType::CMPCTBLOCK, TX_WITH_WITNESS(cmpct_block)); g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg)); }, @@ -186,9 +192,19 @@ FUZZ_TARGET(p2p_headers_presync, .init = initialize) // Send a block auto block = finalized_block(); + all_headers.push_back(block); + auto headers_msg = NetMsg::Make(NetMsgType::BLOCK, TX_WITH_WITNESS(block)); g_testing_setup->SendMessage(fuzzed_data_provider, std::move(headers_msg)); }); + + // This is a conservative overestimate, as base is only moved forward when sending headers. In theory, + // the longest chain generated by this test is 1600 (FUZZ_MAX_HEADERS_RESULTS * 100) headers. In that case, + // this variable will accurately reflect the chain's total work. + total_work += CalculateClaimedHeadersWork(all_headers); + + // This test should never create a chain with more work than MinimumChainWork. + assert(total_work < chainman.MinimumChainWork()); } // The headers/blocks sent in this test should never be stored, as the chains don't have the work required