@@ -444,6 +444,15 @@ pub(super) struct Channel<Signer: Sign> {
444
444
///
445
445
/// See-also <https://github.com/lightningnetwork/lnd/issues/4006>
446
446
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 > ,
447
456
}
448
457
449
458
#[ cfg( any( test, feature = "fuzztarget" ) ) ]
@@ -645,6 +654,9 @@ impl<Signer: Sign> Channel<Signer> {
645
654
next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
646
655
647
656
workaround_lnd_bug_4006 : None ,
657
+
658
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
659
+ historical_inbound_htlc_fulfills : HashSet :: new ( ) ,
648
660
} )
649
661
}
650
662
@@ -890,6 +902,9 @@ impl<Signer: Sign> Channel<Signer> {
890
902
next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
891
903
892
904
workaround_lnd_bug_4006 : None ,
905
+
906
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
907
+ historical_inbound_htlc_fulfills : HashSet :: new ( ) ,
893
908
} ;
894
909
895
910
Ok ( chan)
@@ -1249,8 +1264,8 @@ impl<Signer: Sign> Channel<Signer> {
1249
1264
if let & InboundHTLCRemovalReason :: Fulfill ( _) = reason {
1250
1265
} else {
1251
1266
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" ) ;
1252
1268
}
1253
- debug_assert ! ( false , "Tried to fulfill an HTLC that was already fail/fulfilled" ) ;
1254
1269
return Ok ( ( None , None ) ) ;
1255
1270
} ,
1256
1271
_ => {
@@ -1263,7 +1278,11 @@ impl<Signer: Sign> Channel<Signer> {
1263
1278
}
1264
1279
}
1265
1280
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 ) ) ;
1267
1286
}
1268
1287
1269
1288
// Now update local state:
@@ -1285,7 +1304,8 @@ impl<Signer: Sign> Channel<Signer> {
1285
1304
if htlc_id_arg == htlc_id {
1286
1305
// Make sure we don't leave latest_monitor_update_id incremented here:
1287
1306
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) ) ;
1289
1309
return Ok ( ( None , None ) ) ;
1290
1310
}
1291
1311
} ,
@@ -1305,8 +1325,12 @@ impl<Signer: Sign> Channel<Signer> {
1305
1325
self . holding_cell_htlc_updates . push ( HTLCUpdateAwaitingACK :: ClaimHTLC {
1306
1326
payment_preimage : payment_preimage_arg, htlc_id : htlc_id_arg,
1307
1327
} ) ;
1328
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1329
+ self . historical_inbound_htlc_fulfills . insert ( htlc_id_arg) ;
1308
1330
return Ok ( ( None , Some ( monitor_update) ) ) ;
1309
1331
}
1332
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
1333
+ self . historical_inbound_htlc_fulfills . insert ( htlc_id_arg) ;
1310
1334
1311
1335
{
1312
1336
let htlc = & mut self . pending_inbound_htlcs [ pending_idx] ;
@@ -1366,8 +1390,11 @@ impl<Signer: Sign> Channel<Signer> {
1366
1390
if htlc. htlc_id == htlc_id_arg {
1367
1391
match htlc. state {
1368
1392
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
+ }
1371
1398
return Ok ( None ) ;
1372
1399
} ,
1373
1400
_ => {
@@ -1379,7 +1406,11 @@ impl<Signer: Sign> Channel<Signer> {
1379
1406
}
1380
1407
}
1381
1408
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 ) ;
1383
1414
}
1384
1415
1385
1416
// Now update local state:
@@ -1388,8 +1419,9 @@ impl<Signer: Sign> Channel<Signer> {
1388
1419
match pending_update {
1389
1420
& HTLCUpdateAwaitingACK :: ClaimHTLC { htlc_id, .. } => {
1390
1421
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 ) ;
1393
1425
}
1394
1426
} ,
1395
1427
& HTLCUpdateAwaitingACK :: FailHTLC { htlc_id, .. } => {
@@ -2453,7 +2485,14 @@ impl<Signer: Sign> Channel<Signer> {
2453
2485
} ,
2454
2486
& HTLCUpdateAwaitingACK :: FailHTLC { htlc_id, ref err_packet } => {
2455
2487
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
+ } ,
2457
2496
Err ( e) => {
2458
2497
if let ChannelError :: Ignore ( _) = e { }
2459
2498
else {
@@ -4690,6 +4729,13 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
4690
4729
4691
4730
self . channel_update_status . write ( writer) ?;
4692
4731
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
+
4693
4739
write_tlv_fields ! ( writer, {
4694
4740
( 0 , self . announcement_sigs, option) ,
4695
4741
// 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>
4882
4928
4883
4929
let channel_update_status = Readable :: read ( reader) ?;
4884
4930
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
+
4885
4941
let mut announcement_sigs = None ;
4886
4942
read_tlv_fields ! ( reader, {
4887
4943
( 0 , announcement_sigs, option) ,
@@ -4973,6 +5029,9 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
4973
5029
next_remote_commitment_tx_fee_info_cached : Mutex :: new ( None ) ,
4974
5030
4975
5031
workaround_lnd_bug_4006 : None ,
5032
+
5033
+ #[ cfg( any( test, feature = "fuzztarget" ) ) ]
5034
+ historical_inbound_htlc_fulfills,
4976
5035
} )
4977
5036
}
4978
5037
}
0 commit comments