Skip to content

Commit 00b9e70

Browse files
committed
log: add print statements to understand fuzz test
1 parent c610583 commit 00b9e70

File tree

2 files changed

+51
-7
lines changed

2 files changed

+51
-7
lines changed

src/test/fuzz/block_index_tree.cpp

+46-7
Original file line numberDiff line numberDiff line change
@@ -48,31 +48,46 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
4848
std::vector<CBlockIndex*> blocks;
4949
blocks.push_back(genesis);
5050

51+
printf("START\n");
52+
printf("chain.m_chain.Height() = %d\n", chainman.ActiveChainstate().m_chain.Height());
53+
printf("Genesis block : %s\n", genesis->ToString().c_str());
54+
5155
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 1000)
5256
{
5357
CallOneOf(
5458
fuzzed_data_provider,
5559
[&] {
5660
// Receive a header building on an existing one. This assumes headers are valid, so PoW is not relevant here.
5761
LOCK(cs_main);
62+
printf("1. Receive header and build on existing one\n");
5863
CBlockIndex* prev_block = PickValue(fuzzed_data_provider, blocks);
64+
printf("prev_block : %s\n", prev_block->ToString().c_str());
5965
if (!(prev_block->nStatus & BLOCK_FAILED_MASK)) {
6066
CBlockHeader header = ConsumeBlockHeader(fuzzed_data_provider, prev_block->GetBlockHash(), nonce_counter);
67+
printf("m_best_header before AddToBlockIndex : %s\n", chainman.m_best_header->ToString().c_str());
6168
CBlockIndex* index = blockman.AddToBlockIndex(header, chainman.m_best_header);
69+
printf("m_best_header after AddToBlockIndex : %s\n", chainman.m_best_header->ToString().c_str());
70+
printf("new index is : %s\n", index->ToString().c_str());
6271
assert(index->nStatus & BLOCK_VALID_TREE);
6372
blocks.push_back(index);
73+
} else {
74+
printf("prev_block is BLOCK_FAILED_MASK, don't build on top of prev_block\n");
6475
}
76+
printf("\n");
6577
},
6678
[&] {
6779
// Receive a full block (valid or invalid) for an existing header, but don't attempt to connect it yet
6880
LOCK(cs_main);
81+
printf("2. Receive full block (valid or invalid) for an existing header but don't CONNECT\n");
6982
CBlockIndex* index = PickValue(fuzzed_data_provider, blocks);
83+
printf("index : %s\n", index->ToString().c_str());
7084
// Must be new to us and not known to be invalid (e.g. because of an invalid ancestor).
7185
if (index->nTx == 0 && !(index->nStatus & BLOCK_FAILED_MASK)) {
7286
if (fuzzed_data_provider.ConsumeBool()) { // Invalid
7387
BlockValidationState state;
7488
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "consensus-invalid");
7589
chainman.ActiveChainstate().InvalidBlockFound(index, state);
90+
printf("call InvalidBlockFound, index is now BLOCK_FAILED_VALID\n");
7691
} else {
7792
size_t nTx = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 1000);
7893
CBlock block; // Dummy block, so that ReceivedBlockTransaction can infer a nTx value.
@@ -81,12 +96,19 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
8196
chainman.ReceivedBlockTransactions(block, index, pos);
8297
assert(index->nStatus & BLOCK_VALID_TRANSACTIONS);
8398
assert(index->nStatus & BLOCK_HAVE_DATA);
99+
printf("call ReceivedBlockTransactions, index is now BLOCK_VALID_TRANSACTIONS\n");
84100
}
101+
} else {
102+
printf("index->nTx == 0 is %d\n", index->nTx == 0);
103+
printf("index->nStatus & BLOCK_FAILED_MASK = %d\n", index->nStatus & BLOCK_FAILED_MASK);
104+
printf("since index->nTx(%d) is not 0 and index->nStatus(%s) is not BLOCK_FAILED_MASK, we don't tamper with the validity level\n", index->nTx, index->BlockStatusToString().c_str());
85105
}
106+
printf("\n");
86107
},
87108
[&] {
88109
// Simplified ActivateBestChain(): Try to move to a chain with more work - with the possibility of finding blocks to be invalid on the way
89110
LOCK(cs_main);
111+
printf("2.Simplified ActivateBestChain()\n");
90112
auto& chain = chainman.ActiveChain();
91113
CBlockIndex* old_tip = chain.Tip();
92114
assert(old_tip);
@@ -96,21 +118,27 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
96118
if (best_tip == chain.Tip()) break; // Nothing to do
97119
// Rewind chain to forking point
98120
const CBlockIndex* fork = chain.FindFork(best_tip);
121+
printf("fork : %s\n", fork->ToString().c_str());
99122
// If we can't go back to the fork point due to pruned data, abort and don't do anything. Note that this check does not exist in validation.cpp, where
100123
// the node would currently just crash in this scenario (although this is very unlikely to happen due to the minimum pruning threshold of 550MiB).
101124
CBlockIndex* it = chain.Tip();
125+
printf("chain.Tip() : %s\n", it->ToString().c_str());
126+
printf("we go back to fork point\n");
102127
bool pruned_block{false};
103128
while (it && it->nHeight != fork->nHeight) {
104129
if (!(it->nStatus & BLOCK_HAVE_UNDO) && it->nHeight > 0) {
105130
assert(blockman.m_have_pruned);
106131
pruned_block = true;
132+
printf("pruned block, exit\n");
107133
break;
108134
}
109135
it = it->pprev;
110136
}
111137
if (pruned_block) break;
112138

113139
chain.SetTip(*chain[fork->nHeight]);
140+
it = chain.Tip();
141+
printf("new chain.Tip() : %s\n", it->ToString().c_str());
114142

115143
// Prepare new blocks to connect
116144
std::vector<CBlockIndex*> to_connect;
@@ -120,21 +148,28 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
120148
it = it->pprev;
121149
}
122150
// Connect blocks, possibly fail
151+
printf("Loop through possible blocks to connect to (same as blocks from tip to fork)\n");
123152
for (CBlockIndex* block : to_connect | std::views::reverse) {
124153
assert(!(block->nStatus & BLOCK_FAILED_MASK));
125154
assert(block->nStatus & BLOCK_HAVE_DATA);
126155
if (!block->IsValid(BLOCK_VALID_SCRIPTS)) {
156+
printf("block : %s\n", block->ToString().c_str());
127157
if (fuzzed_data_provider.ConsumeBool()) { // Invalid
128158
BlockValidationState state;
129159
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "consensus-invalid");
130160
chainman.ActiveChainstate().InvalidBlockFound(block, state);
161+
printf("block status after invalidation : %s\n", block->BlockStatusToString().c_str());
162+
printf("we marked as invalid block and EXIT\n");
131163
break;
132164
} else {
133165
block->RaiseValidity(BLOCK_VALID_SCRIPTS);
134166
block->nStatus |= BLOCK_HAVE_UNDO;
167+
printf("block status after raising validity : %s\n", block->BlockStatusToString().c_str());
168+
printf("we marked as BLOCK_VALID_SCRIPTS and LOOP\n");
135169
}
136170
}
137171
chain.SetTip(*block);
172+
printf("set block as new tip\n");
138173
chainman.ActiveChainstate().PruneBlockIndexCandidates();
139174
// ABC may release cs_main / not connect all blocks in one go - but only if we have at least much chain work as we had at the start.
140175
if (block->nChainWork > old_tip->nChainWork && fuzzed_data_provider.ConsumeBool()) {
@@ -143,15 +178,18 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
143178
}
144179
} while (node::CBlockIndexWorkComparator()(chain.Tip(), old_tip));
145180
assert(chain.Tip()->nChainWork >= old_tip->nChainWork);
181+
printf("\n");
146182
},
147183
[&] {
148184
// Prune chain - dealing with block files is beyond the scope of this test, so just prune random blocks, making no assumptions what must
149185
// be together in a block file.
150186
// Also don't prune blocks outside of the chain for now - this would make the fuzzer crash because of the problem describted in
151187
// https://github.com/bitcoin/bitcoin/issues/31512
152188
LOCK(cs_main);
189+
printf("4. Prune chain\n");
153190
auto& chain = chainman.ActiveChain();
154191
int prune_height = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, chain.Height());
192+
printf("chain.Height() = %d and prune_height = %d\n", chain.Height(), prune_height);
155193
CBlockIndex* prune_block{chain[prune_height]};
156194
if (prune_block != chain.Tip()) {
157195
blockman.m_have_pruned = true;
@@ -169,34 +207,35 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
169207
}
170208
}
171209
}
210+
printf("\n");
172211
},
173212
[&] {
174213
// InvalidateBlock + ReconsiderBlock
175214
unsigned mode = fuzzed_data_provider.ConsumeIntegral<uint8_t>();
176215
// different block index constellation when different probabilities used
177216
if ((mode & 127) == 127) {
178217
// InvalidateBlock
218+
printf("5. Invalidateblock\n");
179219
CBlockIndex *prev_block = PickValue(fuzzed_data_provider, blocks);
180220
BlockValidationState state;
221+
printf("block to invalidate : %s\n", prev_block->ToString().c_str());
181222
chainman.ActiveChainstate().InvalidateBlock(state, prev_block);
182-
<<<<<<< Updated upstream
183-
} else if (mode & 5) {
184-
||||||| Stash base
185-
printf("block status after invalidation : %s\n", prev_block->BlockStatusToString().c_str());
186-
} else if (mode & 5) {
187-
=======
188223
printf("block status after invalidation : %s\n", prev_block->BlockStatusToString().c_str());
189224
} else if ((mode & 5) == 5) {
190-
>>>>>>> Stashed changes
191225
// ReconsiderBlock
192226
LOCK(cs_main);
227+
printf("6. Reconsiderblock\n");
193228
CBlockIndex *prev_block = PickValue(fuzzed_data_provider, blocks);
229+
printf("block to reconsider : %s\n", prev_block->ToString().c_str());
194230
chainman.ActiveChainstate().ResetBlockFailureFlags(prev_block);
231+
printf("block status after reconsider : %s\n", prev_block->BlockStatusToString().c_str());
195232
chainman.RecalculateBestHeader();
196233
}
234+
printf("\n");
197235
});
198236
}
199237
chainman.CheckBlockIndex();
238+
printf("END\n");
200239

