Skip to content

Commit b7bdcf3

Browse files
committed
print statements to understand fuzz test
1 parent 13abf3f commit b7bdcf3

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

src/chain.h

+44
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,50 @@ enum BlockStatus : uint32_t {
132132
//!< ancestors before they were validated, and unset when they were validated.
133133
};
134134

135+
inline std::string BlockStatusToString(uint32_t status) {
136+
std::string s = "";
137+
if (status & BLOCK_STATUS_RESERVED){
138+
s += "BLOCK_STATUS_RESERVED, ";
139+
}
140+
if (status & BLOCK_OPT_WITNESS){
141+
s += "BLOCK_OPT_WITNESS, ";
142+
}
143+
if (status & BLOCK_FAILED_CHILD){
144+
s += "BLOCK_FAILED_CHILD, ";
145+
}
146+
if (status & BLOCK_FAILED_VALID){
147+
s += "BLOCK_FAILED_VALID, ";
148+
}
149+
if (status & BLOCK_HAVE_UNDO){
150+
s += "BLOCK_HAVE_UNDO, ";
151+
}
152+
if (status & BLOCK_HAVE_DATA){
153+
s += "BLOCK_HAVE_DATA, ";
154+
}
155+
if (status & BLOCK_VALID_SCRIPTS){
156+
s += "BLOCK_VALID_SCRIPTS, ";
157+
}
158+
if (status & BLOCK_VALID_CHAIN){
159+
s += "BLOCK_VALID_CHAIN, ";
160+
}
161+
if (status & BLOCK_VALID_TRANSACTIONS){
162+
s += "BLOCK_VALID_TRANSACTIONS, ";
163+
}
164+
if (status & BLOCK_VALID_TREE){
165+
s += "BLOCK_VALID_TREE, ";
166+
}
167+
if (status & BLOCK_VALID_RESERVED){
168+
s += "BLOCK_VALID_RESERVED, ";
169+
}
170+
if (status & BLOCK_VALID_UNKNOWN){
171+
s += "BLOCK_VALID_UNKNOWN, ";
172+
}
173+
if (s == ""){
174+
s += "uhmm UNKNOWN_BLOCK_STATUS";
175+
}
176+
return s;
177+
}
178+
135179
/** The block chain is a tree shaped structure starting with the
136180
* genesis block at the root, with each block potentially having multiple
137181
* candidates to be the next block. A blockindex may have multiple pprev pointing

src/test/fuzz/block_index_tree.cpp

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

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+
5054
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 1000)
5155
{
5256
CallOneOf(
5357
fuzzed_data_provider,
5458
[&] {
5559
// Receive a header building on an existing one. This assumes headers are valid, so PoW is not relevant here.
5660
LOCK(cs_main);
61+
printf("1. Receive header and build on existing one\n");
5762
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());
5864
if (!(prev_block->nStatus & BLOCK_FAILED_MASK)) {
5965
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());
6067
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());
6170
assert(index->nStatus & BLOCK_VALID_TREE);
6271
blocks.push_back(index);
72+
} else {
73+
printf("prev_block is BLOCK_FAILED_MASK, don't build on top of prev_block\n");
6374
}
75+
printf("\n\n");
6476
},
6577
[&] {
6678
// Receive a full block (valid or invalid) for an existing header, but don't attempt to connect it yet
6779
LOCK(cs_main);
80+
printf("2. Receive full block (valid or invalid) for an existing header but don't CONNECT\n");
6881
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());
6983
// Must be new to us and not known to be invalid (e.g. because of an invalid ancestor).
7084
if (index->nTx == 0 && !(index->nStatus & BLOCK_FAILED_MASK)) {
7185
if (fuzzed_data_provider.ConsumeBool()) { // Invalid
7286
BlockValidationState state;
7387
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "consensus-invalid");
7488
chainman.ActiveChainstate().InvalidBlockFound(index, state);
89+
printf("call InvalidBlockFound, index is now BLOCK_FAILED_VALID\n");
7590
} else {
7691
size_t nTx = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 1000);
7792
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)
8095
chainman.ReceivedBlockTransactions(block, index, pos);
8196
assert(index->nStatus & BLOCK_VALID_TRANSACTIONS);
8297
assert(index->nStatus & BLOCK_HAVE_DATA);
98+
printf("call ReceivedBlockTransactions, index is now BLOCK_VALID_TRANSACTIONS\n");
8399
}
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());
84104
}
105+
printf("\n\n");
85106
},
86107
[&] {
87108
// Simplified ActivateBestChain(): Try to move to a chain with more work - with the possibility of finding blocks to be invalid on the way
88109
LOCK(cs_main);
110+
printf("2.Simplified ActivateBestChain()\n");
89111
auto& chain = chainman.ActiveChain();
90112
CBlockIndex* old_tip = chain.Tip();
91113
assert(old_tip);
@@ -95,21 +117,27 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
95117
if (best_tip == chain.Tip()) break; // Nothing to do
96118
// Rewind chain to forking point
97119
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());
98121
// 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
99122
// the node would currently just crash in this scenario (although this is very unlikely to happen due to the minimum pruning threshold of 550MiB).
100123
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");
101126
bool pruned_block{false};
102127
while (it && it->nHeight != fork->nHeight) {
103128
if (!(it->nStatus & BLOCK_HAVE_UNDO) && it->nHeight > 0) {
104129
assert(blockman.m_have_pruned);
105130
pruned_block = true;
131+
printf("pruned block, exit\n");
106132
break;
107133
}
108134
it = it->pprev;
109135
}
110136
if (pruned_block) break;
111137

112138
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());
113141

114142
// Prepare new blocks to connect
115143
std::vector<CBlockIndex*> to_connect;
@@ -119,21 +147,26 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
119147
it = it->pprev;
120148
}
121149
// Connect blocks, possibly fail
150+
printf("Loop through possible blocks to connect to (same as blocks from tip to fork)\n");
122151
for (CBlockIndex* block : to_connect | std::views::reverse) {
123152
assert(!(block->nStatus & BLOCK_FAILED_MASK));
124153
assert(block->nStatus & BLOCK_HAVE_DATA);
125154
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());
126156
if (fuzzed_data_provider.ConsumeBool()) { // Invalid
127157
BlockValidationState state;
128158
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "consensus-invalid");
129159
chainman.ActiveChainstate().InvalidBlockFound(block, state);
160+
printf("mark as invalid block and EXIT\n");
130161
break;
131162
} else {
132163
block->RaiseValidity(BLOCK_VALID_SCRIPTS);
133164
block->nStatus |= BLOCK_HAVE_UNDO;
165+
printf("mark as BLOCK_VALID_SCRIPTS and LOOP\n");
134166
}
135167
}
136168
chain.SetTip(*block);
169+
printf("set block as new tip\n");
137170
chainman.ActiveChainstate().PruneBlockIndexCandidates();
138171
// 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.
139172
if (block->nChainWork > old_tip->nChainWork && fuzzed_data_provider.ConsumeBool()) {
@@ -142,15 +175,18 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
142175
}
143176
} while (node::CBlockIndexWorkComparator()(chain.Tip(), old_tip));
144177
assert(chain.Tip()->nChainWork >= old_tip->nChainWork);
178+
printf("\n\n");
145179
},
146180
[&] {
147181
// Prune chain - dealing with block files is beyond the scope of this test, so just prune random blocks, making no assumptions what must
148182
// be together in a block file.
149183
// Also don't prune blocks outside of the chain for now - this would make the fuzzer crash because of the problem describted in
150184
// https://github.com/bitcoin/bitcoin/issues/31512
151185
LOCK(cs_main);
186+
printf("4. Prune chain\n");
152187
auto& chain = chainman.ActiveChain();
153188
int prune_height = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, chain.Height());
189+
printf("prune_height = %d\n", prune_height);
154190
CBlockIndex* prune_block{chain[prune_height]};
155191
if (prune_block != chain.Tip()) {
156192
blockman.m_have_pruned = true;
@@ -171,18 +207,26 @@ FUZZ_TARGET(block_index_tree, .init = initialize_block_index_tree)
171207
},
172208
[&] {
173209
// InvalidateBlock
210+
printf("5. Invalidateblock\n");
174211
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());
175213
BlockValidationState state;
176214
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());
177216
},
178217
[&] {
179218
// ReconsiderBlock
180219
LOCK(cs_main);
220+
printf("6. Reconsiderblock\n");
181221
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());
182223
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());
183225
});
226+
printf("\n\n");
184227
}
185228
chainman.CheckBlockIndex();
229+
printf("END\n");
186230

187231
// clean up global state changed by last iteration and prepare for next iteration
188232
{

src/validation.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -5387,13 +5387,16 @@ void ChainstateManager::CheckBlockIndex()
53875387
if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) assert(pindexFirstNotScriptsValid == nullptr); // SCRIPTS valid implies all parents are SCRIPTS valid
53885388
if (pindexFirstInvalid == nullptr) {
53895389
// Checks for not-invalid blocks.
5390+
printf("pindexFirstInvalid == nullptr (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), BlockStatusToString(pindex->nStatus).c_str(), pindex->nChainWork.ToString().c_str());
53905391
assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents.
53915392
} else if (pindexFirstInvalid != pindex) {
53925393
// pindexFirstInvalid -> ...... -> pindex
53935394
// we check that descendants are BLOCK_FAILED_CHILD and not BLOCK_FAILED_VALID
5395+
printf("pindexFirstInvalid != pindex (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), BlockStatusToString(pindex->nStatus).c_str(), pindex->nChainWork.ToString().c_str());
53945396
assert((pindex->nStatus & BLOCK_FAILED_VALID) == 0);
53955397
assert(pindex->nStatus & BLOCK_FAILED_CHILD);
53965398
} else {
5399+
printf("pindexFirstInvalid == pindex (height = %d, block hash = %s, nStatus = %s, chainwork = %s)\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), BlockStatusToString(pindex->nStatus).c_str(), pindex->nChainWork.ToString().c_str());
53975400
assert(pindex->nStatus & BLOCK_FAILED_VALID);
53985401
assert((pindex->nStatus & BLOCK_FAILED_CHILD) == 0);
53995402
}

0 commit comments

Comments
 (0)