Test bwatch handles a longer reorg (5+ blocks)
(node_factory, bitcoind)
| 5452 | |
| 5453 | |
| 5454 | def test_bwatch_reorg_long_chain(node_factory, bitcoind): |
| 5455 | """Test bwatch handles a longer reorg (5+ blocks)""" |
| 5456 | l1 = node_factory.get_node(options=BWATCH_OPTS) |
| 5457 | |
| 5458 | # Wait for bwatch to initialize and sync to initial tip |
| 5459 | wait_bwatch_caught_up(l1) |
| 5460 | |
| 5461 | # Mine 10 blocks and wait for bwatch to fully catch up |
| 5462 | bitcoind.generate_block(10) |
| 5463 | expected_height = bitcoind.rpc.getblockcount() |
| 5464 | l1.daemon.wait_for_log(rf'Added block {expected_height} to history') |
| 5465 | |
| 5466 | # Reorg 5 blocks - save hashes of blocks that will be reorged out |
| 5467 | height = bitcoind.rpc.getblockcount() |
| 5468 | common_ancestor_height = height - 5 |
| 5469 | common_ancestor_hash = bitcoind.rpc.getblockhash(common_ancestor_height) |
| 5470 | old_hashes = [bitcoind.rpc.getblockhash(h) |
| 5471 | for h in range(common_ancestor_height + 1, height + 1)] |
| 5472 | |
| 5473 | reorg_from_hash = bitcoind.rpc.getblockhash( |
| 5474 | common_ancestor_height + 1) |
| 5475 | bitcoind.rpc.invalidateblock(reorg_from_hash) |
| 5476 | |
| 5477 | # Mine longer replacement chain |
| 5478 | bitcoind.generate_block(8) |
| 5479 | time.sleep(3) |
| 5480 | |
| 5481 | # Should handle the deep reorg |
| 5482 | l1.daemon.wait_for_log(r'Reorg detected') |
| 5483 | |
| 5484 | # Verify bwatch's block history matches bitcoind's new chain |
| 5485 | new_height = bitcoind.rpc.getblockcount() |
| 5486 | |
| 5487 | # Wait for bwatch to fully sync to the new chain height |
| 5488 | # bwatch stores blocks from initial height (101), not genesis |
| 5489 | initial_height = 101 # regtest starts at this height |
| 5490 | expected_blocks = new_height - initial_height + 1 |
| 5491 | wait_for(lambda: len(l1.rpc.listdatastore(['bwatch', 'block_history'])['datastore']) == expected_blocks) |
| 5492 | |
| 5493 | ds = l1.rpc.listdatastore(['bwatch', 'block_history']) |
| 5494 | |
| 5495 | # Check that bwatch has correct number of blocks |
| 5496 | assert len(ds['datastore']) == expected_blocks |
| 5497 | |
| 5498 | # Verify the common ancestor is still present with correct hash |
| 5499 | ancestor_entry = next((e for e in ds['datastore'] |
| 5500 | if e['key'][-1] == f"{common_ancestor_height:010d}"), |
| 5501 | None) |
| 5502 | assert ancestor_entry is not None |
| 5503 | assert reverse_bitcoin_hash(common_ancestor_hash) in str(ancestor_entry['hex']) |
| 5504 | |
| 5505 | # Verify none of the old block hashes are in datastore |
| 5506 | for entry in ds['datastore']: |
| 5507 | for old_hash in old_hashes: |
| 5508 | assert reverse_bitcoin_hash(old_hash) not in str(entry['hex']) |
| 5509 | |
| 5510 | # Verify the new tip matches bitcoind |
| 5511 | new_tip_hash = bitcoind.rpc.getblockhash(new_height) |
nothing calls this directly
no test coverage detected