Test that block history is correctly rolled back during reorg
(node_factory, bitcoind)
| 5556 | |
| 5557 | @pytest.mark.slow_test |
| 5558 | def test_bwatch_block_history_rollback(node_factory, bitcoind): |
| 5559 | """Test that block history is correctly rolled back during reorg""" |
| 5560 | l1 = node_factory.get_node(options=BWATCH_OPTS) |
| 5561 | |
| 5562 | # Wait for bwatch to fully sync |
| 5563 | wait_bwatch_caught_up(l1) |
| 5564 | |
| 5565 | # Mine blocks |
| 5566 | bitcoind.generate_block(5) |
| 5567 | expected_height = bitcoind.rpc.getblockcount() |
| 5568 | |
| 5569 | # Wait for bwatch to process the new blocks |
| 5570 | l1.daemon.wait_for_log(rf'Added block {expected_height} to history', timeout=60) |
| 5571 | |
| 5572 | # Check block history exists in datastore |
| 5573 | initial_height = 101 # regtest starts at this height |
| 5574 | expected_initial_blocks = expected_height - initial_height + 1 |
| 5575 | wait_for(lambda: len(l1.rpc.listdatastore(['bwatch', 'block_history'])['datastore']) == expected_initial_blocks, timeout=60) |
| 5576 | |
| 5577 | ds = l1.rpc.listdatastore(['bwatch', 'block_history']) |
| 5578 | initial_count = len(ds['datastore']) |
| 5579 | # bwatch stores blocks from its start height (101), so we should have at least 5 new blocks |
| 5580 | assert initial_count >= 5 |
| 5581 | |
| 5582 | # Cause a 3-block reorg - save hashes of blocks that will be reorged |
| 5583 | height = bitcoind.rpc.getblockcount() |
| 5584 | common_ancestor_height = height - 3 |
| 5585 | common_ancestor_hash = bitcoind.rpc.getblockhash(common_ancestor_height) |
| 5586 | old_hashes = [bitcoind.rpc.getblockhash(h) |
| 5587 | for h in range(common_ancestor_height + 1, height + 1)] |
| 5588 | |
| 5589 | reorg_from_hash = bitcoind.rpc.getblockhash( |
| 5590 | common_ancestor_height + 1) |
| 5591 | bitcoind.rpc.invalidateblock(reorg_from_hash) |
| 5592 | bitcoind.generate_block(5) |
| 5593 | |
| 5594 | # Verify reorg was handled |
| 5595 | l1.daemon.wait_for_log(r'Reorg detected', timeout=60) |
| 5596 | # Wait for bwatch to finish syncing to the new chain |
| 5597 | l1.daemon.wait_for_log(r'No block change') |
| 5598 | |
| 5599 | # Verify block history after reorg |
| 5600 | ds = l1.rpc.listdatastore(['bwatch', 'block_history']) |
| 5601 | new_height = bitcoind.rpc.getblockcount() |
| 5602 | |
| 5603 | # Should have correct number of blocks (from its start height, not genesis) |
| 5604 | initial_height = 101 # regtest starts at this height |
| 5605 | expected_blocks = new_height - initial_height + 1 |
| 5606 | assert len(ds['datastore']) == expected_blocks |
| 5607 | |
| 5608 | # Verify the common ancestor is still present with correct hash |
| 5609 | ancestor_entry = next((e for e in ds['datastore'] |
| 5610 | if e['key'][-1] == f"{common_ancestor_height:010d}"), |
| 5611 | None) |
| 5612 | assert ancestor_entry is not None |
| 5613 | assert reverse_bitcoin_hash(common_ancestor_hash) in str(ancestor_entry['hex']) |
| 5614 | |
| 5615 | # Verify old block hashes are not present |
nothing calls this directly
no test coverage detected