add check that chainwork doesn't exceed minimum work

This commit is contained in:
marcofleon 2024-09-17 17:52:56 +01:00
parent 9aa5d1c3fc
commit 284bd17309

View file

@ -10,6 +10,7 @@
#include <test/util/net.h>
#include <test/util/script.h>
#include <test/util/setup_common.h>
#include <uint256.h>
#include <validation.h>
namespace {
@ -20,9 +21,7 @@ class HeadersSyncSetup : public TestingSetup
std::vector<CNode*> 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<CBlockHeader> 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<uint64_t>()};
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