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