201240
// clean up global state changed by last iteration and prepare for next iteration
202241
{

src/validation.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -3812,6 +3812,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
38123812
return false;
38133813
}
38143814

3815+
printf("InvalidateBlock: pindex_was_in_chain = %d\n", pindex_was_in_chain);
38153816
// we reach here when m_chain doesn't contain pindex anymore
38163817
// if pindex_was_in_chain is false => we never entered the while loop above => we need to mark (only if it's not marked - maybe it's marked even before fxn call)
38173818
// if pindex_was_in_chain is true => we entered the while loop above => to_mark_failed was definitely marked as BLOCK_FAILED_VALID/CHILD
@@ -5398,16 +5399,20 @@ void ChainstateManager::CheckBlockIndex()
53985399
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) assert(pindexFirstNotScriptsValid == nullptr); // SCRIPTS valid implies all parents are SCRIPTS valid
53995400
if (pindexFirstInvalid == nullptr) {
54005401
// Checks for not-invalid blocks.
5402+
printf("pindexFirstInvalid == nullptr : %s\n", pindex->ToString().c_str());
54015403
if (ActiveChain().Contains(pindex)) {
5404+
printf("failed mask not set in main chain\n");
54025405
assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents.
54035406
}
54045407
}
54055408
else if (pindexFirstInvalid != pindex) {
54065409
// pindexFirstInvalid -> ...... -> pindex
54075410
// we check that descendants are BLOCK_FAILED_CHILD and not BLOCK_FAILED_VALID
5411+
printf("pindexFirstInvalid != pindex : %s\n", pindex->ToString().c_str());
54085412
assert((pindex->nStatus & BLOCK_FAILED_VALID) == 0);
54095413
assert(pindex->nStatus & BLOCK_FAILED_CHILD);
54105414
} else {
5415+
printf("pindexFirstInvalid == pindex : %s\n", pindex->ToString().c_str());
54115416
assert(pindex->nStatus & BLOCK_FAILED_VALID);
54125417
assert((pindex->nStatus & BLOCK_FAILED_CHILD) == 0);
54135418
}

0 commit comments

Comments
 (0)