Skip to content

Commit fa67e3a

Browse files
committed
Track how our HTLCs are resolved on-chain persistently
This tracks how any HTLC outputs in broadcast commitment transactions are resolved on-chain, storing the result of the HTLC resolution persistently in the ChannelMonitor. This can be used to determine which outputs may still be available for claiming on-chain.
1 parent 9e328ee commit fa67e3a

File tree

1 file changed

+87
-2
lines changed

1 file changed

+87
-2
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,11 @@ impl OnchainEventEntry {
369369
// it's broadcastable when we see the previous block.
370370
conf_threshold = cmp::max(conf_threshold, self.height + csv as u32 - 1);
371371
},
372+
OnchainEvent::HTLCSpendConfirmation { on_to_local_output_csv: Some(csv), .. } => {
373+
// A CSV'd transaction is confirmable in block (input height) + CSV delay, which means
374+
// it's broadcastable when we see the previous block.
375+
conf_threshold = cmp::max(conf_threshold, self.height + csv as u32 - 1);
376+
},
372377
_ => {},
373378
}
374379
conf_threshold
@@ -390,6 +395,7 @@ enum OnchainEvent {
390395
source: HTLCSource,
391396
payment_hash: PaymentHash,
392397
onchain_value_satoshis: Option<u64>,
398+
input_idx: Option<u32>,
393399
},
394400
MaturingOutput {
395401
descriptor: SpendableOutputDescriptor,
@@ -402,6 +408,12 @@ enum OnchainEvent {
402408
/// commitment transaction, and this is the delay on the to_self output).
403409
on_local_output_csv: Option<u16>,
404410
},
411+
HTLCSpendConfirmation {
412+
input_idx: u32,
413+
/// Only set if the claim was made by us with a preimage
414+
our_preimage: Option<PaymentPreimage>,
415+
on_to_local_output_csv: Option<u16>,
416+
},
405417
}
406418

407419
impl Writeable for OnchainEventEntry {
@@ -438,6 +450,7 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
438450
(0, source, required),
439451
(1, onchain_value_satoshis, option),
440452
(2, payment_hash, required),
453+
(3, input_idx, option),
441454
},
442455
(1, MaturingOutput) => {
443456
(0, descriptor, required),
@@ -446,6 +459,12 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
446459
(0, txid, required),
447460
(2, on_local_output_csv, option),
448461
},
462+
(5, HTLCSpendConfirmation) => {
463+
(0, input_idx, required),
464+
(2, our_preimage, option),
465+
(4, on_to_local_output_csv, option),
466+
},
467+
449468
);
450469

451470
#[cfg_attr(any(test, feature = "fuzztarget", feature = "_test_utils"), derive(PartialEq))]
@@ -506,6 +525,19 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
506525
},
507526
);
508527

