Skip to content

Commit 963aaa6

Browse files
author
Antoine Riard
committed
Add test_concurrent_monitor_claim
Watchower Alice receives block 134, broadcasts state X, rejects state Y. Watchtower Bob accepts state Y, receives blocks 135, broadcasts state Y. State Y confirms onchain. Alice must be able to claim outputs.
1 parent 1480262 commit 963aaa6

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

lightning/src/ln/functional_tests.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8736,3 +8736,115 @@ fn test_update_err_monitor_lockdown() {
87368736
let events = nodes[0].node.get_and_clear_pending_events();
87378737
assert_eq!(events.len(), 1);
87388738
}
8739+
8740+
#[test]
8741+
fn test_concurrent_monitor_claim() {
8742+
// Watchtower A receives block, broadcasts state N, then channel receives new state N+1,
8743+
// sending it to both watchtowers, Bob accepts N+1, then receives block and broadcasts
8744+
// the latest state N+1, Alice rejects state N+1, but Bob has already broadcast it,
8745+
// state N+1 confirms. Alice claims output from state N+1.
8746+
8747+
let chanmon_cfgs = create_chanmon_cfgs(2);
8748+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
8749+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
8750+
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
8751+
8752+
// Create some initial channel
8753+
let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
8754+
let outpoint = OutPoint { txid: chan_1.3.txid(), index: 0 };
8755+
8756+
// Rebalance the network to generate htlc in the two directions
8757+
send_payment(&nodes[0], &vec!(&nodes[1])[..], 10_000_000, 10_000_000);
8758+
8759+
// Route a HTLC from node 0 to node 1 (but don't settle)
8760+
route_payment(&nodes[0], &vec!(&nodes[1])[..], 9_000_000).0;
8761+
8762+
// Copy SimpleManyChannelMonitor to simulate watchtower Alice and update block height her ChannelMonitor timeout HTLC onchain
8763+
let logger = test_utils::TestLogger::with_id(format!("node {}", "Alice"));
8764+
let chain_monitor = chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet);
8765+
let watchtower_alice = {
8766+
let monitors = nodes[0].chan_monitor.simple_monitor.monitors.lock().unwrap();
8767+
let monitor = monitors.get(&outpoint).unwrap();
8768+
let mut w = test_utils::TestVecWriter(Vec::new());
8769+
monitor.write_for_disk(&mut w).unwrap();
8770+
let new_monitor = <(BlockHash, channelmonitor::ChannelMonitor<EnforcingChannelKeys>)>::read(
8771+
&mut ::std::io::Cursor::new(&w.0)).unwrap().1;
8772+
assert!(new_monitor == *monitor);
8773+
let watchtower = test_utils::TestChannelMonitor::new(&chain_monitor, &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator);
8774+
assert!(watchtower.add_monitor(outpoint, new_monitor).is_ok());
8775+
watchtower
8776+
};
8777+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
8778+
watchtower_alice.simple_monitor.block_connected(&header, 135, &vec![], &vec![]);
8779+
8780+
// Watchtower Alice should have broadcast a commitment/HTLC-timeout
8781+
{
8782+
let mut txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
8783+
assert_eq!(txn.len(), 2);
8784+
txn.clear();
8785+
}
8786+
8787+
// Copy SimpleManyChannelMonitor to simulate watchtower Bob and make it receive a commitment update first.
8788+
let logger = test_utils::TestLogger::with_id(format!("node {}", "Bob"));
8789+
let chain_monitor = chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet);
8790+
let watchtower_bob = {
8791+
let monitors = nodes[0].chan_monitor.simple_monitor.monitors.lock().unwrap();
8792+
let monitor = monitors.get(&outpoint).unwrap();
8793+
let mut w = test_utils::TestVecWriter(Vec::new());
8794+
monitor.write_for_disk(&mut w).unwrap();
8795+
let new_monitor = <(BlockHash, channelmonitor::ChannelMonitor<EnforcingChannelKeys>)>::read(
8796+
&mut ::std::io::Cursor::new(&w.0)).unwrap().1;
8797+
assert!(new_monitor == *monitor);
8798+
let watchtower = test_utils::TestChannelMonitor::new(&chain_monitor, &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator);
8799+
assert!(watchtower.add_monitor(outpoint, new_monitor).is_ok());
8800+
watchtower
8801+
};
8802+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
8803+
watchtower_bob.simple_monitor.block_connected(&header, 134, &vec![], &vec![]);
8804+
8805+
// Route another payment to generate another update with still previous HTLC pending
8806+
let (_, payment_hash) = get_payment_preimage_hash!(nodes[0]);
8807+
{
8808+
let net_graph_msg_handler = &nodes[1].net_graph_msg_handler;
8809+
let route = get_route(&nodes[1].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[0].node.get_our_node_id(), None, &Vec::new(), 3000000 , TEST_FINAL_CLTV, &logger).unwrap();
8810+
nodes[1].node.send_payment(&route, payment_hash, &None).unwrap();
8811+
}
8812+
check_added_monitors!(nodes[1], 1);
8813+
8814+
let updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
8815+
assert_eq!(updates.update_add_htlcs.len(), 1);
8816+
nodes[0].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &updates.update_add_htlcs[0]);
8817+
if let Some(ref mut channel) = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&chan_1.2) {
8818+
if let Ok((_, _, _, update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].fee_estimator, &node_cfgs[0].logger) {
8819+
// Watchtower Alice should already have seen the block and reject the update
8820+
if let Err(_) = watchtower_alice.simple_monitor.update_monitor(outpoint, update.clone()) {} else { assert!(false); }
8821+
if let Ok(_) = watchtower_bob.simple_monitor.update_monitor(outpoint, update.clone()) {} else { assert!(false); }
8822+
if let Ok(_) = nodes[0].chan_monitor.update_monitor(outpoint, update) {} else { assert!(false); }
8823+
} else { assert!(false); }
8824+
} else { assert!(false); };
8825+
// Our local monitor is in-sync and hasn't processed yet timeout
8826+
check_added_monitors!(nodes[0], 1);
8827+
8828+
//// Provide one more block to watchtower Bob, expect broadcast of commitment and HTLC-Timeout
8829+
watchtower_bob.simple_monitor.block_connected(&header, 135, &vec![], &vec![]);
8830+
8831+
// Watchtower Bob should have broadcast a commitment/HTLC-timeout
8832+
let bob_state_y;
8833+
{
8834+
let mut txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
8835+
assert_eq!(txn.len(), 2);
8836+
bob_state_y = txn[0].clone();
8837+
txn.clear();
8838+
};
8839+
8840+
// We confirm Bob's state Y on Alice, she should broadcast a HTLC-timeout
8841+
watchtower_alice.simple_monitor.block_connected(&header, 136, &vec![&bob_state_y][..], &vec![]);
8842+
{
8843+
let htlc_txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
8844+
// We broadcast twice the transaction, once due to the HTLC-timeout, once due
8845+
// the onchain detection of the HTLC output
8846+
assert_eq!(htlc_txn.len(), 2);
8847+
check_spends!(htlc_txn[0], bob_state_y);
8848+
check_spends!(htlc_txn[1], bob_state_y);
8849+
}
8850+
}

0 commit comments

Comments
 (0)