@@ -51,6 +51,7 @@ def skip_test_if_missing_module(self):
51
51
def run_test (self ):
52
52
self ._test_coin_stats_index ()
53
53
self ._test_use_index_option ()
54
+ self ._test_reorg_index ()
54
55
55
56
def block_sanity_check (self , block_info ):
56
57
block_subsidy = 50
@@ -247,6 +248,56 @@ def _test_use_index_option(self):
247
248
del res ['disk_size' ], option_res ['disk_size' ]
248
249
assert_equal (res , option_res )
249
250
251
+ def _test_reorg_index (self ):
252
+ self .log .info ("Test that index can handle reorgs" )
253
+
254
+ # Generate two block, let the index catch up, then invalidate the blocks
255
+ index_node = self .nodes [1 ]
256
+ reorg_blocks = index_node .generatetoaddress (2 , index_node .getnewaddress ())
257
+ reorg_block = reorg_blocks [1 ]
258
+ self .wait_until (lambda : not try_rpc (- 32603 , "Unable to read UTXO set" , index_node .gettxoutsetinfo , 'muhash' ))
259
+ res_invalid = index_node .gettxoutsetinfo ('muhash' )
260
+ index_node .invalidateblock (reorg_blocks [0 ])
261
+ assert_equal (index_node .gettxoutsetinfo ('muhash' )['height' ], 110 )
262
+
263
+ # Add two new blocks
264
+ block = index_node .generate (2 )[1 ]
265
+ self .wait_until (lambda : not try_rpc (- 32603 , "Unable to read UTXO set" , index_node .gettxoutsetinfo , 'muhash' ))
266
+ res = index_node .gettxoutsetinfo (hash_type = 'muhash' , hash_or_height = None , use_index = False )
267
+
268
+ # Test that the result of the reorged block is not returned for its old block height
269
+ res2 = index_node .gettxoutsetinfo (hash_type = 'muhash' , hash_or_height = 112 )
270
+ assert_equal (res ["bestblock" ], block )
271
+ assert_equal (res ["muhash" ], res2 ["muhash" ])
272
+ assert (res ["muhash" ] != res_invalid ["muhash" ])
273
+
274
+ # Test that requesting reorged out block by hash is still returning correct results
275
+ res_invalid2 = index_node .gettxoutsetinfo (hash_type = 'muhash' , hash_or_height = reorg_block )
276
+ assert_equal (res_invalid2 ["muhash" ], res_invalid ["muhash" ])
277
+ assert (res ["muhash" ] != res_invalid2 ["muhash" ])
278
+
279
+ # Add another block, so we don't depend on reconsiderblock remembering which
280
+ # blocks were touched by invalidateblock
281
+ index_node .generate (1 )
282
+
283
+ # Ensure that removing and re-adding blocks yields consistent results
284
+ block = index_node .getblockhash (99 )
285
+ index_node .invalidateblock (block )
286
+ self .wait_until (lambda : not try_rpc (- 32603 , "Unable to read UTXO set" , index_node .gettxoutsetinfo , 'muhash' ))
287
+ index_node .reconsiderblock (block )
288
+ self .wait_until (lambda : not try_rpc (- 32603 , "Unable to read UTXO set" , index_node .gettxoutsetinfo , 'muhash' ))
289
+ res3 = index_node .gettxoutsetinfo (hash_type = 'muhash' , hash_or_height = 112 )
290
+ assert_equal (res2 , res3 )
291
+
292
+ self .log .info ("Test that a node aware of stale blocks syncs them as well" )
293
+ node = self .nodes [0 ]
294
+ # Ensure the node is aware of a stale block prior to restart
295
+ node .getblock (reorg_block )
296
+
297
+ self .restart_node (0 , ["-coinstatsindex" ])
298
+ self .wait_until (lambda : not try_rpc (- 32603 , "Unable to read UTXO set" , node .gettxoutsetinfo , 'muhash' ))
299
+ assert_raises_rpc_error (- 32603 , "Unable to read UTXO set" , node .gettxoutsetinfo , 'muhash' , reorg_block )
300
+
250
301
251
302
if __name__ == '__main__' :
252
303
CoinStatsIndexTest ().main ()
0 commit comments