MCPcopy Create free account
hub / github.com/ElementsProject/lightning / test_bwatch_reorg_1_block

Function test_bwatch_reorg_1_block

tests/test_plugin.py:5330–5389  ·  view source on GitHub ↗

Test bwatch handles a 1-block reorg correctly

(node_factory, bitcoind)

Source from the content-addressed store, hash-verified

5328
5329
5330def test_bwatch_reorg_1_block(node_factory, bitcoind):
5331 """Test bwatch handles a 1-block reorg correctly"""
5332 l1 = node_factory.get_node(options=BWATCH_OPTS)
5333
5334 # Wait for bwatch to initialize and sync to initial tip
5335 wait_bwatch_caught_up(l1)
5336
5337 # Mine a few blocks to establish history
5338 bitcoind.generate_block(5)
5339 # Wait for bwatch to fully catch up (important: bwatch must have the block
5340 # that will be reorged, otherwise it can't detect the reorg)
5341 l1.daemon.wait_for_log(r'No block change')
5342
5343 # Get the actual number of blocks bwatch has stored before reorg
5344 ds_before = l1.rpc.listdatastore(['bwatch', 'block_history'])
5345 blocks_before = len(ds_before['datastore'])
5346
5347 # Get the hash of the last block (the one we'll reorg out)
5348 height = bitcoind.rpc.getblockcount()
5349 old_block_hash = bitcoind.rpc.getblockhash(height)
5350 common_ancestor_hash = bitcoind.rpc.getblockhash(height - 1)
5351
5352 # Invalidate the last block (1-block reorg)
5353 bitcoind.rpc.invalidateblock(old_block_hash)
5354
5355 # Mine 2 new blocks on the new chain
5356 bitcoind.generate_block(2)
5357
5358 # bwatch should detect and handle the reorg
5359 l1.daemon.wait_for_log(r'Reorg detected', timeout=60)
5360 # Persisting rolled-forward blocks is async; don't assert immediately after
5361 # "Reorg detected" (see test_bwatch_reorg_2_blocks).
5362 l1.daemon.wait_for_log(r'No block change', timeout=60)
5363
5364 # Verify bwatch's block history matches bitcoind's new chain
5365 new_height = bitcoind.rpc.getblockcount()
5366 # After reorg: removed 1 old block, added 2 new blocks, so net +1
5367 wait_for(lambda: len(l1.rpc.listdatastore(['bwatch', 'block_history'])['datastore'])
5368 == blocks_before + 1,
5369 timeout=60)
5370
5371 ds = l1.rpc.listdatastore(['bwatch', 'block_history'])
5372
5373 # Verify the common ancestor is still present with correct hash
5374 ancestor_entry = next((e for e in ds['datastore']
5375 if e['key'][-1] == f"{height - 1:010d}"), None)
5376 assert ancestor_entry is not None
5377 # Decode the block record and verify hash matches
5378 assert reverse_bitcoin_hash(common_ancestor_hash) in str(ancestor_entry['hex'])
5379
5380 # Verify the old block hash is not in datastore
5381 for entry in ds['datastore']:
5382 assert reverse_bitcoin_hash(old_block_hash) not in str(entry['hex'])
5383
5384 # Verify the new tip matches bitcoind
5385 new_tip_hash = bitcoind.rpc.getblockhash(new_height)
5386 tip_entry = next((e for e in ds['datastore']
5387 if e['key'][-1] == f"{new_height:010d}"), None)

Callers

nothing calls this directly

Calls 8

wait_forFunction · 0.90
wait_bwatch_caught_upFunction · 0.85
nextFunction · 0.85
reverse_bitcoin_hashFunction · 0.85
generate_blockMethod · 0.80
wait_for_logMethod · 0.80
listdatastoreMethod · 0.80
get_nodeMethod · 0.45

Tested by

no test coverage detected