assert_eq!(nodes[1].node.list_channels().len(), 0);
}
+ #[test]
+ fn test_htlc_on_chain_success() {
+ // Test that in case of an unilateral close onchain, we detect the state of output thanks to
+ // ChainWatchInterface and pass the preimage backward accordingly. So here we test that ChannelManager is
+ // broadcasting the right event to other nodes in payment path.
+ // A --------------------> B ----------------------> C (preimage)
+ // First, C should claim the HTLC output via HTLC-Success when its own latest local
+ // commitment transaction was broadcast.
+ // Then, B should learn the preimage from said transactions, attempting to claim backwards
+ // towards B.
+ // B should be able to claim via preimage if A then broadcasts its local tx.
+ // Finally, when A sees B's latest local commitment transaction it should be able to claim
+ // the HTLC output via the preimage it learned (which, once confirmed should generate a
+ // PaymentSent event).
+
+ let nodes = create_network(3);
+
+ // Create some initial channels
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2);
+
+ // Rebalance the network a bit by relaying one payment through all the channels...
+ send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
+ send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
+
+ let (our_payment_preimage, _payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), 3000000);
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
+
+ // Broadcast legit commitment tx from C on B's chain
+ // Broadcast HTLC Success transation by C on received output from C's commitment tx on B's chain
+ let commitment_tx = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone();
+ assert_eq!(commitment_tx.len(), 1);
+ check_spends!(commitment_tx[0], chan_2.3.clone());
+ nodes[2].node.claim_funds(our_payment_preimage);
+ check_added_monitors!(nodes[2], 1);
+ let updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
+ assert!(updates.update_add_htlcs.is_empty());
+ assert!(updates.update_fail_htlcs.is_empty());
+ assert!(updates.update_fail_malformed_htlcs.is_empty());
+ assert_eq!(updates.update_fulfill_htlcs.len(), 1);
+
+ nodes[2].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1);
+ let events = nodes[2].node.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+ let node_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 1 (commitment tx), ChannelMonitor : 2 (2 * HTLC-Success tx)
+ assert_eq!(node_txn.len(), 3);
+ assert_eq!(node_txn[1], commitment_tx[0]);
+ assert_eq!(node_txn[0], node_txn[2]);
+ check_spends!(node_txn[0], commitment_tx[0].clone());
+ assert_eq!(node_txn[0].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ assert!(node_txn[0].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
+ assert_eq!(node_txn[0].lock_time, 0);
+
+ // Verify that B's ChannelManager is able to extract preimage from HTLC Success tx and pass it backward
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: node_txn}, 1);
+ let events = nodes[1].node.get_and_clear_pending_msg_events();
+ {
+ let mut added_monitors = nodes[1].chan_monitor.added_monitors.lock().unwrap();
+ assert_eq!(added_monitors.len(), 1);
+ assert_eq!(added_monitors[0].0.txid, chan_1.3.txid());
+ added_monitors.clear();
+ }
+ assert_eq!(events.len(), 2);
+ match events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+ match events[1] {
+ MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => {
+ assert!(update_add_htlcs.is_empty());
+ assert!(update_fail_htlcs.is_empty());
+ assert_eq!(update_fulfill_htlcs.len(), 1);
+ assert!(update_fail_malformed_htlcs.is_empty());
+ assert_eq!(nodes[0].node.get_our_node_id(), *node_id);
+ },
+ _ => panic!("Unexpected event"),
+ };
+ {
+ // nodes[1] now broadcasts its own local state as a fallback, suggesting an alternate
+ // commitment transaction with a corresponding HTLC-Timeout transaction, as well as a
+ // timeout-claim of the output that nodes[2] just claimed via success.
+ let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 1 (timeout tx) * 2 (block-rescan)
+ assert_eq!(node_txn.len(), 4);
+ assert_eq!(node_txn[0], node_txn[3]);
+ check_spends!(node_txn[0], commitment_tx[0].clone());
+ assert_eq!(node_txn[0].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ assert_ne!(node_txn[0].lock_time, 0);
+ assert!(node_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
+ check_spends!(node_txn[1], chan_2.3.clone());
+ check_spends!(node_txn[2], node_txn[1].clone());
+ assert_eq!(node_txn[1].input[0].witness.clone().last().unwrap().len(), 71);
+ assert_eq!(node_txn[2].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ assert!(node_txn[2].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
+ assert_ne!(node_txn[2].lock_time, 0);
+ node_txn.clear();
+ }
+
+ // Broadcast legit commitment tx from A on B's chain
+ // Broadcast preimage tx by B on offered output from A commitment tx on A's chain
+ let commitment_tx = nodes[0].node.channel_state.lock().unwrap().by_id.get(&chan_1.2).unwrap().last_local_commitment_txn.clone();
+ check_spends!(commitment_tx[0], chan_1.3.clone());
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1);
+ let events = nodes[1].node.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+ let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 1 (commitment tx), ChannelMonitor : 1 (HTLC-Success) * 2 (block-rescan)
+ assert_eq!(node_txn.len(), 3);
+ assert_eq!(node_txn[0], node_txn[2]);
+ check_spends!(node_txn[0], commitment_tx[0].clone());
+ assert_eq!(node_txn[0].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ assert_eq!(node_txn[0].lock_time, 0);
+ assert!(node_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
+ check_spends!(node_txn[1], chan_1.3.clone());
+ assert_eq!(node_txn[1].input[0].witness.clone().last().unwrap().len(), 71);
+ // We don't bother to check that B can claim the HTLC output on its commitment tx here as
+ // we already checked the same situation with A.
+
+ // Verify that A's ChannelManager is able to extract preimage from preimage tx and generate PaymentSent
+ nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone(), node_txn[0].clone()] }, 1);
+ let events = nodes[0].node.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+ let events = nodes[0].node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ Event::PaymentSent { payment_preimage } => {
+ assert_eq!(payment_preimage, our_payment_preimage);
+ },
+ _ => panic!("Unexpected event"),
+ }
+ let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 1 (HTLC-Timeout tx) * 2 (block-rescan)
+ assert_eq!(node_txn.len(), 4);
+ assert_eq!(node_txn[0], node_txn[3]);
+ check_spends!(node_txn[0], commitment_tx[0].clone());
+ assert_eq!(node_txn[0].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ assert_ne!(node_txn[0].lock_time, 0);
+ assert!(node_txn[0].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
+ check_spends!(node_txn[1], chan_1.3.clone());
+ check_spends!(node_txn[2], node_txn[1].clone());
+ assert_eq!(node_txn[1].input[0].witness.clone().last().unwrap().len(), 71);
+ assert_eq!(node_txn[2].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ assert!(node_txn[2].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
+ assert_ne!(node_txn[2].lock_time, 0);
+ }
+
+ #[test]
+ fn test_htlc_on_chain_timeout() {
+ // Test that in case of an unilateral close onchain, we detect the state of output thanks to
+ // ChainWatchInterface and timeout the HTLC bacward accordingly. So here we test that ChannelManager is
+ // broadcasting the right event to other nodes in payment path.
+ // A ------------------> B ----------------------> C (timeout)
+ // B's commitment tx C's commitment tx
+ // \ \
+ // B's HTLC timeout tx B's timeout tx
+
+ let nodes = create_network(3);
+
+ // Create some intial channels
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2);
+
+ // Rebalance the network a bit by relaying one payment thorugh all the channels...
+ send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
+ send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
+
+ let (_payment_preimage, payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), 3000000);
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
+
+ // Brodacast legit commitment tx from C on B's chain
+ let commitment_tx = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone();
+ check_spends!(commitment_tx[0], chan_2.3.clone());
+ nodes[2].node.fail_htlc_backwards(&payment_hash, PaymentFailReason::PreimageUnknown);
+ {
+ let mut added_monitors = nodes[2].chan_monitor.added_monitors.lock().unwrap();
+ assert_eq!(added_monitors.len(), 1);
+ added_monitors.clear();
+ }
+ let events = nodes[2].node.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => {
+ assert!(update_add_htlcs.is_empty());
+ assert!(!update_fail_htlcs.is_empty());
+ assert!(update_fulfill_htlcs.is_empty());
+ assert!(update_fail_malformed_htlcs.is_empty());
+ assert_eq!(nodes[1].node.get_our_node_id(), *node_id);
+ },
+ _ => panic!("Unexpected event"),
+ };
+ nodes[2].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1);
+ let events = nodes[2].node.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { msg: msgs::ChannelUpdate { .. } } => {},
+ _ => panic!("Unexpected event"),
+ }
+ let node_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 1 (commitment tx)
+ assert_eq!(node_txn.len(), 1);
+ check_spends!(node_txn[0], chan_2.3.clone());
+ assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), 71);
+
+ // Broadcast timeout transaction by B on received output fron C's commitment tx on B's chain
+ // Verify that B's ChannelManager is able to detect that HTLC is timeout by its own tx and react backward in consequence
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 200);
+ let timeout_tx;
+ {
+ let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
+ assert_eq!(node_txn.len(), 8); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 6 (HTLC-Timeout tx, commitment tx, timeout tx) * 2 (block-rescan)
+ assert_eq!(node_txn[0], node_txn[5]);
+ assert_eq!(node_txn[1], node_txn[6]);
+ assert_eq!(node_txn[2], node_txn[7]);
+ check_spends!(node_txn[0], commitment_tx[0].clone());
+ assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ check_spends!(node_txn[1], chan_2.3.clone());
+ check_spends!(node_txn[2], node_txn[1].clone());
+ assert_eq!(node_txn[1].clone().input[0].witness.last().unwrap().len(), 71);
+ assert_eq!(node_txn[2].clone().input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ check_spends!(node_txn[3], chan_2.3.clone());
+ check_spends!(node_txn[4], node_txn[3].clone());
+ assert_eq!(node_txn[3].input[0].witness.clone().last().unwrap().len(), 71);
+ assert_eq!(node_txn[4].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ timeout_tx = node_txn[0].clone();
+ node_txn.clear();
+ }
+
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![timeout_tx]}, 1);
+ let events = nodes[1].node.get_and_clear_pending_msg_events();
+ check_added_monitors!(nodes[1], 1);
+ assert_eq!(events.len(), 2);
+ match events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { msg: msgs::ChannelUpdate { .. } } => {},
+ _ => panic!("Unexpected event"),
+ }
+ match events[1] {
+ MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => {
+ assert!(update_add_htlcs.is_empty());
+ assert!(!update_fail_htlcs.is_empty());
+ assert!(update_fulfill_htlcs.is_empty());
+ assert!(update_fail_malformed_htlcs.is_empty());
+ assert_eq!(nodes[0].node.get_our_node_id(), *node_id);
+ },
+ _ => panic!("Unexpected event"),
+ };
+ let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // Well... here we detect our own htlc_timeout_tx so no tx to be generated
+ assert_eq!(node_txn.len(), 0);
+
+ // Broadcast legit commitment tx from B on A's chain
+ let commitment_tx = nodes[1].node.channel_state.lock().unwrap().by_id.get(&chan_1.2).unwrap().last_local_commitment_txn.clone();
+ check_spends!(commitment_tx[0], chan_1.3.clone());
+
+ nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 200);
+ let events = nodes[0].node.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { msg: msgs::ChannelUpdate { .. } } => {},
+ _ => panic!("Unexpected event"),
+ }
+ let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 2 (timeout tx) * 2 block-rescan
+ assert_eq!(node_txn.len(), 4);
+ assert_eq!(node_txn[0], node_txn[3]);
+ check_spends!(node_txn[0], commitment_tx[0].clone());
+ assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ check_spends!(node_txn[1], chan_1.3.clone());
+ check_spends!(node_txn[2], node_txn[1].clone());
+ assert_eq!(node_txn[1].clone().input[0].witness.last().unwrap().len(), 71);
+ assert_eq!(node_txn[2].clone().input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ }
+
+ #[test]
+ fn test_simple_commitment_revoked_fail_backward() {
+ // Test that in case of a revoked commitment tx, we detect the resolution of output by justice tx
+ // and fail backward accordingly.
+
+ let nodes = create_network(3);
+
+ // Create some initial channels
+ create_announced_chan_between_nodes(&nodes, 0, 1);
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2);
+
+ let (payment_preimage, _payment_hash) = route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 3000000);
+ // Get the will-be-revoked local txn from nodes[2]
+ let revoked_local_txn = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone();
+ // Revoke the old state
+ claim_payment(&nodes[0], &[&nodes[1], &nodes[2]], payment_preimage);
+
+ route_payment(&nodes[0], &[&nodes[1], &nodes[2]], 3000000);
+
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
+ let events = nodes[1].node.get_and_clear_pending_msg_events();
+ check_added_monitors!(nodes[1], 1);
+ assert_eq!(events.len(), 2);
+ match events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { msg: msgs::ChannelUpdate { .. } } => {},
+ _ => panic!("Unexpected event"),
+ }
+ match events[1] {
+ MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, ref commitment_signed, .. } } => {
+ assert!(update_add_htlcs.is_empty());
+ assert_eq!(update_fail_htlcs.len(), 1);
+ assert!(update_fulfill_htlcs.is_empty());
+ assert!(update_fail_malformed_htlcs.is_empty());
+ assert_eq!(nodes[0].node.get_our_node_id(), *node_id);
+
+ nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &update_fail_htlcs[0]).unwrap();
+ commitment_signed_dance!(nodes[0], nodes[1], commitment_signed, false, true);
+
+ let events = nodes[0].node.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ MessageSendEvent::PaymentFailureNetworkUpdate { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+ let events = nodes[0].node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ Event::PaymentFailed { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+ },
+ _ => panic!("Unexpected event"),
+ }
+ }
+
#[test]
fn test_htlc_ignore_latest_remote_commitment() {
// Test that HTLC transactions spending the latest remote commitment transaction are simply
check_spends!(spend_txn[4], node_txn[3].clone()); // spending justice tx output on htlc success tx
}
+ #[test]
+ fn test_onchain_to_onchain_claim() {
+ // Test that in case of channel closure, we detect the state of output thanks to
+ // ChainWatchInterface and claim HTLC on downstream peer's remote commitment tx.
+ // First, have C claim an HTLC against its own latest commitment transaction.
+ // Then, broadcast these to B, which should update the monitor downstream on the A<->B
+ // channel.
+ // Finally, check that B will claim the HTLC output if A's latest commitment transaction
+ // gets broadcast.
+
+ let nodes = create_network(3);
+
+ // Create some initial channels
+ let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2);
+
+ // Rebalance the network a bit by relaying one payment through all the channels ...
+ send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
+ send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000);
+
+ let (payment_preimage, _payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), 3000000);
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42};
+ let commitment_tx = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone();
+ check_spends!(commitment_tx[0], chan_2.3.clone());
+ nodes[2].node.claim_funds(payment_preimage);
+ check_added_monitors!(nodes[2], 1);
+ let updates = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id());
+ assert!(updates.update_add_htlcs.is_empty());
+ assert!(updates.update_fail_htlcs.is_empty());
+ assert_eq!(updates.update_fulfill_htlcs.len(), 1);
+ assert!(updates.update_fail_malformed_htlcs.is_empty());
+
+ nodes[2].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1);
+ let events = nodes[2].node.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+
+ let c_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 2 (commitment tx, HTLC-Success tx), ChannelMonitor : 1 (HTLC-Success tx)
+ assert_eq!(c_txn.len(), 3);
+ assert_eq!(c_txn[0], c_txn[2]);
+ assert_eq!(commitment_tx[0], c_txn[1]);
+ check_spends!(c_txn[1], chan_2.3.clone());
+ check_spends!(c_txn[2], c_txn[1].clone());
+ assert_eq!(c_txn[1].input[0].witness.clone().last().unwrap().len(), 71);
+ assert_eq!(c_txn[2].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ assert!(c_txn[0].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
+ assert_eq!(c_txn[0].lock_time, 0); // Success tx
+
+ // So we broadcast C's commitment tx and HTLC-Success on B's chain, we should successfully be able to extract preimage and update downstream monitor
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![c_txn[1].clone(), c_txn[2].clone()]}, 1);
+ {
+ let mut b_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
+ assert_eq!(b_txn.len(), 4);
+ assert_eq!(b_txn[0], b_txn[3]);
+ check_spends!(b_txn[1], chan_2.3); // B local commitment tx, issued by ChannelManager
+ check_spends!(b_txn[2], b_txn[1].clone()); // HTLC-Timeout on B local commitment tx, issued by ChannelManager
+ assert_eq!(b_txn[2].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ assert!(b_txn[2].output[0].script_pubkey.is_v0_p2wsh()); // revokeable output
+ assert_ne!(b_txn[2].lock_time, 0); // Timeout tx
+ check_spends!(b_txn[0], c_txn[1].clone()); // timeout tx on C remote commitment tx, issued by ChannelMonitor, * 2 due to block rescan
+ assert_eq!(b_txn[0].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ assert!(b_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
+ assert_ne!(b_txn[2].lock_time, 0); // Timeout tx
+ b_txn.clear();
+ }
+ let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
+ check_added_monitors!(nodes[1], 1);
+ match msg_events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+ match msg_events[1] {
+ MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => {
+ assert!(update_add_htlcs.is_empty());
+ assert!(update_fail_htlcs.is_empty());
+ assert_eq!(update_fulfill_htlcs.len(), 1);
+ assert!(update_fail_malformed_htlcs.is_empty());
+ assert_eq!(nodes[0].node.get_our_node_id(), *node_id);
+ },
+ _ => panic!("Unexpected event"),
+ };
+ // Broadcast A's commitment tx on B's chain to see if we are able to claim inbound HTLC with our HTLC-Success tx
+ let commitment_tx = nodes[0].node.channel_state.lock().unwrap().by_id.get(&chan_1.2).unwrap().last_local_commitment_txn.clone();
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1);
+ let b_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
+ assert_eq!(b_txn.len(), 3);
+ check_spends!(b_txn[1], chan_1.3); // Local commitment tx, issued by ChannelManager
+ assert_eq!(b_txn[0], b_txn[2]); // HTLC-Success tx, issued by ChannelMonitor, * 2 due to block rescan
+ check_spends!(b_txn[0], commitment_tx[0].clone());
+ assert_eq!(b_txn[0].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
+ assert!(b_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
+ assert_eq!(b_txn[2].lock_time, 0); // Success tx
+ let msg_events = nodes[1].node.get_and_clear_pending_msg_events();
+ match msg_events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+ }
+
+ #[test]
+ fn test_duplicate_payment_hash_one_failure_one_success() {
+ // Topology : A --> B --> C
+ // We route 2 payments with same hash between B and C, one will be timeout, the other successfully claim
+ let mut nodes = create_network(3);
+
+ create_announced_chan_between_nodes(&nodes, 0, 1);
+ let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2);
+
+ let (our_payment_preimage, duplicate_payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 900000);
+ *nodes[0].network_payment_count.borrow_mut() -= 1;
+ assert_eq!(route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 900000).1, duplicate_payment_hash);
+
+ let commitment_txn = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone();
+ assert_eq!(commitment_txn[0].input.len(), 1);
+ check_spends!(commitment_txn[0], chan_2.3.clone());
+
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_txn[0].clone()] }, 1);
+ let htlc_timeout_tx;
+ { // Extract one of the two HTLC-Timeout transaction
+ let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
+ assert_eq!(node_txn.len(), 7);
+ assert_eq!(node_txn[0], node_txn[5]);
+ assert_eq!(node_txn[1], node_txn[6]);
+ check_spends!(node_txn[0], commitment_txn[0].clone());
+ assert_eq!(node_txn[0].input.len(), 1);
+ check_spends!(node_txn[1], commitment_txn[0].clone());
+ assert_eq!(node_txn[1].input.len(), 1);
+ assert_ne!(node_txn[0].input[0], node_txn[1].input[0]);
+ check_spends!(node_txn[2], chan_2.3.clone());
+ check_spends!(node_txn[3], node_txn[2].clone());
+ check_spends!(node_txn[4], node_txn[2].clone());
+ htlc_timeout_tx = node_txn[1].clone();
+ }
+
+ let events = nodes[1].node.get_and_clear_pending_msg_events();
+ match events[0] {
+ MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+ _ => panic!("Unexepected event"),
+ }
+
+ nodes[2].node.claim_funds(our_payment_preimage);
+ nodes[2].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_txn[0].clone()] }, 1);
+ check_added_monitors!(nodes[2], 2);
+ let events = nodes[2].node.get_and_clear_pending_msg_events();
+ match events[0] {
+ MessageSendEvent::UpdateHTLCs { .. } => {},
+ _ => panic!("Unexpected event"),
+ }
+ match events[1] {
+ MessageSendEvent::BroadcastChannelUpdate { .. } => {},
+ _ => panic!("Unexepected event"),
+ }
+ let htlc_success_txn: Vec<_> = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
+ assert_eq!(htlc_success_txn.len(), 5);
+ check_spends!(htlc_success_txn[2], chan_2.3.clone());
+ assert_eq!(htlc_success_txn[0], htlc_success_txn[3]);
+ assert_eq!(htlc_success_txn[0].input.len(), 1);
+ assert_eq!(htlc_success_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ assert_eq!(htlc_success_txn[1], htlc_success_txn[4]);
+ assert_eq!(htlc_success_txn[1].input.len(), 1);
+ assert_eq!(htlc_success_txn[1].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+ assert_ne!(htlc_success_txn[0].input[0], htlc_success_txn[1].input[0]);
+ check_spends!(htlc_success_txn[0], commitment_txn[0].clone());
+ check_spends!(htlc_success_txn[1], commitment_txn[0].clone());
+
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![htlc_timeout_tx] }, 200);
+ let htlc_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+ assert!(htlc_updates.update_add_htlcs.is_empty());
+ assert_eq!(htlc_updates.update_fail_htlcs.len(), 1);
+ assert_eq!(htlc_updates.update_fail_htlcs[0].htlc_id, 1);
+ assert!(htlc_updates.update_fulfill_htlcs.is_empty());
+ assert!(htlc_updates.update_fail_malformed_htlcs.is_empty());
+ check_added_monitors!(nodes[1], 1);
+
+ nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &htlc_updates.update_fail_htlcs[0]).unwrap();
+ assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
+ {
+ commitment_signed_dance!(nodes[0], nodes[1], &htlc_updates.commitment_signed, false, true);
+ let events = nodes[0].node.get_and_clear_pending_msg_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ MessageSendEvent::PaymentFailureNetworkUpdate { update: msgs::HTLCFailChannelUpdate::ChannelClosed { .. } } => {
+ },
+ _ => { panic!("Unexpected event"); }
+ }
+ }
+ let events = nodes[0].node.get_and_clear_pending_events();
+ match events[0] {
+ Event::PaymentFailed { ref payment_hash, .. } => {
+ assert_eq!(*payment_hash, duplicate_payment_hash);
+ }
+ _ => panic!("Unexpected event"),
+ }
+
+ // Solve 2nd HTLC by broadcasting on B's chain HTLC-Success Tx from C
+ nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![htlc_success_txn[0].clone()] }, 200);
+ let updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+ assert!(updates.update_add_htlcs.is_empty());
+ assert!(updates.update_fail_htlcs.is_empty());
+ assert_eq!(updates.update_fulfill_htlcs.len(), 1);
+ assert_eq!(updates.update_fulfill_htlcs[0].htlc_id, 0);
+ assert!(updates.update_fail_malformed_htlcs.is_empty());
+ check_added_monitors!(nodes[1], 1);
+
+ nodes[0].node.handle_update_fulfill_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fulfill_htlcs[0]).unwrap();
+ commitment_signed_dance!(nodes[0], nodes[1], &updates.commitment_signed, false);
+
+ let events = nodes[0].node.get_and_clear_pending_events();
+ match events[0] {
+ Event::PaymentSent { ref payment_preimage } => {
+ assert_eq!(*payment_preimage, our_payment_preimage);
+ }
+ _ => panic!("Unexpected event"),
+ }
+ }
+
#[test]
fn test_dynamic_spendable_outputs_local_htlc_success_tx() {
let nodes = create_network(2);