@@ -444,6 +444,15 @@ pub(super) struct Channel<Signer: Sign> {
444444 ///
445445 /// See-also <https://github.com/lightningnetwork/lnd/issues/4006>
446446 pub workaround_lnd_bug_4006 : Option < msgs:: FundingLocked > ,
447+
448+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
449+ // When we receive an HTLC fulfill on an outbound path, we may immediately fulfill the
450+ // corresponding HTLC on the inbound path. If, then, the outbound path channel is
451+ // disconnected and reconnected (before we've exchange commitment_signed and revoke_and_ack
452+ // messages), they may re-broadcast their update_fulfill_htlc, causing a duplicate claim. This
453+ // is fine, but as a sanity check in our failure to generate the second claim, we check here
454+ // that the original was a claim, and that we aren't now trying to fulfill a failed HTLC.
455+ historical_inbound_htlc_fulfills : HashSet < u64 > ,
447456}
448457
449458#[ cfg( any( test, feature = "fuzztarget" ) ) ]
@@ -645,6 +654,9 @@ impl<Signer: Sign> Channel<Signer> {
645654 next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
646655
647656 workaround_lnd_bug_4006 : None ,
657+
658+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
659+ historical_inbound_htlc_fulfills : HashSet :: new ( ) ,
648660 } )
649661 }
650662
@@ -890,6 +902,9 @@ impl<Signer: Sign> Channel<Signer> {
890902 next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
891903
892904 workaround_lnd_bug_4006 : None ,
905+
906+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
907+ historical_inbound_htlc_fulfills : HashSet :: new ( ) ,
893908 } ;
894909
895910 Ok ( chan)
@@ -1249,8 +1264,8 @@ impl<Signer: Sign> Channel<Signer> {
12491264 if let & InboundHTLCRemovalReason :: Fulfill ( _) = reason {
12501265 } else {
12511266 log_warn ! ( logger, "Have preimage and want to fulfill HTLC with payment hash {} we already failed against channel {}" , log_bytes!( htlc. payment_hash. 0 ) , log_bytes!( self . channel_id( ) ) ) ;
1267+ debug_assert ! ( false , "Tried to fulfill an HTLC that was already failed" ) ;
12521268 }
1253- debug_assert ! ( false , "Tried to fulfill an HTLC that was already fail/fulfilled" ) ;
12541269 return Ok ( ( None , None ) ) ;
12551270 } ,
12561271 _ => {
@@ -1263,7 +1278,11 @@ impl<Signer: Sign> Channel<Signer> {
12631278 }
12641279 }
12651280 if pending_idx == core:: usize:: MAX {
1266- return Err ( ChannelError :: Ignore ( "Unable to find a pending HTLC which matched the given HTLC ID" . to_owned ( ) ) ) ;
1281+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1282+ // If we failed to find an HTLC to fulfill, make sure it was previously fulfilled and
1283+ // this is simply a duplicate claim, not previously failed and we lost funds.
1284+ debug_assert ! ( self . historical_inbound_htlc_fulfills. contains( & htlc_id_arg) ) ;
1285+ return Ok ( ( None , None ) ) ;
12671286 }
12681287
12691288 // Now update local state:
@@ -1285,7 +1304,8 @@ impl<Signer: Sign> Channel<Signer> {
12851304 if htlc_id_arg == htlc_id {
12861305 // Make sure we don't leave latest_monitor_update_id incremented here:
12871306 self . latest_monitor_update_id -= 1 ;
1288- debug_assert ! ( false , "Tried to fulfill an HTLC that was already fulfilled" ) ;
1307+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1308+ debug_assert ! ( self . historical_inbound_htlc_fulfills. contains( & htlc_id_arg) ) ;
12891309 return Ok ( ( None , None ) ) ;
12901310 }
12911311 } ,
@@ -1305,8 +1325,12 @@ impl<Signer: Sign> Channel<Signer> {
13051325 self . holding_cell_htlc_updates . push ( HTLCUpdateAwaitingACK :: ClaimHTLC {
13061326 payment_preimage : payment_preimage_arg, htlc_id : htlc_id_arg,
13071327 } ) ;
1328+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1329+ self . historical_inbound_htlc_fulfills . insert ( htlc_id_arg) ;
13081330 return Ok ( ( None , Some ( monitor_update) ) ) ;
13091331 }
1332+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1333+ self . historical_inbound_htlc_fulfills . insert ( htlc_id_arg) ;
13101334
13111335 {
13121336 let htlc = & mut self . pending_inbound_htlcs [ pending_idx] ;
@@ -1366,8 +1390,11 @@ impl<Signer: Sign> Channel<Signer> {
13661390 if htlc. htlc_id == htlc_id_arg {
13671391 match htlc. state {
13681392 InboundHTLCState :: Committed => { } ,
1369- InboundHTLCState :: LocalRemoved ( _) => {
1370- debug_assert ! ( false , "Tried to fail an HTLC that was already fail/fulfilled" ) ;
1393+ InboundHTLCState :: LocalRemoved ( ref reason) => {
1394+ if let & InboundHTLCRemovalReason :: Fulfill ( _) = reason {
1395+ } else {
1396+ debug_assert ! ( false , "Tried to fail an HTLC that was already failed" ) ;
1397+ }
13711398 return Ok ( None ) ;
13721399 } ,
13731400 _ => {
@@ -1379,7 +1406,11 @@ impl<Signer: Sign> Channel<Signer> {
13791406 }
13801407 }
13811408 if pending_idx == core:: usize:: MAX {
1382- return Err ( ChannelError :: Ignore ( "Unable to find a pending HTLC which matched the given HTLC ID" . to_owned ( ) ) ) ;
1409+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1410+ // If we failed to find an HTLC to fail, make sure it was previously fulfilled and this
1411+ // is simply a duplicate fail, not previously failed and we failed-back too early.
1412+ debug_assert ! ( self . historical_inbound_htlc_fulfills. contains( & htlc_id_arg) ) ;
1413+ return Ok ( None ) ;
13831414 }
13841415
13851416 // Now update local state:
@@ -1388,8 +1419,9 @@ impl<Signer: Sign> Channel<Signer> {
13881419 match pending_update {
13891420 & HTLCUpdateAwaitingACK :: ClaimHTLC { htlc_id, .. } => {
13901421 if htlc_id_arg == htlc_id {
1391- debug_assert ! ( false , "Tried to fail an HTLC that was already fulfilled" ) ;
1392- return Err ( ChannelError :: Ignore ( "Unable to find a pending HTLC which matched the given HTLC ID" . to_owned ( ) ) ) ;
1422+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1423+ debug_assert ! ( self . historical_inbound_htlc_fulfills. contains( & htlc_id_arg) ) ;
1424+ return Ok ( None ) ;
13931425 }
13941426 } ,
13951427 & HTLCUpdateAwaitingACK :: FailHTLC { htlc_id, .. } => {
@@ -2453,7 +2485,14 @@ impl<Signer: Sign> Channel<Signer> {
24532485 } ,
24542486 & HTLCUpdateAwaitingACK :: FailHTLC { htlc_id, ref err_packet } => {
24552487 match self . get_update_fail_htlc ( htlc_id, err_packet. clone ( ) , logger) {
2456- Ok ( update_fail_msg_option) => update_fail_htlcs. push ( update_fail_msg_option. unwrap ( ) ) ,
2488+ Ok ( update_fail_msg_option) => {
2489+ // If an HTLC failure was previously added to the holding cell (via
2490+ // `get_update_fail_htlc`) then generating the fail message itself
2491+ // must not fail - we should never end up in a state where we
2492+ // double-fail an HTLC or fail-then-claim an HTLC as it indicates
2493+ // we didn't wait for a full revocation before failing.
2494+ update_fail_htlcs. push ( update_fail_msg_option. unwrap ( ) )
2495+ } ,
24572496 Err ( e) => {
24582497 if let ChannelError :: Ignore ( _) = e { }
24592498 else {
@@ -4690,6 +4729,13 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
46904729
46914730 self . channel_update_status . write ( writer) ?;
46924731
4732+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4733+ ( self . historical_inbound_htlc_fulfills . len ( ) as u64 ) . write ( writer) ?;
4734+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4735+ for htlc in self . historical_inbound_htlc_fulfills . iter ( ) {
4736+ htlc. write ( writer) ?;
4737+ }
4738+
46934739 write_tlv_fields ! ( writer, {
46944740 ( 0 , self . announcement_sigs, option) ,
46954741 // minimum_depth and counterparty_selected_channel_reserve_satoshis used to have a
@@ -4882,6 +4928,16 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
48824928
48834929 let channel_update_status = Readable :: read ( reader) ?;
48844930
4931+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4932+ let mut historical_inbound_htlc_fulfills = HashSet :: new ( ) ;
4933+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
4934+ {
4935+ let htlc_fulfills_len: u64 = Readable :: read ( reader) ?;
4936+ for _ in 0 ..htlc_fulfills_len {
4937+ assert ! ( historical_inbound_htlc_fulfills. insert( Readable :: read( reader) ?) ) ;
4938+ }
4939+ }
4940+
48854941 let mut announcement_sigs = None ;
48864942 read_tlv_fields ! ( reader, {
48874943 ( 0 , announcement_sigs, option) ,
@@ -4973,6 +5029,9 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
49735029 next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
49745030
49755031 workaround_lnd_bug_4006 : None ,
5032+
5033+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
5034+ historical_inbound_htlc_fulfills,
49765035 } )
49775036 }
49785037}
0 commit comments