1
1
#!/usr/bin/env python3
2
- # Copyright (c) 2020-2022 The Bitcoin Core developers
2
+ # Copyright (c) 2020-present The Bitcoin Core developers
3
3
# Distributed under the MIT software license, see the accompanying
4
4
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
5
"""Test indices in conjunction with prune."""
6
+ import concurrent .futures
6
7
import os
7
8
from test_framework .test_framework import BitcoinTestFramework
8
9
from test_framework .util import (
@@ -19,9 +20,25 @@ def set_test_params(self):
19
20
["-fastprune" , "-prune=1" , "-blockfilterindex=1" ],
20
21
["-fastprune" , "-prune=1" , "-coinstatsindex=1" ],
21
22
["-fastprune" , "-prune=1" , "-blockfilterindex=1" , "-coinstatsindex=1" ],
22
- []
23
+ [],
23
24
]
24
25
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
+
25
42
def sync_index (self , height ):
26
43
expected_filter = {
27
44
'basic block filter index' : {'synced' : True , 'best_block_height' : height },
@@ -36,22 +53,9 @@ def sync_index(self, height):
36
53
expected = {** expected_filter , ** expected_stats }
37
54
self .wait_until (lambda : self .nodes [2 ].getindexinfo () == expected )
38
55
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
-
51
56
def restart_without_indices (self ):
52
57
for i in range (3 ):
53
58
self .restart_node (i , extra_args = ["-fastprune" , "-prune=1" ])
54
- self .reconnect_nodes ()
55
59
56
60
def run_test (self ):
57
61
filter_nodes = [self .nodes [0 ], self .nodes [2 ]]
@@ -65,7 +69,7 @@ def run_test(self):
65
69
for node in stats_nodes :
66
70
assert node .gettxoutsetinfo (hash_type = "muhash" , hash_or_height = tip )['muhash' ]
67
71
68
- self .mine_batches ( 500 )
72
+ self .generate ( self . nodes [ 0 ], 500 )
69
73
self .sync_index (height = 700 )
70
74
71
75
self .log .info ("prune some blocks" )
@@ -104,7 +108,7 @@ def run_test(self):
104
108
msg = "Querying specific block heights requires coinstatsindex"
105
109
assert_raises_rpc_error (- 8 , msg , node .gettxoutsetinfo , "muhash" , height_hash )
106
110
107
- self .mine_batches ( 749 )
111
+ self .generate ( self . nodes [ 0 ], 749 )
108
112
109
113
self .log .info ("prune exactly up to the indices best blocks while the indices are disabled" )
110
114
for i in range (3 ):
@@ -118,7 +122,7 @@ def run_test(self):
118
122
119
123
self .log .info ("prune further than the indices best blocks while the indices are disabled" )
120
124
self .restart_without_indices ()
121
- self .mine_batches ( 1000 )
125
+ self .generate ( self . nodes [ 0 ], 1000 )
122
126
123
127
for i in range (3 ):
124
128
pruneheight_3 = self .nodes [i ].pruneblockchain (2000 )
@@ -134,12 +138,10 @@ def run_test(self):
134
138
135
139
self .log .info ("make sure the nodes start again with the indices and an additional -reindex arg" )
136
140
for i in range (3 ):
137
- restart_args = self .extra_args [i ]+ ["-reindex" ]
141
+ restart_args = self .extra_args [i ] + ["-reindex" ]
138
142
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 )
141
143
142
- self .sync_blocks ( timeout = 300 )
144
+ self .linear_sync ( self . nodes [ 3 ] )
143
145
self .sync_index (height = 2500 )
144
146
145
147
for node in self .nodes [:2 ]:
@@ -150,8 +152,7 @@ def run_test(self):
150
152
self .log .info ("ensure that prune locks don't prevent indices from failing in a reorg scenario" )
151
153
with self .nodes [0 ].assert_debug_log (['basic block filter index prune lock moved back to 2480' ]):
152
154
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 ))
155
156
156
157
157
158
if __name__ == '__main__' :
0 commit comments