Skip to content

Commit 4965f0a

Browse files
committed
merge bitcoin#27823: return error when block index is non-contiguous, fix feature_init.py file perturbation
1 parent 9d375af commit 4965f0a

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

src/node/blockstorage.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,13 @@ bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
289289
std::sort(vSortedByHeight.begin(), vSortedByHeight.end(),
290290
CBlockIndexHeightOnlyComparator());
291291

292+
CBlockIndex* previous_index{nullptr};
292293
for (CBlockIndex* pindex : vSortedByHeight) {
293294
if (ShutdownRequested()) return false;
295+
if (previous_index && pindex->nHeight > previous_index->nHeight + 1) {
296+
return error("%s: block index is non-contiguous, index of height %d missing", __func__, previous_index->nHeight + 1);
297+
}
298+
previous_index = pindex;
294299
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
295300
pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
296301

test/functional/feature_init.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""Stress tests related to node initialization."""
66
import os
77
from pathlib import Path
8+
import shutil
89

910
from test_framework.test_framework import BitcoinTestFramework, SkipTest
1011
from test_framework.test_node import ErrorMatch
@@ -44,7 +45,7 @@ def sigterm_node():
4445

4546
def start_expecting_error(err_fragment):
4647
node.assert_start_raises_init_error(
47-
extra_args=['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1'],
48+
extra_args=['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1', '-checkblocks=200', '-checklevel=4'],
4849
expected_msg=err_fragment,
4950
match=ErrorMatch.PARTIAL_REGEX,
5051
)
@@ -99,9 +100,9 @@ def check_clean_start():
99100
}
100101

101102
files_to_perturb = {
102-
'blocks/index/*.ldb': 'Error opening block database.',
103+
'blocks/index/*.ldb': 'Error loading block database.',
103104
'chainstate/*.ldb': 'Error opening block database.',
104-
'blocks/blk*.dat': 'Error opening block database.',
105+
'blocks/blk*.dat': 'Corrupted block database detected.',
105106
}
106107

107108
for file_patt, err_fragment in files_to_delete.items():
@@ -122,18 +123,31 @@ def check_clean_start():
122123
check_clean_start()
123124
self.stop_node(0)
124125

126+
self.log.info("Test startup errors after perturbing certain essential files")
125127
for file_patt, err_fragment in files_to_perturb.items():
128+
shutil.copytree(node.chain_path / "blocks", node.chain_path / "blocks_bak")
129+
shutil.copytree(node.chain_path / "chainstate", node.chain_path / "chainstate_bak")
126130
target_files = list(node.chain_path.glob(file_patt))
127131

128132
for target_file in target_files:
129133
self.log.info(f"Perturbing file to ensure failure {target_file}")
130-
with open(target_file, "rb") as tf_read, open(target_file, "wb") as tf_write:
134+
with open(target_file, "rb") as tf_read:
131135
contents = tf_read.read()
132136
tweaked_contents = bytearray(contents)
133-
tweaked_contents[50:250] = b'1' * 200
137+
# Since the genesis block is not checked by -checkblocks, the
138+
# perturbation window must be chosen such that a higher block
139+
# in blk*.dat is affected.
140+
tweaked_contents[150:350] = b'1' * 200
141+
with open(target_file, "wb") as tf_write:
134142
tf_write.write(bytes(tweaked_contents))
135143

136144
start_expecting_error(err_fragment)
137145

146+
shutil.rmtree(node.chain_path / "blocks")
147+
shutil.rmtree(node.chain_path / "chainstate")
148+
shutil.move(node.chain_path / "blocks_bak", node.chain_path / "blocks")
149+
shutil.move(node.chain_path / "chainstate_bak", node.chain_path / "chainstate")
150+
151+
138152
if __name__ == '__main__':
139153
InitStressTest().main()

0 commit comments

Comments
 (0)