@@ -2136,13 +2136,17 @@ impl ChainListener for ChannelManager {
21362136 for ( arr, vec) in payment_preimage. iter_mut ( ) . zip ( tx. input [ 0 ] . witness [ 3 ] . iter ( ) ) {
21372137 * arr = * vec;
21382138 }
2139- hash_to_remove. push ( ( payment_preimage, htlc_with_hash. clone ( ) ) ) ;
2139+ hash_to_remove. push ( ( Some ( payment_preimage) , htlc_with_hash. clone ( ) ) ) ;
21402140 } else if tx. input . len ( ) > 0 && tx. input [ 0 ] . witness . len ( ) == 3 && tx. input [ 0 ] . witness [ 2 ] . len ( ) == 133 && payment_hash160 == tx. input [ 0 ] . witness [ 2 ] [ 109 ..129 ] {
21412141 let mut payment_preimage = [ 0 ; 32 ] ;
21422142 for ( arr, vec) in payment_preimage. iter_mut ( ) . zip ( tx. input [ 0 ] . witness [ 1 ] . iter ( ) ) {
21432143 * arr = * vec;
21442144 }
2145- hash_to_remove. push ( ( payment_preimage, htlc_with_hash. clone ( ) ) ) ;
2145+ hash_to_remove. push ( ( Some ( payment_preimage) , htlc_with_hash. clone ( ) ) ) ;
2146+ } else if tx. input . len ( ) > 0 && tx. input [ 0 ] . witness . len ( ) == 5 && tx. input [ 0 ] . witness [ 4 ] . len ( ) == 133 && payment_hash160 == tx. input [ 0 ] . witness [ 4 ] [ 109 ..129 ] {
2147+ hash_to_remove. push ( ( None , htlc_with_hash. clone ( ) ) ) ;
2148+ } else if tx. input . len ( ) > 0 && tx. input [ 0 ] . witness . len ( ) == 3 && tx. input [ 0 ] . witness [ 2 ] . len ( ) == 138 && payment_hash160 == tx. input [ 0 ] . witness [ 2 ] [ 69 ..89 ] {
2149+ hash_to_remove. push ( ( None , htlc_with_hash. clone ( ) ) ) ;
21462150 }
21472151 }
21482152 }
@@ -2153,11 +2157,20 @@ impl ChainListener for ChannelManager {
21532157
21542158 {
21552159 let mut channel_state = Some ( self . channel_state . lock ( ) . unwrap ( ) ) ;
2156- for ( preimage, hash) in hash_to_remove {
2157- if channel_state. is_none ( ) { channel_state = Some ( self . channel_state . lock ( ) . unwrap ( ) ) ; }
2158- if let Some ( mut sources) = channel_state. as_mut ( ) . unwrap ( ) . claimable_htlcs . remove ( & hash) {
2159- for source in sources. drain ( ..) {
2160- self . claim_funds_internal ( channel_state. take ( ) . unwrap ( ) , HTLCSource :: PreviousHopData ( source) , preimage) ;
2160+ for ( payment_preimage, payment_hash) in hash_to_remove {
2161+ if let Some ( preimage) = payment_preimage {
2162+ if channel_state. is_none ( ) { channel_state = Some ( self . channel_state . lock ( ) . unwrap ( ) ) ; }
2163+ if let Some ( mut entry) = channel_state. as_mut ( ) . unwrap ( ) . claimable_htlcs . remove ( & payment_hash) {
2164+ for source in entry. drain ( ..) {
2165+ self . claim_funds_internal ( channel_state. take ( ) . unwrap ( ) , HTLCSource :: PreviousHopData ( source) , preimage) ;
2166+ }
2167+ }
2168+ } else {
2169+ if channel_state. is_none ( ) { channel_state = Some ( self . channel_state . lock ( ) . unwrap ( ) ) ; }
2170+ if let Some ( mut entry) = channel_state. as_mut ( ) . unwrap ( ) . claimable_htlcs . remove ( & payment_hash) {
2171+ for source in entry. drain ( ..) {
2172+ self . fail_htlc_backwards_internal ( channel_state. take ( ) . unwrap ( ) , HTLCSource :: PreviousHopData ( source) , & payment_hash, HTLCFailReason :: Reason { failure_code : 0x1000 | 14 , data : Vec :: new ( ) } ) ;
2173+ }
21612174 }
21622175 }
21632176 }
@@ -4361,6 +4374,117 @@ mod tests {
43614374 }
43624375 }
43634376
4377+ #[ test]
4378+ fn test_htlc_on_chain_timeout ( ) {
4379+ // Test that in case of an unilateral close onchain, we detect the state of output thanks to
4380+ // ChainWatchInterface and timeout the HTLC bacward accordingly. So here we test that ChannelManager is
4381+ // broadcasting the right event to other nodes in payment path.
4382+ // A ------------------> B ----------------------> C (timeout)
4383+ // A's commitment tx C's commitment tx
4384+ // \ \
4385+ // B's HTLC timeout tx B's timeout tx
4386+
4387+ let nodes = create_network ( 3 ) ;
4388+
4389+ // Create some intial channels
4390+ let chan_1 = create_announced_chan_between_nodes ( & nodes, 0 , 1 ) ;
4391+ let chan_2 = create_announced_chan_between_nodes ( & nodes, 1 , 2 ) ;
4392+
4393+ // Rebalance the network a bit by relaying one payment thorugh all the channels...
4394+ send_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] , & nodes[ 2 ] ) [ ..] , 8000000 ) ;
4395+ send_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] , & nodes[ 2 ] ) [ ..] , 8000000 ) ;
4396+
4397+ let ( _payment_preimage, payment_hash) = route_payment ( & nodes[ 0 ] , & vec ! ( & nodes[ 1 ] , & nodes[ 2 ] ) , 3000000 ) ;
4398+ let header = BlockHeader { version : 0x20000000 , prev_blockhash : Default :: default ( ) , merkle_root : Default :: default ( ) , time : 42 , bits : 42 , nonce : 42 } ;
4399+
4400+ // Brodacast legit commitment tx from C on B's chain
4401+ let commitment_tx = nodes[ 2 ] . node . channel_state . lock ( ) . unwrap ( ) . by_id . get ( & chan_2. 2 ) . unwrap ( ) . last_local_commitment_txn . clone ( ) ;
4402+ nodes[ 2 ] . node . fail_htlc_backwards ( & payment_hash) ;
4403+ {
4404+ let mut added_monitors = nodes[ 2 ] . chan_monitor . added_monitors . lock ( ) . unwrap ( ) ;
4405+ assert_eq ! ( added_monitors. len( ) , 1 ) ;
4406+ added_monitors. clear ( ) ;
4407+ }
4408+ let events = nodes[ 2 ] . node . get_and_clear_pending_events ( ) ;
4409+ assert_eq ! ( events. len( ) , 1 ) ;
4410+ match events[ 0 ] {
4411+ Event :: UpdateHTLCs { ref node_id, updates : msgs:: CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => {
4412+ assert ! ( update_add_htlcs. is_empty( ) ) ;
4413+ assert ! ( !update_fail_htlcs. is_empty( ) ) ;
4414+ assert ! ( update_fulfill_htlcs. is_empty( ) ) ;
4415+ assert ! ( update_fail_malformed_htlcs. is_empty( ) ) ;
4416+ assert_eq ! ( nodes[ 1 ] . node. get_our_node_id( ) , * node_id) ;
4417+ } ,
4418+ _ => panic ! ( "Unexpected event" ) ,
4419+ } ;
4420+ nodes[ 2 ] . chain_monitor . block_connected_with_filtering ( & Block { header, txdata : vec ! [ commitment_tx[ 0 ] . clone( ) ] } , 1 ) ;
4421+ let events = nodes[ 2 ] . node . get_and_clear_pending_events ( ) ;
4422+ assert_eq ! ( events. len( ) , 1 ) ;
4423+ match events[ 0 ] {
4424+ Event :: BroadcastChannelUpdate { msg : msgs:: ChannelUpdate { .. } } => { } ,
4425+ _ => panic ! ( "Unexpected event" ) ,
4426+ }
4427+ let mut funding_tx_map = HashMap :: new ( ) ;
4428+ funding_tx_map. insert ( chan_2. 3 . txid ( ) , chan_2. 3 . clone ( ) ) ;
4429+ commitment_tx[ 0 ] . verify ( & funding_tx_map) . unwrap ( ) ;
4430+
4431+ // Broadcast timeout transaction by B on received output fron C's commitment tx on B's chain
4432+ // Verify that B's ChannelManager is able to detect that HTLC is timeout by its own tx and react backward in consequence
4433+ nodes[ 1 ] . chain_monitor . block_connected_with_filtering ( & Block { header, txdata : vec ! [ commitment_tx[ 0 ] . clone( ) ] } , 200 ) ;
4434+ let node_txn = nodes[ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . clone ( ) ;
4435+ assert_eq ! ( node_txn. len( ) , 8 ) ; // ChannelManager : 2 (commitment tx, HTLC-Timeout), ChannelMonitor : 6 (commitment tx, HTLC-Timeout, timeout tx) * 2 (block-rescan)
4436+ assert_eq ! ( node_txn[ 2 ] . input[ 0 ] . previous_output. txid, node_txn[ 1 ] . txid( ) ) ;
4437+ assert_eq ! ( node_txn[ 2 ] . clone( ) . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , 133 ) ;
4438+
4439+ let mut commitment_tx_map = HashMap :: new ( ) ;
4440+ commitment_tx_map. insert ( commitment_tx[ 0 ] . txid ( ) , commitment_tx[ 0 ] . clone ( ) ) ;
4441+ node_txn[ 0 ] . verify ( & commitment_tx_map) . unwrap ( ) ;
4442+
4443+ nodes[ 1 ] . chain_monitor . block_connected_with_filtering ( & Block { header, txdata : vec ! [ node_txn[ 0 ] . clone( ) ] } , 1 ) ;
4444+ {
4445+ let mut added_monitors = nodes[ 1 ] . chan_monitor . added_monitors . lock ( ) . unwrap ( ) ;
4446+ assert_eq ! ( added_monitors. len( ) , 1 ) ;
4447+ added_monitors. clear ( ) ;
4448+ }
4449+ let events = nodes[ 1 ] . node . get_and_clear_pending_events ( ) ;
4450+ assert_eq ! ( events. len( ) , 2 ) ;
4451+ match events[ 0 ] {
4452+ Event :: BroadcastChannelUpdate { msg : msgs:: ChannelUpdate { .. } } => { } ,
4453+ _ => panic ! ( "Unexpected event" ) ,
4454+ }
4455+ match events[ 1 ] {
4456+ Event :: UpdateHTLCs { ref node_id, updates : msgs:: CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => {
4457+ assert ! ( update_add_htlcs. is_empty( ) ) ;
4458+ assert ! ( !update_fail_htlcs. is_empty( ) ) ;
4459+ assert ! ( update_fulfill_htlcs. is_empty( ) ) ;
4460+ assert ! ( update_fail_malformed_htlcs. is_empty( ) ) ;
4461+ assert_eq ! ( nodes[ 0 ] . node. get_our_node_id( ) , * node_id) ;
4462+ } ,
4463+ _ => panic ! ( "Unexpected event" ) ,
4464+ } ;
4465+
4466+ // Broadcast legit commitment tx from A on B's chain
4467+ // Broadcast HTLC Timeout tx by B on offered output from A commitment tx on A's chain
4468+ let commitment_tx = nodes[ 0 ] . node . channel_state . lock ( ) . unwrap ( ) . by_id . get ( & chan_1. 2 ) . unwrap ( ) . last_local_commitment_txn . clone ( ) ;
4469+ nodes[ 1 ] . chain_monitor . block_connected_with_filtering ( & Block { header, txdata : vec ! [ commitment_tx[ 0 ] . clone( ) ] } , 1 ) ;
4470+ let events = nodes[ 1 ] . node . get_and_clear_pending_events ( ) ;
4471+ assert_eq ! ( events. len( ) , 1 ) ;
4472+ match events[ 0 ] {
4473+ Event :: BroadcastChannelUpdate { msg : msgs:: ChannelUpdate { .. } } => { } ,
4474+ _ => panic ! ( "Unexpected event" ) ,
4475+ }
4476+ let node_txn = nodes[ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . clone ( ) ;
4477+
4478+ // Verify that A's ChannelManager is able to detect that HTLC is timeout by a HTLC Timeout tx and react backward in consequence
4479+ nodes[ 0 ] . chain_monitor . block_connected_with_filtering ( & Block { header, txdata : node_txn } , 1 ) ;
4480+ let events = nodes[ 0 ] . node . get_and_clear_pending_events ( ) ;
4481+ assert_eq ! ( events. len( ) , 1 ) ;
4482+ match events[ 0 ] {
4483+ Event :: BroadcastChannelUpdate { msg : msgs:: ChannelUpdate { .. } } => { } ,
4484+ _ => panic ! ( "Unexpected event" ) ,
4485+ }
4486+ }
4487+
43644488 #[ test]
43654489 fn test_htlc_ignore_latest_remote_commitment ( ) {
43664490 // Test that HTLC transactions spending the latest remote commitment transaction are simply
0 commit comments