Describe the bug
When Emitter cannot find any caller-provided checkpoint on the RPC node, it silently replaces its checkpoint chain with the node's genesis and continues emitting blocks. This happens with an ordinary wrong-network configuration, such as mainnet checkpoints connected to a regtest node.
The emitted checkpoints no longer connect to the supplied chain, contrary to BlockEvent::checkpoint's documented guarantee. LocalChain::apply_update rejects them, but the emitter has already switched its internal chain without reporting the mismatch.
This issue was found by AI.
To Reproduce
- Run a regtest Bitcoin Core node with at least one mined block.
- Create a
LocalChain from mainnet genesis and pass its tip to Emitter::new with that node's RPC client, start_height = 1, and NO_EXPECTED_MEMPOOL_TXS.
- Call
next_block(). It returns a regtest block instead of reporting the network mismatch. Its checkpoint chain ends at regtest genesis, and connected_to() points to that genesis.
- Apply the emitted checkpoint to the original
LocalChain; it returns CannotConnectError at height 0.
Confirmed with an RPC stub returning -5 for the caller's genesis and serving a chain rooted at a different genesis.
Expected behavior
An endpoint on a different network should not silently replace the caller's chain root or produce events that violate the documented connection guarantee.
Describe the bug
When
Emittercannot find any caller-provided checkpoint on the RPC node, it silently replaces its checkpoint chain with the node's genesis and continues emitting blocks. This happens with an ordinary wrong-network configuration, such as mainnet checkpoints connected to a regtest node.The emitted checkpoints no longer connect to the supplied chain, contrary to
BlockEvent::checkpoint's documented guarantee.LocalChain::apply_updaterejects them, but the emitter has already switched its internal chain without reporting the mismatch.This issue was found by AI.
To Reproduce
LocalChainfrom mainnet genesis and pass its tip toEmitter::newwith that node's RPC client,start_height = 1, andNO_EXPECTED_MEMPOOL_TXS.next_block(). It returns a regtest block instead of reporting the network mismatch. Its checkpoint chain ends at regtest genesis, andconnected_to()points to that genesis.LocalChain; it returnsCannotConnectErrorat height 0.Confirmed with an RPC stub returning
-5for the caller's genesis and serving a chain rooted at a different genesis.Expected behavior
An endpoint on a different network should not silently replace the caller's chain root or produce events that violate the documented connection guarantee.