Skip to content

Commit ba0cb7d

Browse files
committed
Merge bitcoin/bitcoin#31468: test: Avoid intermittent error in assert_equal(pruneheight_new, 248)
fa0998f test: Avoid intermittent error in assert_equal(pruneheight_new, 248) (MarcoFalke) Pull request description: Fixes bitcoin/bitcoin#31446 The test uses the P2P network to sync blocks, which has no inherent guarantee that the blocks are sent and received in the right order, assuming the headers are received first. This can mean that the first block file is flushed with block at height 249 and block at height 248 is added to the second file. In the log it looks like: `Leaving block file 0: CBlockFileInfo(blocks=249, size=65319, heights=0...249, time=2011-02-02...2024-12-03) (onto 1) (height 248)`. The test assumes that the height of the last pruned block in the first file is 248, expecting it to look like: `Leaving block file 0: CBlockFileInfo(blocks=249, size=65319, heights=0...248, time=2011-02-02...2024-12-09) (onto 1) (height 249) `. Fix the issue by using a linear dumb sync. ACKs for top commit: achow101: ACK fa0998f mzumsande: Code Review ACK fa0998f i-am-yuvi: Code Review ACK fa0998f fjahr: Code review ACK fa0998f Tree-SHA512: 59cb4317be6cf9012c9bf7a3e9f5ba96b8b114b30bd2ac42af4fe742cd26a634d685b075f04a84bd782b2a43a342d75bb20a042bd82ad2831dbf844d39517ca2
2 parents 69e35f5 + fa0998f commit ba0cb7d

File tree

1 file changed

+25
-24
lines changed

1 file changed

+25
-24
lines changed

test/functional/feature_index_prune.py

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#!/usr/bin/env python3
2-
# Copyright (c) 2020-2022 The Bitcoin Core developers
2+
# Copyright (c) 2020-present The Bitcoin Core developers
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test indices in conjunction with prune."""
6+
import concurrent.futures
67
import os
78
from test_framework.test_framework import BitcoinTestFramework
89
from test_framework.util import (
@@ -19,9 +20,25 @@ def set_test_params(self):
1920
["-fastprune", "-prune=1", "-blockfilterindex=1"],
2021
["-fastprune", "-prune=1", "-coinstatsindex=1"],
2122
["-fastprune", "-prune=1", "-blockfilterindex=1", "-coinstatsindex=1"],
22-
[]
23+
[],
2324
]
2425

26+
def setup_network(self):
27+
self.setup_nodes() # No P2P connection, so that linear_sync works
28+
29+
def linear_sync(self, node_from, *, height_from=None):
30+
# Linear sync over RPC, because P2P sync may not be linear
31+
to_height = node_from.getblockcount()
32+
if height_from is None:
33+
height_from = min([n.getblockcount() for n in self.nodes]) + 1
34+
with concurrent.futures.ThreadPoolExecutor(max_workers=self.num_nodes) as rpc_threads:
35+
for i in range(height_from, to_height + 1):
36+
b = node_from.getblock(blockhash=node_from.getblockhash(i), verbosity=0)
37+
list(rpc_threads.map(lambda n: n.submitblock(b), self.nodes))
38+
39+
def generate(self, node, num_blocks, sync_fun=None):
40+
return super().generate(node, num_blocks, sync_fun=sync_fun or (lambda: self.linear_sync(node)))
41+
2542
def sync_index(self, height):
2643
expected_filter = {
2744
'basic block filter index': {'synced': True, 'best_block_height': height},
@@ -36,22 +53,9 @@ def sync_index(self, height):
3653
expected = {**expected_filter, **expected_stats}
3754
self.wait_until(lambda: self.nodes[2].getindexinfo() == expected)
3855

39-
def reconnect_nodes(self):
40-
self.connect_nodes(0,1)
41-
self.connect_nodes(0,2)
42-
self.connect_nodes(0,3)
43-
44-
def mine_batches(self, blocks):
45-
n = blocks // 250
46-
for _ in range(n):
47-
self.generate(self.nodes[0], 250)
48-
self.generate(self.nodes[0], blocks % 250)
49-
self.sync_blocks()
50-
5156
def restart_without_indices(self):
5257
for i in range(3):
5358
self.restart_node(i, extra_args=["-fastprune", "-prune=1"])
54-
self.reconnect_nodes()
5559

5660
def run_test(self):
5761
filter_nodes = [self.nodes[0], self.nodes[2]]
@@ -65,7 +69,7 @@ def run_test(self):
6569
for node in stats_nodes:
6670
assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash']
6771

68-
self.mine_batches(500)
72+
self.generate(self.nodes[0], 500)
6973
self.sync_index(height=700)
7074

7175
self.log.info("prune some blocks")
@@ -104,7 +108,7 @@ def run_test(self):
104108
msg = "Querying specific block heights requires coinstatsindex"
105109
assert_raises_rpc_error(-8, msg, node.gettxoutsetinfo, "muhash", height_hash)
106110

107-
self.mine_batches(749)
111+
self.generate(self.nodes[0], 749)
108112

109113
self.log.info("prune exactly up to the indices best blocks while the indices are disabled")
110114
for i in range(3):
@@ -118,7 +122,7 @@ def run_test(self):
118122

119123
self.log.info("prune further than the indices best blocks while the indices are disabled")
120124
self.restart_without_indices()
121-
self.mine_batches(1000)
125+
self.generate(self.nodes[0], 1000)
122126

123127
for i in range(3):
124128
pruneheight_3 = self.nodes[i].pruneblockchain(2000)
@@ -134,12 +138,10 @@ def run_test(self):
134138

135139
self.log.info("make sure the nodes start again with the indices and an additional -reindex arg")
136140
for i in range(3):
137-
restart_args = self.extra_args[i]+["-reindex"]
141+
restart_args = self.extra_args[i] + ["-reindex"]
138142
self.restart_node(i, extra_args=restart_args)
139-
# The nodes need to be reconnected to the non-pruning node upon restart, otherwise they will be stuck
140-
self.connect_nodes(i, 3)
141143

142-
self.sync_blocks(timeout=300)
144+
self.linear_sync(self.nodes[3])
143145
self.sync_index(height=2500)
144146

145147
for node in self.nodes[:2]:
@@ -150,8 +152,7 @@ def run_test(self):
150152
self.log.info("ensure that prune locks don't prevent indices from failing in a reorg scenario")
151153
with self.nodes[0].assert_debug_log(['basic block filter index prune lock moved back to 2480']):
152154
self.nodes[3].invalidateblock(self.nodes[0].getblockhash(2480))
153-
self.generate(self.nodes[3], 30)
154-
self.sync_blocks()
155+
self.generate(self.nodes[3], 30, sync_fun=lambda: self.linear_sync(self.nodes[3], height_from=2480))
155156

156157

157158
if __name__ == '__main__':

0 commit comments

Comments
 (0)