528+
/// An HTLC which has been irrevocably resolved on-chain, and has reached ANTI_REORG_DELAY.
529+
#[derive(PartialEq)]
530+
struct HTLCIrrevocablyResolved {
531+
input_idx: u32,
532+
/// Only set if the HTLC claim was ours using a payment preimage
533+
payment_preimage: Option<PaymentPreimage>,
534+
}
535+
536+
impl_writeable_tlv_based!(HTLCIrrevocablyResolved, {
537+
(0, input_idx, required),
538+
(2, payment_preimage, option),
539+
});
540+
509541
/// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates
510542
/// on-chain transactions to ensure no loss of funds occurs.
511543
///
@@ -619,6 +651,9 @@ pub(crate) struct ChannelMonitorImpl<Signer: Sign> {
619651
holder_tx_signed: bool,
620652

621653
funding_spend_confirmed: Option<Txid>,
654+
/// The set of HTLCs which have been either claimed or failed on chain and have reached
655+
/// ANTI_REORG_DELAY confirmations on the claim/fail transaction.
656+
htlcs_resolved_on_chain: Vec<HTLCIrrevocablyResolved>,
622657

623658
// We simply modify best_block in Channel's block_connected so that serialization is
624659
// consistent but hopefully the users' copy handles block_connected in a consistent way.
@@ -679,7 +714,8 @@ impl<Signer: Sign> PartialEq for ChannelMonitorImpl<Signer> {
679714
self.outputs_to_watch != other.outputs_to_watch ||
680715
self.lockdown_from_offchain != other.lockdown_from_offchain ||
681716
self.holder_tx_signed != other.holder_tx_signed ||
682-
self.funding_spend_confirmed != other.funding_spend_confirmed
717+
self.funding_spend_confirmed != other.funding_spend_confirmed ||
718+
self.htlcs_resolved_on_chain != other.htlcs_resolved_on_chain
683719
{
684720
false
685721
} else {
@@ -846,6 +882,7 @@ impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
846882

847883
write_tlv_fields!(writer, {
848884
(1, self.funding_spend_confirmed, option),
885+
(3, self.htlcs_resolved_on_chain, vec_type),
849886
});
850887

851888
Ok(())
@@ -945,6 +982,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
945982
lockdown_from_offchain: false,
946983
holder_tx_signed: false,
947984
funding_spend_confirmed: None,
985+
htlcs_resolved_on_chain: Vec::new(),
948986

949987
best_block,
950988

@@ -1311,6 +1349,7 @@ macro_rules! fail_unbroadcast_htlcs {
13111349
source: (**source).clone(),
13121350
payment_hash: htlc.payment_hash.clone(),
13131351
onchain_value_satoshis: Some(htlc.amount_msat / 1000),
1352+
input_idx: None,
13141353
},
13151354
};
13161355
log_trace!($logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of {} commitment transaction, waiting for confirmation (at height {})",
@@ -2119,6 +2158,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
21192158
OnchainEvent::HTLCUpdate { source, .. } => Some(source),
21202159
OnchainEvent::MaturingOutput { .. } => None,
21212160
OnchainEvent::FundingSpendConfirmation { .. } => None,
2161+
OnchainEvent::HTLCSpendConfirmation { .. } => None,
21222162
})
21232163
.collect();
21242164
#[cfg(debug_assertions)]
@@ -2127,7 +2167,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
21272167
// Produce actionable events from on-chain events having reached their threshold.
21282168
for entry in onchain_events_reaching_threshold_conf.drain(..) {
21292169
match entry.event {
2130-
OnchainEvent::HTLCUpdate { ref source, payment_hash, onchain_value_satoshis } => {
2170+
OnchainEvent::HTLCUpdate { ref source, payment_hash, onchain_value_satoshis, input_idx } => {
21312171
// Check for duplicate HTLC resolutions.
21322172
#[cfg(debug_assertions)]
21332173
{
@@ -2151,13 +2191,19 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
21512191
source: source.clone(),
21522192
onchain_value_satoshis,
21532193
}));
2194+
if let Some(idx) = input_idx {
2195+
self.htlcs_resolved_on_chain.push(HTLCIrrevocablyResolved { input_idx: idx, payment_preimage: None });
2196+
}
21542197
},
21552198
OnchainEvent::MaturingOutput { descriptor } => {
21562199
log_debug!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
21572200
self.pending_events.push(Event::SpendableOutputs {
21582201
outputs: vec![descriptor]
21592202
});
21602203
},
2204+
OnchainEvent::HTLCSpendConfirmation { input_idx, our_preimage, .. } => {
2205+
self.htlcs_resolved_on_chain.push(HTLCIrrevocablyResolved { input_idx, payment_preimage: our_preimage });
2206+
},
21612207
OnchainEvent::FundingSpendConfirmation { txid, .. } => {
21622208
self.funding_spend_confirmed = Some(txid);
21632209
},
@@ -2339,6 +2385,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
23392385
|| (input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::AcceptedHTLC) && input.witness[1].len() == 33);
23402386
let accepted_preimage_claim = input.witness.len() == 5 && HTLCType::scriptlen_to_htlctype(input.witness[4].len()) == Some(HTLCType::AcceptedHTLC);
23412387
let offered_preimage_claim = input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::OfferedHTLC);
2388+
let offered_timeout_claim = input.witness.len() == 5 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::OfferedHTLC);
23422389

