Test bwatch handles a 2-block reorg correctly
(node_factory, bitcoind)
| 5391 | |
| 5392 | @pytest.mark.slow_test |
| 5393 | def test_bwatch_reorg_2_blocks(node_factory, bitcoind): |
| 5394 | """Test bwatch handles a 2-block reorg correctly""" |
| 5395 | l1 = node_factory.get_node(options=BWATCH_OPTS) |
| 5396 | |
| 5397 | # Wait for bwatch to initialize |
| 5398 | wait_bwatch_caught_up(l1) |
| 5399 | |
| 5400 | # Mine some blocks |
| 5401 | bitcoind.generate_block(5) |
| 5402 | expected_height = bitcoind.rpc.getblockcount() |
| 5403 | l1.daemon.wait_for_log(rf'Added block {expected_height} to history') |
| 5404 | |
| 5405 | # Get the hash of block to reorg from (2 blocks back) |
| 5406 | height = bitcoind.rpc.getblockcount() |
| 5407 | old_block1_hash = bitcoind.rpc.getblockhash(height - 1) |
| 5408 | old_block2_hash = bitcoind.rpc.getblockhash(height) |
| 5409 | common_ancestor_hash = bitcoind.rpc.getblockhash(height - 2) |
| 5410 | |
| 5411 | # Invalidate to cause 2-block reorg |
| 5412 | bitcoind.rpc.invalidateblock(old_block1_hash) |
| 5413 | |
| 5414 | # Mine longer chain |
| 5415 | bitcoind.generate_block(4) |
| 5416 | time.sleep(2) |
| 5417 | |
| 5418 | # bwatch should detect and handle the reorg |
| 5419 | l1.daemon.wait_for_log(r'Reorg detected', timeout=60) |
| 5420 | # Wait for bwatch to finish processing the new chain |
| 5421 | l1.daemon.wait_for_log(r'No block change') |
| 5422 | |
| 5423 | # Verify bwatch's block history matches bitcoind's new chain |
| 5424 | new_height = bitcoind.rpc.getblockcount() |
| 5425 | |
| 5426 | # Check that bwatch has correct number of blocks (from its start height, not genesis) |
| 5427 | initial_height = 101 # regtest starts at this height |
| 5428 | expected_blocks = new_height - initial_height + 1 |
| 5429 | |
| 5430 | # Wait for datastore to be fully updated |
| 5431 | wait_for(lambda: len(l1.rpc.listdatastore(['bwatch', 'block_history'])['datastore']) == expected_blocks, timeout=60) |
| 5432 | |
| 5433 | ds = l1.rpc.listdatastore(['bwatch', 'block_history']) |
| 5434 | |
| 5435 | # Verify the common ancestor is still present with correct hash |
| 5436 | ancestor_entry = next((e for e in ds['datastore'] |
| 5437 | if e['key'][-1] == f"{height - 2:010d}"), None) |
| 5438 | assert ancestor_entry is not None |
| 5439 | assert reverse_bitcoin_hash(common_ancestor_hash) in str(ancestor_entry['hex']) |
| 5440 | |
| 5441 | # Verify the old block hashes are not in datastore |
| 5442 | for entry in ds['datastore']: |
| 5443 | assert reverse_bitcoin_hash(old_block1_hash) not in str(entry['hex']) |
| 5444 | assert reverse_bitcoin_hash(old_block2_hash) not in str(entry['hex']) |
| 5445 | |
| 5446 | # Verify the new tip matches bitcoind |
| 5447 | new_tip_hash = bitcoind.rpc.getblockhash(new_height) |
| 5448 | tip_entry = next((e for e in ds['datastore'] |
| 5449 | if e['key'][-1] == f"{new_height:010d}"), None) |
| 5450 | assert tip_entry is not None |
nothing calls this directly
no test coverage detected