@@ -536,3 +536,193 @@ fn test_claim_value_force_close() {
536
536
do_test_claim_value_force_close ( true ) ;
537
537
do_test_claim_value_force_close ( false ) ;
538
538
}
539
+
540
+ #[ test]
541
+ fn test_balances_on_local_commitment_htlcs ( ) {
542
+ // Previously, when handling the broadcast of a local commitment transactions (with associated
543
+ // CSV delays prior to spendability), we incorrectly handled the CSV delays on HTLC
544
+ // transactions. This caused us to miss spendable outputs for HTLCs which were awaiting a CSV
545
+ // delay prior to spendability.
546
+ //
547
+ // Further, because of this, we could hit an assertion as `get_claimable_balances` asserted
548
+ // that HTLCs were resolved after the funding spend was resolved, which was not true if the
549
+ // HTLC did not have a CSV delay attached (due to the above bug or due to it being an HTLC
550
+ // claim by our counterparty).
551
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
552
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
553
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
554
+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
555
+
556
+ // Create a single channel with two pending HTLCs from nodes[0] to nodes[1], one which nodes[1]
557
+ // knows the preimage for, one which it does not.
558
+ let ( _, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
559
+ let funding_outpoint = OutPoint { txid : funding_tx. txid ( ) , index : 0 } ;
560
+
561
+ let ( route, payment_hash, _, payment_secret) = get_route_and_payment_hash ! ( nodes[ 0 ] , nodes[ 1 ] , 10_000_000 ) ;
562
+ let htlc_cltv_timeout = nodes[ 0 ] . best_block_info ( ) . 1 + TEST_FINAL_CLTV + 1 ; // Note ChannelManager adds one to CLTV timeouts for safety
563
+ nodes[ 0 ] . node . send_payment ( & route, payment_hash, & Some ( payment_secret) ) . unwrap ( ) ;
564
+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
565
+
566
+ let updates = get_htlc_update_msgs ! ( nodes[ 0 ] , nodes[ 1 ] . node. get_our_node_id( ) ) ;
567
+ nodes[ 1 ] . node . handle_update_add_htlc ( & nodes[ 0 ] . node . get_our_node_id ( ) , & updates. update_add_htlcs [ 0 ] ) ;
568
+ commitment_signed_dance ! ( nodes[ 1 ] , nodes[ 0 ] , updates. commitment_signed, false ) ;
569
+
570
+ expect_pending_htlcs_forwardable ! ( nodes[ 1 ] ) ;
571
+ expect_payment_received ! ( nodes[ 1 ] , payment_hash, payment_secret, 10_000_000 ) ;
572
+
573
+ let ( route_2, payment_hash_2, payment_preimage_2, payment_secret_2) = get_route_and_payment_hash ! ( nodes[ 0 ] , nodes[ 1 ] , 20_000_000 ) ;
574
+ nodes[ 0 ] . node . send_payment ( & route_2, payment_hash_2, & Some ( payment_secret_2) ) . unwrap ( ) ;
575
+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
576
+
577
+ let updates = get_htlc_update_msgs ! ( nodes[ 0 ] , nodes[ 1 ] . node. get_our_node_id( ) ) ;
578
+ nodes[ 1 ] . node . handle_update_add_htlc ( & nodes[ 0 ] . node . get_our_node_id ( ) , & updates. update_add_htlcs [ 0 ] ) ;
579
+ commitment_signed_dance ! ( nodes[ 1 ] , nodes[ 0 ] , updates. commitment_signed, false ) ;
580
+
581
+ expect_pending_htlcs_forwardable ! ( nodes[ 1 ] ) ;
582
+ expect_payment_received ! ( nodes[ 1 ] , payment_hash_2, payment_secret_2, 20_000_000 ) ;
583
+ assert ! ( nodes[ 1 ] . node. claim_funds( payment_preimage_2) ) ;
584
+ get_htlc_update_msgs ! ( nodes[ 1 ] , nodes[ 0 ] . node. get_our_node_id( ) ) ;
585
+ check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
586
+
587
+ let chan_feerate = get_feerate ! ( nodes[ 0 ] , chan_id) as u64 ;
588
+ let opt_anchors = get_opt_anchors ! ( nodes[ 0 ] , chan_id) ;
589
+
590
+ // Get nodes[0]'s commitment transaction and HTLC-Timeout transactions
591
+ let as_txn = get_local_commitment_txn ! ( nodes[ 0 ] , chan_id) ;
592
+ assert_eq ! ( as_txn. len( ) , 3 ) ;
593
+ check_spends ! ( as_txn[ 1 ] , as_txn[ 0 ] ) ;
594
+ check_spends ! ( as_txn[ 2 ] , as_txn[ 0 ] ) ;
595
+ check_spends ! ( as_txn[ 0 ] , funding_tx) ;
596
+
597
+ // First confirm the commitment transaction on nodes[0], which should leave us with three
598
+ // claimable balances.
599
+ let node_a_commitment_claimable = nodes[ 0 ] . best_block_info ( ) . 1 + BREAKDOWN_TIMEOUT as u32 ;
600
+ mine_transaction ( & nodes[ 0 ] , & as_txn[ 0 ] ) ;
601
+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
602
+ check_closed_broadcast ! ( nodes[ 0 ] , true ) ;
603
+ check_closed_event ! ( nodes[ 0 ] , 1 , ClosureReason :: CommitmentTxConfirmed ) ;
604
+
605
+ assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
606
+ claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
607
+ ( channel:: commitment_tx_base_weight( opt_anchors) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
608
+ confirmation_height: node_a_commitment_claimable,
609
+ } , Balance :: MaybeClaimableHTLCAwaitingTimeout {
610
+ claimable_amount_satoshis: 10_000 ,
611
+ claimable_height: htlc_cltv_timeout,
612
+ } , Balance :: MaybeClaimableHTLCAwaitingTimeout {
613
+ claimable_amount_satoshis: 20_000 ,
614
+ claimable_height: htlc_cltv_timeout,
615
+ } ] ) ,
616
+ sorted_vec( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
617
+
618
+ // Get nodes[1]'s HTLC claim tx for the second HTLC
619
+ mine_transaction ( & nodes[ 1 ] , & as_txn[ 0 ] ) ;
620
+ check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
621
+ check_closed_broadcast ! ( nodes[ 1 ] , true ) ;
622
+ check_closed_event ! ( nodes[ 1 ] , 1 , ClosureReason :: CommitmentTxConfirmed ) ;
623
+ let bs_htlc_claim_txn = nodes[ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . split_off ( 0 ) ;
624
+ assert_eq ! ( bs_htlc_claim_txn. len( ) , 3 ) ;
625
+ check_spends ! ( bs_htlc_claim_txn[ 0 ] , as_txn[ 0 ] ) ;
626
+ check_spends ! ( bs_htlc_claim_txn[ 1 ] , funding_tx) ;
627
+ check_spends ! ( bs_htlc_claim_txn[ 2 ] , bs_htlc_claim_txn[ 1 ] ) ;
628
+
629
+ // Connect blocks until the HTLCs expire, allowing us to (validly) broadcast the HTLC-Timeout
630
+ // transaction.
631
+ connect_blocks ( & nodes[ 0 ] , TEST_FINAL_CLTV - 1 ) ;
632
+ assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
633
+ claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
634
+ ( channel:: commitment_tx_base_weight( opt_anchors) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
635
+ confirmation_height: node_a_commitment_claimable,
636
+ } , Balance :: MaybeClaimableHTLCAwaitingTimeout {
637
+ claimable_amount_satoshis: 10_000 ,
638
+ claimable_height: htlc_cltv_timeout,
639
+ } , Balance :: MaybeClaimableHTLCAwaitingTimeout {
640
+ claimable_amount_satoshis: 20_000 ,
641
+ claimable_height: htlc_cltv_timeout,
642
+ } ] ) ,
643
+ sorted_vec( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
644
+ assert_eq ! ( as_txn[ 1 ] . lock_time, nodes[ 0 ] . best_block_info( ) . 1 + 1 ) ; // as_txn[1] can be included in the next block
645
+
646
+ // Now confirm nodes[0]'s HTLC-Timeout transaction, which changes the claimable balance to an
647
+ // "awaiting confirmations" one.
648
+ let node_a_htlc_claimable = nodes[ 0 ] . best_block_info ( ) . 1 + BREAKDOWN_TIMEOUT as u32 ;
649
+ mine_transaction ( & nodes[ 0 ] , & as_txn[ 1 ] ) ;
650
+ // Note that prior to the fix in the commit which introduced this test, this (and the next
651
+ // balance) check failed. With this check removed, the code panicked in the `connect_blocks`
652
+ // call, as described, two hunks down.
653
+ assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
654
+ claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
655
+ ( channel:: commitment_tx_base_weight( opt_anchors) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
656
+ confirmation_height: node_a_commitment_claimable,
657
+ } , Balance :: ClaimableAwaitingConfirmations {
658
+ claimable_amount_satoshis: 10_000 ,
659
+ confirmation_height: node_a_htlc_claimable,
660
+ } , Balance :: MaybeClaimableHTLCAwaitingTimeout {
661
+ claimable_amount_satoshis: 20_000 ,
662
+ claimable_height: htlc_cltv_timeout,
663
+ } ] ) ,
664
+ sorted_vec( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
665
+
666
+ // Now confirm nodes[1]'s HTLC claim, giving nodes[0] the preimage. Note that the "maybe
667
+ // claimable" balance remains until we see ANTI_REORG_DELAY blocks.
668
+ mine_transaction ( & nodes[ 0 ] , & bs_htlc_claim_txn[ 0 ] ) ;
669
+ expect_payment_sent ! ( nodes[ 0 ] , payment_preimage_2) ;
670
+ assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
671
+ claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
672
+ ( channel:: commitment_tx_base_weight( opt_anchors) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
673
+ confirmation_height: node_a_commitment_claimable,
674
+ } , Balance :: ClaimableAwaitingConfirmations {
675
+ claimable_amount_satoshis: 10_000 ,
676
+ confirmation_height: node_a_htlc_claimable,
677
+ } , Balance :: MaybeClaimableHTLCAwaitingTimeout {
678
+ claimable_amount_satoshis: 20_000 ,
679
+ claimable_height: htlc_cltv_timeout,
680
+ } ] ) ,
681
+ sorted_vec( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
682
+
683
+ // Finally make the HTLC transactions have ANTI_REORG_DELAY blocks. This call previously
684
+ // panicked as described in the test introduction. This will remove the "maybe claimable"
685
+ // spendable output as nodes[1] has fully claimed the second HTLC.
686
+ connect_blocks ( & nodes[ 0 ] , ANTI_REORG_DELAY - 1 ) ;
687
+ expect_payment_failed ! ( nodes[ 0 ] , payment_hash, true ) ;
688
+
689
+ assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
690
+ claimable_amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
691
+ ( channel:: commitment_tx_base_weight( opt_anchors) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
692
+ confirmation_height: node_a_commitment_claimable,
693
+ } , Balance :: ClaimableAwaitingConfirmations {
694
+ claimable_amount_satoshis: 10_000 ,
695
+ confirmation_height: node_a_htlc_claimable,
696
+ } ] ) ,
697
+ sorted_vec( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
698
+
699
+ // Connect blocks until the commitment transaction's CSV expires, providing us the relevant
700
+ // `SpendableOutputs` event and removing the claimable balance entry.
701
+ connect_blocks ( & nodes[ 0 ] , node_a_commitment_claimable - nodes[ 0 ] . best_block_info ( ) . 1 ) ;
702
+ assert_eq ! ( vec![ Balance :: ClaimableAwaitingConfirmations {
703
+ claimable_amount_satoshis: 10_000 ,
704
+ confirmation_height: node_a_htlc_claimable,
705
+ } ] ,
706
+ nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ;
707
+ let mut node_a_spendable = nodes[ 0 ] . chain_monitor . chain_monitor . get_and_clear_pending_events ( ) ;
708
+ assert_eq ! ( node_a_spendable. len( ) , 1 ) ;
709
+ if let Event :: SpendableOutputs { outputs } = node_a_spendable. pop ( ) . unwrap ( ) {
710
+ assert_eq ! ( outputs. len( ) , 1 ) ;
711
+ let spend_tx = nodes[ 0 ] . keys_manager . backing . spend_spendable_outputs ( & [ & outputs[ 0 ] ] , Vec :: new ( ) ,
712
+ Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_RETURN ) . into_script ( ) , 253 , & Secp256k1 :: new ( ) ) . unwrap ( ) ;
713
+ check_spends ! ( spend_tx, as_txn[ 0 ] ) ;
714
+ }
715
+
716
+ // Connect blocks until the HTLC-Timeout's CSV expires, providing us the relevant
717
+ // `SpendableOutputs` event and removing the claimable balance entry.
718
+ connect_blocks ( & nodes[ 0 ] , node_a_htlc_claimable - nodes[ 0 ] . best_block_info ( ) . 1 ) ;
719
+ assert ! ( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) . is_empty( ) ) ;
720
+ let mut node_a_spendable = nodes[ 0 ] . chain_monitor . chain_monitor . get_and_clear_pending_events ( ) ;
721
+ assert_eq ! ( node_a_spendable. len( ) , 1 ) ;
722
+ if let Event :: SpendableOutputs { outputs } = node_a_spendable. pop ( ) . unwrap ( ) {
723
+ assert_eq ! ( outputs. len( ) , 1 ) ;
724
+ let spend_tx = nodes[ 0 ] . keys_manager . backing . spend_spendable_outputs ( & [ & outputs[ 0 ] ] , Vec :: new ( ) ,
725
+ Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_RETURN ) . into_script ( ) , 253 , & Secp256k1 :: new ( ) ) . unwrap ( ) ;
726
+ check_spends ! ( spend_tx, as_txn[ 1 ] ) ;
727
+ }
728
+ }
0 commit comments