23432390
macro_rules! log_claim {
23442391
($tx_info: expr, $holder_tx: expr, $htlc: expr, $source_avail: expr) => {
@@ -2398,6 +2445,21 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
23982445
}
23992446
if payment_data.is_none() {
24002447
log_claim!($tx_info, $holder_tx, htlc_output, false);
2448+
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
2449+
txid: tx.txid(), height,
2450+
event: OnchainEvent::HTLCSpendConfirmation {
2451+
input_idx: input.previous_output.vout,
2452+
our_preimage: None,
2453+
// `payment_data.is_none()` implies that this is our
2454+
// payment, as we haven't learned anything to cause us to
2455+
// update another channel or our offchain state. Thus, wait
2456+
// for the CSV delay before dropping the HTLC from
2457+
// claimable balance if the claim was an HTLC-Success or
2458+
// HTLC-Timeout transaction.
2459+
on_to_local_output_csv: if accepted_preimage_claim || offered_timeout_claim {
2460+
Some(self.on_holder_tx_csv) } else { None },
2461+
},
2462+
});
24012463
continue 'outer_loop;
24022464
}
24032465
}
@@ -2428,6 +2490,15 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
24282490
if !self.pending_monitor_events.iter().any(
24292491
|update| if let &MonitorEvent::HTLCEvent(ref upd) = update { upd.source == source } else { false }) {
24302492
payment_preimage.0.copy_from_slice(&input.witness[3]);
2493+
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
2494+
txid: tx.txid(),
2495+
height,
2496+
event: OnchainEvent::HTLCSpendConfirmation {
2497+
input_idx: input.previous_output.vout,
2498+
our_preimage: Some(payment_preimage),
2499+
on_to_local_output_csv: None,
2500+
},
2501+
});
24312502
self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
24322503
source,
24332504
payment_preimage: Some(payment_preimage),
@@ -2441,6 +2512,15 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
24412512
upd.source == source
24422513
} else { false }) {
24432514
payment_preimage.0.copy_from_slice(&input.witness[1]);
2515+
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
2516+
txid: tx.txid(),
2517+
height,
2518+
event: OnchainEvent::HTLCSpendConfirmation {
2519+
input_idx: input.previous_output.vout,
2520+
our_preimage: Some(payment_preimage),
2521+
on_to_local_output_csv: None,
2522+
},
2523+
});
24442524
self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
24452525
source,
24462526
payment_preimage: Some(payment_preimage),
@@ -2458,12 +2538,14 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
24582538
_ => true,
24592539
}
24602540
});
2541+
let txid = tx.txid();
24612542
let entry = OnchainEventEntry {
24622543
txid: tx.txid(),
24632544
height,
24642545
event: OnchainEvent::HTLCUpdate {
24652546
source, payment_hash,
24662547
onchain_value_satoshis: Some(amount_msat / 1000),
2548+
input_idx: Some(input.previous_output.vout),
24672549
},
24682550
};
24692551
log_info!(logger, "Failing HTLC with payment_hash {} timeout by a spend tx, waiting for confirmation (at height {})", log_bytes!(payment_hash.0), entry.confirmation_threshold());
@@ -2836,8 +2918,10 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
28362918
}
28372919

28382920
let mut funding_spend_confirmed = None;
2921+
let mut htlcs_resolved_on_chain = Some(Vec::new());
28392922
read_tlv_fields!(reader, {
28402923
(1, funding_spend_confirmed, option),
2924+
(3, htlcs_resolved_on_chain, vec_type),
28412925
});
28422926

28432927
let mut secp_ctx = Secp256k1::new();
@@ -2888,6 +2972,7 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
28882972
lockdown_from_offchain,
28892973
holder_tx_signed,
28902974
funding_spend_confirmed,
2975+
htlcs_resolved_on_chain: htlcs_resolved_on_chain.unwrap(),
28912976

28922977
best_block,
28932978

0 commit comments

Comments
 (0)