fuzz: add subtest for re-downloading a previously pruned block
What changed, and why it matters
This commit adds a new test case to an existing fuzz test. Fuzz tests are automated tools that feed random or semi-random inputs to a program to find crashes or bugs. The new test simulates re-downloading a block that was previously pruned (deleted to save disk space), similar to what happens when a user runs the getblockfrompeer RPC. It does not change normal node behavior, only test code.
No security action required. This is a test-only change expanding fuzz coverage for block pruning and re-download logic.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change extends the block_index_tree fuzz target in src/test/fuzz/block_index_tree.cpp. It introduces a pruned_blocks vector and a new fuzz subtest that picks a previously pruned CBlockIndex, constructs a CBlock with the original transaction count, assigns a random FlatFilePos, and calls chainman.ReceivedBlockTransactions() to simulate re-downloading. Assertions verify that BLOCK_HAVE_DATA and BLOCK_VALID_TRANSACTIONS are set afterward. This is purely a test/fuzzing addition.
Changed components
src/test/fuzz/block_index_tree.cppInspect captured patch +19 / −0
diff --git a/src/test/fuzz/block_index_tree.cpp b/src/test/fuzz/block_index_tree.cpp
index df5dc658..df46ebad 100644
--- a/src/test/fuzz/block_index_tree.cpp
+++ b/src/test/fuzz/block_index_tree.cpp
@@ -50,6 +50,8 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
blocks.push_back(genesis);
bool abort_run{false};
+ std::vector<CBlockIndex*> pruned_blocks;
+
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 1000)
{
if (abort_run) break;
@@ -171,7 +173,24 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
blockman.m_blocks_unlinked.erase(_it);
}
}
+ pruned_blocks.push_back(prune_block);
}
+ },
+ [&] {
+ // Download a previously pruned block
+ LOCK(cs_main);
+ size_t num_pruned = pruned_blocks.size();
+ if (num_pruned == 0) return;
+ size_t i = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, num_pruned - 1);
+ CBlockIndex* index = pruned_blocks[i];
+ assert(!(index->nStatus & BLOCK_HAVE_DATA));
+ CBlock block;
+ block.vtx = std::vector<CTransactionRef>(index->nTx); // Set the number of tx to the prior value.
+ FlatFilePos pos(0, fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 1000));
+ chainman.ReceivedBlockTransactions(block, index, pos);
+ assert(index->nStatus & BLOCK_VALID_TRANSACTIONS);
+ assert(index->nStatus & BLOCK_HAVE_DATA);
+ pruned_blocks.erase(pruned_blocks.begin() + i);
});
}
if (!abort_run) {
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.