@@ -899,3 +899,165 @@ fn test_retries_own_commitment_broadcast_after_reorg() {
899
899
do_test_retries_own_commitment_broadcast_after_reorg ( true , false ) ;
900
900
do_test_retries_own_commitment_broadcast_after_reorg ( true , true ) ;
901
901
}
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