@@ -47,31 +47,46 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
47
47
std::vector<CBlockIndex*> blocks;
48
48
blocks.push_back (genesis);
49
49
50
+ printf (" START\n " );
51
+ printf (" chain.m_chain.Height() = %d\n " , chainman.ActiveChainstate ().m_chain .Height ());
52
+ printf (" Genesis block (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , genesis->nHeight , genesis->GetBlockHash ().ToString ().c_str (), BlockStatusToString (genesis->nStatus ).c_str (), genesis->nChainWork .ToString ().c_str ());
53
+
50
54
LIMITED_WHILE (fuzzed_data_provider.ConsumeBool (), 1000 )
51
55
{
52
56
CallOneOf (
53
57
fuzzed_data_provider,
54
58
[&] {
55
59
// Receive a header building on an existing one. This assumes headers are valid, so PoW is not relevant here.
56
60
LOCK (cs_main);
61
+ printf (" 1. Receive header and build on existing one\n " );
57
62
CBlockIndex* prev_block = PickValue (fuzzed_data_provider, blocks);
63
+ printf (" prev_block (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , prev_block->nHeight , prev_block->GetBlockHash ().ToString ().c_str (), BlockStatusToString (prev_block->nStatus ).c_str (), prev_block->nChainWork .ToString ().c_str ());
58
64
if (!(prev_block->nStatus & BLOCK_FAILED_MASK)) {
59
65
CBlockHeader header = ConsumeBlockHeader (fuzzed_data_provider, prev_block->GetBlockHash (), nonce_counter);
66
+ printf (" chainman.m_best_header before AddToBlockIndex (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , chainman.m_best_header ->nHeight , chainman.m_best_header ->GetBlockHash ().ToString ().c_str (), BlockStatusToString (chainman.m_best_header ->nStatus ).c_str (), (chainman.m_best_header )->nChainWork .ToString ().c_str ());
60
67
CBlockIndex* index = blockman.AddToBlockIndex (header, chainman.m_best_header );
68
+ printf (" chainman.m_best_header after AddToBlockIndex (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , chainman.m_best_header ->nHeight , chainman.m_best_header ->GetBlockHash ().ToString ().c_str (), BlockStatusToString (chainman.m_best_header ->nStatus ).c_str (), (chainman.m_best_header )->nChainWork .ToString ().c_str ());
69
+ printf (" index (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , index ->nHeight , index ->GetBlockHash ().ToString ().c_str (), BlockStatusToString (index ->nStatus ).c_str (), index ->nChainWork .ToString ().c_str ());
61
70
assert (index ->nStatus & BLOCK_VALID_TREE);
62
71
blocks.push_back (index );
72
+ } else {
73
+ printf (" prev_block is BLOCK_FAILED_MASK, don't build on top of prev_block\n " );
63
74
}
75
+ printf (" \n\n " );
64
76
},
65
77
[&] {
66
78
// Receive a full block (valid or invalid) for an existing header, but don't attempt to connect it yet
67
79
LOCK (cs_main);
80
+ printf (" 2. Receive full block (valid or invalid) for an existing header but don't CONNECT\n " );
68
81
CBlockIndex* index = PickValue (fuzzed_data_provider, blocks);
82
+ printf (" index (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , index ->nHeight , index ->GetBlockHash ().ToString ().c_str (), BlockStatusToString (index ->nStatus ).c_str (), index ->nChainWork .ToString ().c_str ());
69
83
// Must be new to us and not known to be invalid (e.g. because of an invalid ancestor).
70
84
if (index ->nTx == 0 && !(index ->nStatus & BLOCK_FAILED_MASK)) {
71
85
if (fuzzed_data_provider.ConsumeBool ()) { // Invalid
72
86
BlockValidationState state;
73
87
state.Invalid (BlockValidationResult::BLOCK_CONSENSUS, " consensus-invalid" );
74
88
chainman.ActiveChainstate ().InvalidBlockFound (index , state);
89
+ printf (" call InvalidBlockFound, index is now BLOCK_FAILED_VALID\n " );
75
90
} else {
76
91
size_t nTx = fuzzed_data_provider.ConsumeIntegralInRange <size_t >(1 , 1000 );
77
92
CBlock block; // Dummy block, so that ReceivedBlockTransaction can infer a nTx value.
@@ -80,12 +95,19 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
80
95
chainman.ReceivedBlockTransactions (block, index , pos);
81
96
assert (index ->nStatus & BLOCK_VALID_TRANSACTIONS);
82
97
assert (index ->nStatus & BLOCK_HAVE_DATA);
98
+ printf (" call ReceivedBlockTransactions, index is now BLOCK_VALID_TRANSACTIONS\n " );
83
99
}
100
+ } else {
101
+ printf (" index->nTx == 0 = %d\n " , index ->nTx == 0 );
102
+ printf (" index->nStatus & BLOCK_FAILED_MASK = %d\n " , index ->nStatus & BLOCK_FAILED_MASK);
103
+ printf (" Don't do anything since index->nTx == %d is not 0 && index->nStatus = %s is BLOCK_FAILED_MASK\n " , index ->nTx , BlockStatusToString (index ->nStatus ).c_str ());
84
104
}
105
+ printf (" \n\n " );
85
106
},
86
107
[&] {
87
108
// Simplified ActivateBestChain(): Try to move to a chain with more work - with the possibility of finding blocks to be invalid on the way
88
109
LOCK (cs_main);
110
+ printf (" 2.Simplified ActivateBestChain()\n " );
89
111
auto & chain = chainman.ActiveChain ();
90
112
CBlockIndex* old_tip = chain.Tip ();
91
113
assert (old_tip);
@@ -95,21 +117,27 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
95
117
if (best_tip == chain.Tip ()) break ; // Nothing to do
96
118
// Rewind chain to forking point
97
119
const CBlockIndex* fork = chain.FindFork (best_tip);
120
+ printf (" fork (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , fork ->nHeight , fork ->GetBlockHash ().ToString ().c_str (), BlockStatusToString (fork ->nStatus ).c_str (), fork ->nChainWork .ToString ().c_str ());
98
121
// 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
99
122
// the node would currently just crash in this scenario (although this is very unlikely to happen due to the minimum pruning threshold of 550MiB).
100
123
CBlockIndex* it = chain.Tip ();
124
+ printf (" chain.Tip() (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , it->nHeight , it->GetBlockHash ().ToString ().c_str (), BlockStatusToString (it->nStatus ).c_str (), it->nChainWork .ToString ().c_str ());
125
+ printf (" we go back to fork point\n " );
101
126
bool pruned_block{false };
102
127
while (it && it->nHeight != fork ->nHeight ) {
103
128
if (!(it->nStatus & BLOCK_HAVE_UNDO) && it->nHeight > 0 ) {
104
129
assert (blockman.m_have_pruned );
105
130
pruned_block = true ;
131
+ printf (" pruned block, exit\n " );
106
132
break ;
107
133
}
108
134
it = it->pprev ;
109
135
}
110
136
if (pruned_block) break ;
111
137
112
138
chain.SetTip (*chain[fork ->nHeight ]);
139
+ it = chain.Tip ();
140
+ printf (" new chain.Tip() (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , it->nHeight , it->GetBlockHash ().ToString ().c_str (), BlockStatusToString (it->nStatus ).c_str (), it->nChainWork .ToString ().c_str ());
113
141
114
142
// Prepare new blocks to connect
115
143
std::vector<CBlockIndex*> to_connect;
@@ -119,21 +147,26 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
119
147
it = it->pprev ;
120
148
}
121
149
// Connect blocks, possibly fail
150
+ printf (" Loop through possible blocks to connect to (same as blocks from tip to fork)\n " );
122
151
for (CBlockIndex* block : to_connect | std::views::reverse) {
123
152
assert (!(block->nStatus & BLOCK_FAILED_MASK));
124
153
assert (block->nStatus & BLOCK_HAVE_DATA);
125
154
if (!block->IsValid (BLOCK_VALID_SCRIPTS)) {
155
+ printf (" block (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , block->nHeight , block->GetBlockHash ().ToString ().c_str (), BlockStatusToString (block->nStatus ).c_str (), block->nChainWork .ToString ().c_str ());
126
156
if (fuzzed_data_provider.ConsumeBool ()) { // Invalid
127
157
BlockValidationState state;
128
158
state.Invalid (BlockValidationResult::BLOCK_CONSENSUS, " consensus-invalid" );
129
159
chainman.ActiveChainstate ().InvalidBlockFound (block, state);
160
+ printf (" mark as invalid block and EXIT\n " );
130
161
break ;
131
162
} else {
132
163
block->RaiseValidity (BLOCK_VALID_SCRIPTS);
133
164
block->nStatus |= BLOCK_HAVE_UNDO;
165
+ printf (" mark as BLOCK_VALID_SCRIPTS and LOOP\n " );
134
166
}
135
167
}
136
168
chain.SetTip (*block);
169
+ printf (" set block as new tip\n " );
137
170
chainman.ActiveChainstate ().PruneBlockIndexCandidates ();
138
171
// 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.
139
172
if (block->nChainWork > old_tip->nChainWork && fuzzed_data_provider.ConsumeBool ()) {
@@ -142,15 +175,18 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
142
175
}
143
176
} while (node::CBlockIndexWorkComparator ()(chain.Tip (), old_tip));
144
177
assert (chain.Tip ()->nChainWork >= old_tip->nChainWork );
178
+ printf (" \n\n " );
145
179
},
146
180
[&] {
147
181
// Prune chain - dealing with block files is beyond the scope of this test, so just prune random blocks, making no assumptions what must
148
182
// be together in a block file.
149
183
// Also don't prune blocks outside of the chain for now - this would make the fuzzer crash because of the problem describted in
150
184
// https://github.com/bitcoin/bitcoin/issues/31512
151
185
LOCK (cs_main);
186
+ printf (" 4. Prune chain\n " );
152
187
auto & chain = chainman.ActiveChain ();
153
188
int prune_height = fuzzed_data_provider.ConsumeIntegralInRange <int >(0 , chain.Height ());
189
+ printf (" prune_height = %d\n " , prune_height);
154
190
CBlockIndex* prune_block{chain[prune_height]};
155
191
if (prune_block != chain.Tip ()) {
156
192
blockman.m_have_pruned = true ;
@@ -171,18 +207,26 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
171
207
},
172
208
[&] {
173
209
// InvalidateBlock
210
+ printf (" 5. Invalidateblock\n " );
174
211
CBlockIndex* prev_block = PickValue (fuzzed_data_provider, blocks);
212
+ printf (" block to invalidate (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , prev_block->nHeight , prev_block->GetBlockHash ().ToString ().c_str (), BlockStatusToString (prev_block->nStatus ).c_str (), prev_block->nChainWork .ToString ().c_str ());
175
213
BlockValidationState state;
176
214
chainman.ActiveChainstate ().InvalidateBlock (state, prev_block);
215
+ printf (" block after invalidation (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , prev_block->nHeight , prev_block->GetBlockHash ().ToString ().c_str (), BlockStatusToString (prev_block->nStatus ).c_str (), prev_block->nChainWork .ToString ().c_str ());
177
216
},
178
217
[&] {
179
218
// ReconsiderBlock
180
219
LOCK (cs_main);
220
+ printf (" 6. Reconsiderblock\n " );
181
221
CBlockIndex* prev_block = PickValue (fuzzed_data_provider, blocks);
222
+ printf (" block to reconsider (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , prev_block->nHeight , prev_block->GetBlockHash ().ToString ().c_str (), BlockStatusToString (prev_block->nStatus ).c_str (), prev_block->nChainWork .ToString ().c_str ());
182
223
chainman.ActiveChainstate ().ResetBlockFailureFlags (prev_block);
224
+ printf (" block after reconsider (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n " , prev_block->nHeight , prev_block->GetBlockHash ().ToString ().c_str (), BlockStatusToString (prev_block->nStatus ).c_str (), prev_block->nChainWork .ToString ().c_str ());
183
225
});
226
+ printf (" \n\n " );
184
227
}
185
228
chainman.CheckBlockIndex ();
229
+ printf (" END\n " );
186
230
187
231
// clean up global state changed by last iteration and prepare for next iteration
188
232
{
0 commit comments