diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py index 030bf51ed86..191c6466df2 100755 --- a/test/functional/feature_index_prune.py +++ b/test/functional/feature_index_prune.py @@ -1,8 +1,9 @@ #!/usr/bin/env python3 -# Copyright (c) 2020-2022 The Bitcoin Core developers +# Copyright (c) 2020-present The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test indices in conjunction with prune.""" +import concurrent.futures import os from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -19,9 +20,25 @@ class FeatureIndexPruneTest(BitcoinTestFramework): ["-fastprune", "-prune=1", "-blockfilterindex=1"], ["-fastprune", "-prune=1", "-coinstatsindex=1"], ["-fastprune", "-prune=1", "-blockfilterindex=1", "-coinstatsindex=1"], - [] + [], ] + def setup_network(self): + self.setup_nodes() # No P2P connection, so that linear_sync works + + def linear_sync(self, node_from, *, height_from=None): + # Linear sync over RPC, because P2P sync may not be linear + to_height = node_from.getblockcount() + if height_from is None: + height_from = min([n.getblockcount() for n in self.nodes]) + 1 + with concurrent.futures.ThreadPoolExecutor(max_workers=self.num_nodes) as rpc_threads: + for i in range(height_from, to_height + 1): + b = node_from.getblock(blockhash=node_from.getblockhash(i), verbosity=0) + list(rpc_threads.map(lambda n: n.submitblock(b), self.nodes)) + + def generate(self, node, num_blocks, sync_fun=None): + return super().generate(node, num_blocks, sync_fun=sync_fun or (lambda: self.linear_sync(node))) + def sync_index(self, height): expected_filter = { 'basic block filter index': {'synced': True, 'best_block_height': height}, @@ -36,22 +53,9 @@ class FeatureIndexPruneTest(BitcoinTestFramework): expected = {**expected_filter, **expected_stats} self.wait_until(lambda: self.nodes[2].getindexinfo() == expected) - def reconnect_nodes(self): - self.connect_nodes(0,1) - self.connect_nodes(0,2) - self.connect_nodes(0,3) - - def mine_batches(self, blocks): - n = blocks // 250 - for _ in range(n): - self.generate(self.nodes[0], 250) - self.generate(self.nodes[0], blocks % 250) - self.sync_blocks() - def restart_without_indices(self): for i in range(3): self.restart_node(i, extra_args=["-fastprune", "-prune=1"]) - self.reconnect_nodes() def run_test(self): filter_nodes = [self.nodes[0], self.nodes[2]] @@ -65,7 +69,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework): for node in stats_nodes: assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash'] - self.mine_batches(500) + self.generate(self.nodes[0], 500) self.sync_index(height=700) self.log.info("prune some blocks") @@ -104,7 +108,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework): msg = "Querying specific block heights requires coinstatsindex" assert_raises_rpc_error(-8, msg, node.gettxoutsetinfo, "muhash", height_hash) - self.mine_batches(749) + self.generate(self.nodes[0], 749) self.log.info("prune exactly up to the indices best blocks while the indices are disabled") for i in range(3): @@ -118,7 +122,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework): self.log.info("prune further than the indices best blocks while the indices are disabled") self.restart_without_indices() - self.mine_batches(1000) + self.generate(self.nodes[0], 1000) for i in range(3): pruneheight_3 = self.nodes[i].pruneblockchain(2000) @@ -134,12 +138,10 @@ class FeatureIndexPruneTest(BitcoinTestFramework): self.log.info("make sure the nodes start again with the indices and an additional -reindex arg") for i in range(3): - restart_args = self.extra_args[i]+["-reindex"] + restart_args = self.extra_args[i] + ["-reindex"] self.restart_node(i, extra_args=restart_args) - # The nodes need to be reconnected to the non-pruning node upon restart, otherwise they will be stuck - self.connect_nodes(i, 3) - self.sync_blocks(timeout=300) + self.linear_sync(self.nodes[3]) self.sync_index(height=2500) for node in self.nodes[:2]: @@ -150,8 +152,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework): self.log.info("ensure that prune locks don't prevent indices from failing in a reorg scenario") with self.nodes[0].assert_debug_log(['basic block filter index prune lock moved back to 2480']): self.nodes[3].invalidateblock(self.nodes[0].getblockhash(2480)) - self.generate(self.nodes[3], 30) - self.sync_blocks() + self.generate(self.nodes[3], 30, sync_fun=lambda: self.linear_sync(self.nodes[3], height_from=2480)) if __name__ == '__main__':