@@ -2648,14 +2648,15 @@ fn test_htlc_on_chain_success() {
2648
2648
// Test that in case of an unilateral close onchain, we detect the state of output thanks to
2649
2649
// ChainWatchInterface and pass the preimage backward accordingly. So here we test that ChannelManager is
2650
2650
// broadcasting the right event to other nodes in payment path.
2651
+ // We test with two HTLCs simultaneously as that was not handled correctly in the past.
2651
2652
// A --------------------> B ----------------------> C (preimage)
2652
- // First, C should claim the HTLC output via HTLC-Success when its own latest local
2653
+ // First, C should claim the HTLC outputs via HTLC-Success when its own latest local
2653
2654
// commitment transaction was broadcast.
2654
2655
// Then, B should learn the preimage from said transactions, attempting to claim backwards
2655
2656
// towards B.
2656
2657
// B should be able to claim via preimage if A then broadcasts its local tx.
2657
2658
// Finally, when A sees B's latest local commitment transaction it should be able to claim
2658
- // the HTLC output via the preimage it learned (which, once confirmed should generate a
2659
+ // the HTLC outputs via the preimage it learned (which, once confirmed should generate a
2659
2660
// PaymentSent event).
2660
2661
2661
2662
let nodes = create_network ( 3 ) ;
@@ -2669,6 +2670,7 @@ fn test_htlc_on_chain_success() {
2669
2670
send_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] , & nodes[ 2 ] ) [ ..] , 8000000 ) ;
2670
2671
2671
2672
let ( our_payment_preimage, _payment_hash) = route_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] , & nodes[ 2 ] ) , 3000000 ) ;
2673
+ let ( our_payment_preimage_2, _payment_hash_2) = route_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] , & nodes[ 2 ] ) , 3000000 ) ;
2672
2674
let header = BlockHeader { version : 0x20000000 , prev_blockhash : Default :: default ( ) , merkle_root : Default :: default ( ) , time : 42 , bits : 42 , nonce : 42 } ;
2673
2675
2674
2676
// Broadcast legit commitment tx from C on B's chain
@@ -2677,7 +2679,8 @@ fn test_htlc_on_chain_success() {
2677
2679
assert_eq ! ( commitment_tx. len( ) , 1 ) ;
2678
2680
check_spends ! ( commitment_tx[ 0 ] , chan_2. 3 . clone( ) ) ;
2679
2681
nodes[ 2 ] . node . claim_funds ( our_payment_preimage) ;
2680
- check_added_monitors ! ( nodes[ 2 ] , 1 ) ;
2682
+ nodes[ 2 ] . node . claim_funds ( our_payment_preimage_2) ;
2683
+ check_added_monitors ! ( nodes[ 2 ] , 2 ) ;
2681
2684
let updates = get_htlc_update_msgs ! ( nodes[ 2 ] , nodes[ 1 ] . node. get_our_node_id( ) ) ;
2682
2685
assert ! ( updates. update_add_htlcs. is_empty( ) ) ;
2683
2686
assert ! ( updates. update_fail_htlcs. is_empty( ) ) ;
@@ -2686,22 +2689,28 @@ fn test_htlc_on_chain_success() {
2686
2689
2687
2690
nodes[ 2 ] . chain_monitor . block_connected_with_filtering ( & Block { header, txdata : vec ! [ commitment_tx[ 0 ] . clone( ) ] } , 1 ) ;
2688
2691
check_closed_broadcast ! ( nodes[ 2 ] ) ;
2689
- let node_txn = nodes[ 2 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . clone ( ) ; // ChannelManager : 1 (commitment tx), ChannelMonitor : 2 (2 * HTLC-Success tx)
2690
- assert_eq ! ( node_txn. len( ) , 3 ) ;
2691
- assert_eq ! ( node_txn[ 1 ] , commitment_tx[ 0 ] ) ;
2692
- assert_eq ! ( node_txn[ 0 ] , node_txn[ 2 ] ) ;
2692
+ let node_txn = nodes[ 2 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . clone ( ) ; // ChannelManager : 1 (commitment tx), ChannelMonitor : 4 (2*2 * HTLC-Success tx)
2693
+ assert_eq ! ( node_txn. len( ) , 5 ) ;
2694
+ assert_eq ! ( node_txn[ 0 ] , node_txn[ 3 ] ) ;
2695
+ assert_eq ! ( node_txn[ 1 ] , node_txn[ 4 ] ) ;
2696
+ assert_eq ! ( node_txn[ 2 ] , commitment_tx[ 0 ] ) ;
2693
2697
check_spends ! ( node_txn[ 0 ] , commitment_tx[ 0 ] . clone( ) ) ;
2698
+ check_spends ! ( node_txn[ 1 ] , commitment_tx[ 0 ] . clone( ) ) ;
2694
2699
assert_eq ! ( node_txn[ 0 ] . input[ 0 ] . witness. clone( ) . last( ) . unwrap( ) . len( ) , ACCEPTED_HTLC_SCRIPT_WEIGHT ) ;
2700
+ assert_eq ! ( node_txn[ 1 ] . input[ 0 ] . witness. clone( ) . last( ) . unwrap( ) . len( ) , ACCEPTED_HTLC_SCRIPT_WEIGHT ) ;
2695
2701
assert ! ( node_txn[ 0 ] . output[ 0 ] . script_pubkey. is_v0_p2wsh( ) ) ; // revokeable output
2702
+ assert ! ( node_txn[ 1 ] . output[ 0 ] . script_pubkey. is_v0_p2wsh( ) ) ; // revokeable output
2696
2703
assert_eq ! ( node_txn[ 0 ] . lock_time, 0 ) ;
2704
+ assert_eq ! ( node_txn[ 1 ] . lock_time, 0 ) ;
2697
2705
2698
2706
// Verify that B's ChannelManager is able to extract preimage from HTLC Success tx and pass it backward
2699
2707
nodes[ 1 ] . chain_monitor . block_connected_with_filtering ( & Block { header, txdata : node_txn} , 1 ) ;
2700
2708
let events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
2701
2709
{
2702
2710
let mut added_monitors = nodes[ 1 ] . chan_monitor . added_monitors . lock ( ) . unwrap ( ) ;
2703
- assert_eq ! ( added_monitors. len( ) , 1 ) ;
2711
+ assert_eq ! ( added_monitors. len( ) , 2 ) ;
2704
2712
assert_eq ! ( added_monitors[ 0 ] . 0 . txid, chan_1. 3 . txid( ) ) ;
2713
+ assert_eq ! ( added_monitors[ 1 ] . 0 . txid, chan_1. 3 . txid( ) ) ;
2705
2714
added_monitors. clear ( ) ;
2706
2715
}
2707
2716
assert_eq ! ( events. len( ) , 2 ) ;
@@ -2719,25 +2728,45 @@ fn test_htlc_on_chain_success() {
2719
2728
} ,
2720
2729
_ => panic ! ( "Unexpected event" ) ,
2721
2730
} ;
2722
- {
2723
- // nodes[1] now broadcasts its own local state as a fallback, suggesting an alternate
2724
- // commitment transaction with a corresponding HTLC-Timeout transaction, as well as a
2725
- // timeout-claim of the output that nodes[2] just claimed via success.
2726
- 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)
2727
- assert_eq ! ( node_txn. len( ) , 4 ) ;
2728
- assert_eq ! ( node_txn[ 0 ] , node_txn[ 3 ] ) ;
2729
- check_spends ! ( node_txn[ 0 ] , commitment_tx[ 0 ] . clone( ) ) ;
2730
- assert_eq ! ( node_txn[ 0 ] . input[ 0 ] . witness. clone( ) . last( ) . unwrap( ) . len( ) , ACCEPTED_HTLC_SCRIPT_WEIGHT ) ;
2731
- assert_ne ! ( node_txn[ 0 ] . lock_time, 0 ) ;
2732
- assert ! ( node_txn[ 0 ] . output[ 0 ] . script_pubkey. is_v0_p2wpkh( ) ) ; // direct payment
2733
- check_spends ! ( node_txn[ 1 ] , chan_2. 3 . clone( ) ) ;
2734
- check_spends ! ( node_txn[ 2 ] , node_txn[ 1 ] . clone( ) ) ;
2735
- assert_eq ! ( node_txn[ 1 ] . input[ 0 ] . witness. clone( ) . last( ) . unwrap( ) . len( ) , 71 ) ;
2736
- assert_eq ! ( node_txn[ 2 ] . input[ 0 ] . witness. clone( ) . last( ) . unwrap( ) . len( ) , OFFERED_HTLC_SCRIPT_WEIGHT ) ;
2737
- assert ! ( node_txn[ 2 ] . output[ 0 ] . script_pubkey. is_v0_p2wsh( ) ) ; // revokeable output
2738
- assert_ne ! ( node_txn[ 2 ] . lock_time, 0 ) ;
2739
- node_txn. clear ( ) ;
2740
- }
2731
+ macro_rules! check_tx_local_broadcast {
2732
+ ( $node: expr, $htlc_offered: expr, $commitment_tx: expr, $chan_tx: expr) => { {
2733
+ // ChannelManager : 3 (commitment tx, 2*HTLC-Timeout tx), ChannelMonitor : 2 (timeout tx) * 2 (block-rescan)
2734
+ let mut node_txn = $node. tx_broadcaster. txn_broadcasted. lock( ) . unwrap( ) ;
2735
+ assert_eq!( node_txn. len( ) , 7 ) ;
2736
+ assert_eq!( node_txn[ 0 ] , node_txn[ 5 ] ) ;
2737
+ assert_eq!( node_txn[ 1 ] , node_txn[ 6 ] ) ;
2738
+ check_spends!( node_txn[ 0 ] , $commitment_tx. clone( ) ) ;
2739
+ check_spends!( node_txn[ 1 ] , $commitment_tx. clone( ) ) ;
2740
+ assert_ne!( node_txn[ 0 ] . lock_time, 0 ) ;
2741
+ assert_ne!( node_txn[ 1 ] . lock_time, 0 ) ;
2742
+ if $htlc_offered {
2743
+ assert_eq!( node_txn[ 0 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , OFFERED_HTLC_SCRIPT_WEIGHT ) ;
2744
+ assert_eq!( node_txn[ 1 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , OFFERED_HTLC_SCRIPT_WEIGHT ) ;
2745
+ assert!( node_txn[ 0 ] . output[ 0 ] . script_pubkey. is_v0_p2wsh( ) ) ; // revokeable output
2746
+ assert!( node_txn[ 1 ] . output[ 0 ] . script_pubkey. is_v0_p2wsh( ) ) ; // revokeable output
2747
+ } else {
2748
+ assert_eq!( node_txn[ 0 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , ACCEPTED_HTLC_SCRIPT_WEIGHT ) ;
2749
+ assert_eq!( node_txn[ 1 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , ACCEPTED_HTLC_SCRIPT_WEIGHT ) ;
2750
+ assert!( node_txn[ 0 ] . output[ 0 ] . script_pubkey. is_v0_p2wpkh( ) ) ; // direct payment
2751
+ assert!( node_txn[ 1 ] . output[ 0 ] . script_pubkey. is_v0_p2wpkh( ) ) ; // direct payment
2752
+ }
2753
+ check_spends!( node_txn[ 2 ] , $chan_tx. clone( ) ) ;
2754
+ check_spends!( node_txn[ 3 ] , node_txn[ 2 ] . clone( ) ) ;
2755
+ check_spends!( node_txn[ 4 ] , node_txn[ 2 ] . clone( ) ) ;
2756
+ assert_eq!( node_txn[ 2 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , 71 ) ;
2757
+ assert_eq!( node_txn[ 3 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , OFFERED_HTLC_SCRIPT_WEIGHT ) ;
2758
+ assert_eq!( node_txn[ 4 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , OFFERED_HTLC_SCRIPT_WEIGHT ) ;
2759
+ assert!( node_txn[ 3 ] . output[ 0 ] . script_pubkey. is_v0_p2wsh( ) ) ; // revokeable output
2760
+ assert!( node_txn[ 4 ] . output[ 0 ] . script_pubkey. is_v0_p2wsh( ) ) ; // revokeable output
2761
+ assert_ne!( node_txn[ 3 ] . lock_time, 0 ) ;
2762
+ assert_ne!( node_txn[ 4 ] . lock_time, 0 ) ;
2763
+ node_txn. clear( ) ;
2764
+ } }
2765
+ }
2766
+ // nodes[1] now broadcasts its own local state as a fallback, suggesting an alternate
2767
+ // commitment transaction with a corresponding HTLC-Timeout transactions, as well as a
2768
+ // timeout-claim of the output that nodes[2] just claimed via success.
2769
+ check_tx_local_broadcast ! ( nodes[ 1 ] , false , commitment_tx[ 0 ] , chan_2. 3 ) ;
2741
2770
2742
2771
// Broadcast legit commitment tx from A on B's chain
2743
2772
// Broadcast preimage tx by B on offered output from A commitment tx on A's chain
@@ -2749,7 +2778,9 @@ fn test_htlc_on_chain_success() {
2749
2778
assert_eq ! ( node_txn. len( ) , 3 ) ;
2750
2779
assert_eq ! ( node_txn[ 0 ] , node_txn[ 2 ] ) ;
2751
2780
check_spends ! ( node_txn[ 0 ] , commitment_tx[ 0 ] . clone( ) ) ;
2752
- assert_eq ! ( node_txn[ 0 ] . input[ 0 ] . witness. clone( ) . last( ) . unwrap( ) . len( ) , OFFERED_HTLC_SCRIPT_WEIGHT ) ;
2781
+ assert_eq ! ( node_txn[ 0 ] . input. len( ) , 2 ) ;
2782
+ assert_eq ! ( node_txn[ 0 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , OFFERED_HTLC_SCRIPT_WEIGHT ) ;
2783
+ assert_eq ! ( node_txn[ 0 ] . input[ 1 ] . witness. last( ) . unwrap( ) . len( ) , OFFERED_HTLC_SCRIPT_WEIGHT ) ;
2753
2784
assert_eq ! ( node_txn[ 0 ] . lock_time, 0 ) ;
2754
2785
assert ! ( node_txn[ 0 ] . output[ 0 ] . script_pubkey. is_v0_p2wpkh( ) ) ; // direct payment
2755
2786
check_spends ! ( node_txn[ 1 ] , chan_1. 3 . clone( ) ) ;
@@ -2761,26 +2792,22 @@ fn test_htlc_on_chain_success() {
2761
2792
nodes[ 0 ] . chain_monitor . block_connected_with_filtering ( & Block { header, txdata : vec ! [ commitment_tx[ 0 ] . clone( ) , node_txn[ 0 ] . clone( ) ] } , 1 ) ;
2762
2793
check_closed_broadcast ! ( nodes[ 0 ] ) ;
2763
2794
let events = nodes[ 0 ] . node . get_and_clear_pending_events ( ) ;
2764
- assert_eq ! ( events. len( ) , 1 ) ;
2765
- match events[ 0 ] {
2766
- Event :: PaymentSent { payment_preimage } => {
2767
- assert_eq ! ( payment_preimage, our_payment_preimage) ;
2768
- } ,
2769
- _ => panic ! ( "Unexpected event" ) ,
2795
+ assert_eq ! ( events. len( ) , 2 ) ;
2796
+ let mut first_claimed = false ;
2797
+ for event in events {
2798
+ match event {
2799
+ Event :: PaymentSent { payment_preimage } => {
2800
+ if payment_preimage == our_payment_preimage {
2801
+ assert ! ( !first_claimed) ;
2802
+ first_claimed = true ;
2803
+ } else {
2804
+ assert_eq ! ( payment_preimage, our_payment_preimage_2) ;
2805
+ }
2806
+ } ,
2807
+ _ => panic ! ( "Unexpected event" ) ,
2808
+ }
2770
2809
}
2771
- 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)
2772
- assert_eq ! ( node_txn. len( ) , 4 ) ;
2773
- assert_eq ! ( node_txn[ 0 ] , node_txn[ 3 ] ) ;
2774
- check_spends ! ( node_txn[ 0 ] , commitment_tx[ 0 ] . clone( ) ) ;
2775
- assert_eq ! ( node_txn[ 0 ] . input[ 0 ] . witness. clone( ) . last( ) . unwrap( ) . len( ) , OFFERED_HTLC_SCRIPT_WEIGHT ) ;
2776
- assert_ne ! ( node_txn[ 0 ] . lock_time, 0 ) ;
2777
- assert ! ( node_txn[ 0 ] . output[ 0 ] . script_pubkey. is_v0_p2wsh( ) ) ; // revokeable output
2778
- check_spends ! ( node_txn[ 1 ] , chan_1. 3 . clone( ) ) ;
2779
- check_spends ! ( node_txn[ 2 ] , node_txn[ 1 ] . clone( ) ) ;
2780
- assert_eq ! ( node_txn[ 1 ] . input[ 0 ] . witness. clone( ) . last( ) . unwrap( ) . len( ) , 71 ) ;
2781
- assert_eq ! ( node_txn[ 2 ] . input[ 0 ] . witness. clone( ) . last( ) . unwrap( ) . len( ) , OFFERED_HTLC_SCRIPT_WEIGHT ) ;
2782
- assert ! ( node_txn[ 2 ] . output[ 0 ] . script_pubkey. is_v0_p2wsh( ) ) ; // revokeable output
2783
- assert_ne ! ( node_txn[ 2 ] . lock_time, 0 ) ;
2810
+ check_tx_local_broadcast ! ( nodes[ 0 ] , true , commitment_tx[ 0 ] , chan_1. 3 ) ;
2784
2811
}
2785
2812
2786
2813
#[ test]
0 commit comments