@@ -899,3 +899,165 @@ fn test_retries_own_commitment_broadcast_after_reorg() {
899899 do_test_retries_own_commitment_broadcast_after_reorg ( true , false ) ;
900900 do_test_retries_own_commitment_broadcast_after_reorg ( true , true ) ;
901901}
902+
903+ #[ test]
904+ pub fn test_pruned_locktimed_packages_recovery_after_reorg ( ) {
905+ use crate :: events:: bump_transaction:: sync:: WalletSourceSync ;
906+ use bitcoin:: { Amount , Transaction , TxIn , TxOut } ;
907+ use bitcoin:: locktime:: absolute:: LockTime ;
908+ use bitcoin:: transaction:: Version ;
909+
910+ // ====== TEST SETUP ======
911+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
912+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
913+
914+ let mut user_cfg = test_default_channel_config ( ) ;
915+ user_cfg. channel_handshake_config . negotiate_anchors_zero_fee_htlc_tx = true ;
916+ user_cfg. manually_accept_inbound_channels = true ;
917+
918+ let configs = [ Some ( user_cfg. clone ( ) ) , Some ( user_cfg. clone ( ) ) ] ;
919+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & configs) ;
920+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
921+
922+ let node_a_id = nodes[ 0 ] . node . get_our_node_id ( ) ;
923+ let node_b_id = nodes[ 1 ] . node . get_our_node_id ( ) ;
924+
925+ // Since we're using anchor channels, make sure each node has a UTXO for paying fees.
926+ let coinbase_tx = Transaction {
927+ version : Version :: TWO ,
928+ lock_time : LockTime :: ZERO ,
929+ input : vec ! [ TxIn { ..Default :: default ( ) } ] ,
930+ output : vec ! [
931+ TxOut {
932+ value: Amount :: ONE_BTC ,
933+ script_pubkey: nodes[ 0 ] . wallet_source. get_change_script( ) . unwrap( ) ,
934+ } ,
935+ TxOut {
936+ value: Amount :: ONE_BTC ,
937+ script_pubkey: nodes[ 1 ] . wallet_source. get_change_script( ) . unwrap( ) ,
938+ } ,
939+ ] ,
940+ } ;
941+ nodes[ 0 ] . wallet_source . add_utxo (
942+ bitcoin:: OutPoint { txid : coinbase_tx. compute_txid ( ) , vout : 0 } ,
943+ coinbase_tx. output [ 0 ] . value ,
944+ ) ;
945+ nodes[ 1 ] . wallet_source . add_utxo (
946+ bitcoin:: OutPoint { txid : coinbase_tx. compute_txid ( ) , vout : 1 } ,
947+ coinbase_tx. output [ 1 ] . value ,
948+ ) ;
949+
950+ const CHAN_CAPACITY : u64 = 10_000_000 ;
951+ let ( _, _, channel_id, funding_tx) =
952+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , CHAN_CAPACITY , 0 ) ;
953+
954+ // Ensure all nodes are at the same initial height.
955+ let node_max_height = nodes. iter ( ) . map ( |node| node. best_block_info ( ) . 1 ) . max ( ) . unwrap ( ) ;
956+ for node in & nodes {
957+ let blocks_to_mine = node_max_height - node. best_block_info ( ) . 1 ;
958+ if blocks_to_mine > 0 {
959+ connect_blocks ( node, blocks_to_mine) ;
960+ }
961+ }
962+
963+ // ====== TEST PROCESS ======
964+
965+ // Route HTLC 1 from A to B.
966+ let ( preimage_1, payment_hash_1, ..) = route_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , 1_000_000 ) ;
967+
968+ // Node B claims HTLC 1.
969+ nodes[ 1 ] . node . claim_funds ( preimage_1) ;
970+ expect_payment_claimed ! ( nodes[ 1 ] , payment_hash_1, 1_000_000 ) ;
971+ check_added_monitors ( & nodes[ 1 ] , 1 ) ;
972+ let _ = get_htlc_update_msgs ( & nodes[ 1 ] , & node_a_id) ;
973+
974+ // Force close the channel by broadcasting node B's commitment tx.
975+ let node_b_commit_tx = get_local_commitment_txn ! ( nodes[ 1 ] , channel_id) ;
976+ assert_eq ! ( node_b_commit_tx. len( ) , 1 ) ;
977+ let node_b_commit_tx = & node_b_commit_tx[ 0 ] ;
978+ check_spends ! ( node_b_commit_tx, funding_tx) ;
979+
980+ let htlc_1_locktime = nodes[ 0 ] . best_block_info ( ) . 1 + 1 + TEST_FINAL_CLTV ;
981+ mine_transaction ( & nodes[ 0 ] , node_b_commit_tx) ;
982+ check_closed_event (
983+ & nodes[ 0 ] ,
984+ 1 ,
985+ ClosureReason :: CommitmentTxConfirmed ,
986+ false ,
987+ & [ node_b_id] ,
988+ CHAN_CAPACITY ,
989+ ) ;
990+ check_closed_broadcast ! ( nodes[ 0 ] , true ) ;
991+ check_added_monitors ( & nodes[ 0 ] , 1 ) ;
992+
993+ mine_transaction ( & nodes[ 1 ] , node_b_commit_tx) ;
994+ check_closed_event (
995+ & nodes[ 1 ] ,
996+ 1 ,
997+ ClosureReason :: CommitmentTxConfirmed ,
998+ false ,
999+ & [ node_a_id] ,
1000+ CHAN_CAPACITY ,
1001+ ) ;
1002+ check_closed_broadcast ! ( nodes[ 1 ] , true ) ;
1003+ check_added_monitors ( & nodes[ 1 ] , 1 ) ;
1004+
1005+ // Node B generates HTLC 1 claim tx.
1006+ let process_bump_event = |node : & Node | {
1007+ let events = node. chain_monitor . chain_monitor . get_and_clear_pending_events ( ) ;
1008+ assert_eq ! ( events. len( ) , 1 ) ;
1009+ let bump_event = match & events[ 0 ] {
1010+ Event :: BumpTransaction ( bump_event) => bump_event,
1011+ e => panic ! ( "Unexepected event: {:#?}" , e) ,
1012+ } ;
1013+ node. bump_tx_handler . handle_event ( bump_event) ;
1014+
1015+ let mut tx = node. tx_broadcaster . txn_broadcast ( ) ;
1016+ assert_eq ! ( tx. len( ) , 1 ) ;
1017+ tx. pop ( ) . unwrap ( )
1018+ } ;
1019+ let bs_htlc_1_claim_tx = process_bump_event ( & nodes[ 1 ] ) ;
1020+
1021+ let get_locktimed_packages = || {
1022+ let monitor = nodes[ 0 ] . chain_monitor . chain_monitor . get_monitor ( channel_id) . unwrap ( ) ;
1023+ let onchain_tx_handler = & monitor. inner . lock ( ) . unwrap ( ) . onchain_tx_handler ;
1024+ onchain_tx_handler. locktimed_packages . clone ( )
1025+ } ;
1026+
1027+ let locktimed_packages = get_locktimed_packages ( ) ;
1028+ let htlc_1_locktimed_package = {
1029+ let packages = locktimed_packages. get ( & htlc_1_locktime)
1030+ . expect ( "HTLC 1 locktimed package should exist" ) ;
1031+ assert_eq ! ( packages. len( ) , 1 , "HTLC 1 locktimed package should have only one package" ) ;
1032+ packages. first ( ) . unwrap ( ) . clone ( )
1033+ } ;
1034+
1035+ // HTLC 1 claim tx confirmed - Node A should prune its claim request from locktimed HTLC packages.
1036+ mine_transaction ( & nodes[ 0 ] , & bs_htlc_1_claim_tx) ;
1037+ let locktimed_packages = get_locktimed_packages ( ) ;
1038+ assert ! ( locktimed_packages. is_empty( ) , "locktimed packages should be pruned" ) ;
1039+
1040+ // Disconnect the block containing HTLC 1 claim tx to simulate a reorg. Node A should recover
1041+ // the pruned locktimed package.
1042+ disconnect_blocks ( & nodes[ 0 ] , 1 ) ;
1043+ let locktimed_packages = get_locktimed_packages ( ) ;
1044+ let recovered_htlc_1_locktimed_package = {
1045+ let packages = locktimed_packages. get ( & htlc_1_locktime)
1046+ . expect ( "HTLC 1 locktimed package should be recovered" ) ;
1047+ assert_eq ! ( packages. len( ) , 1 , "HTLC 1 locktimed package should have only one package" ) ;
1048+ packages. first ( ) . unwrap ( ) . clone ( )
1049+ } ;
1050+ assert ! ( recovered_htlc_1_locktimed_package == htlc_1_locktimed_package,
1051+ "Recovered HTLC 1 locktimed package should match the original one" ) ;
1052+
1053+ // HTLC 1 locktime expires.
1054+ connect_blocks ( & nodes[ 0 ] , TEST_FINAL_CLTV ) ;
1055+ // HTLC 1 timeout tx should be broadcasted.
1056+ let mut txs = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
1057+ assert_eq ! ( txs. len( ) , 1 ) ;
1058+ check_spends ! ( txs[ 0 ] , node_b_commit_tx) ;
1059+
1060+ // PaymentSent and PaymentPathSuccessful events.
1061+ let events = nodes[ 0 ] . node . get_and_clear_pending_events ( ) ;
1062+ assert_eq ! ( events. len( ) , 2 ) ;
1063+ }
0 commit comments