Skip to content

Commit 742ea24

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 1f915c7 commit 742ea24

File tree

1 file changed

+87
-2
lines changed

1 file changed

+87
-2
lines changed

lightning/src/chain/channelmonitor.rs

+87-2
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,
@@ -398,6 +404,12 @@ enum OnchainEvent {
398404
txid: Txid,
399405
on_local_output_csv: Option<u16>,
400406
},
407+
HTLCSpendConfirmation {
408+
input_idx: u32,
409+
/// Only set if the claim was made by us with a preimage
410+
our_preimage: Option<PaymentPreimage>,
411+
on_to_local_output_csv: Option<u16>,
412+
},
401413
}
402414

403415
impl Writeable for OnchainEventEntry {
@@ -434,6 +446,7 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
434446
(0, source, required),
435447
(1, onchain_value_satoshis, option),
436448
(2, payment_hash, required),
449+
(3, input_idx, option),
437450
},
438451
(1, MaturingOutput) => {
439452
(0, descriptor, required),
@@ -442,6 +455,12 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
442455
(0, txid, required),
443456
(2, on_local_output_csv, option),
444457
},
458+
(5, HTLCSpendConfirmation) => {
459+
(0, input_idx, required),
460+
(2, our_preimage, option),
461+
(4, on_to_local_output_csv, option),
462+
},
463+
445464
);
446465

447466
#[cfg_attr(any(test, feature = "fuzztarget", feature = "_test_utils"), derive(PartialEq))]
@@ -502,6 +521,19 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
502521
},
503522
);
504523

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

617649
funding_spend_confirmed: Option<Txid>,
650+
/// The set of HTLCs which have been either claimed or failed on chain and have reached
651+
/// ANTI_REORG_DELAY confirmations on the claim/fail transaction.
652+
htlcs_resolved_on_chain: Vec<HTLCIrrevocablyResolved>,
618653

619654
// We simply modify best_block in Channel's block_connected so that serialization is
620655
// consistent but hopefully the users' copy handles block_connected in a consistent way.
@@ -675,7 +710,8 @@ impl<Signer: Sign> PartialEq for ChannelMonitorImpl<Signer> {
675710
self.outputs_to_watch != other.outputs_to_watch ||
676711
self.lockdown_from_offchain != other.lockdown_from_offchain ||
677712
self.holder_tx_signed != other.holder_tx_signed ||
678-
self.funding_spend_confirmed != other.funding_spend_confirmed
713+
self.funding_spend_confirmed != other.funding_spend_confirmed ||
714+
self.htlcs_resolved_on_chain != other.htlcs_resolved_on_chain
679715
{
680716
false
681717
} else {
@@ -842,6 +878,7 @@ impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
842878

843879
write_tlv_fields!(writer, {
844880
(1, self.funding_spend_confirmed, option),
881+
(3, self.htlcs_resolved_on_chain, vec_type),
845882
});
846883

847884
Ok(())
@@ -941,6 +978,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
941978
lockdown_from_offchain: false,
942979
holder_tx_signed: false,
943980
funding_spend_confirmed: None,
981+
htlcs_resolved_on_chain: Vec::new(),
944982

945983
best_block,
946984

@@ -1307,6 +1345,7 @@ macro_rules! fail_unbroadcast_htlcs {
13071345
source: (**source).clone(),
13081346
payment_hash: htlc.payment_hash.clone(),
13091347
onchain_value_satoshis: Some(htlc.amount_msat / 1000),
1348+
input_idx: None,
13101349
},
13111350
};
13121351
log_trace!($logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of {} commitment transaction, waiting for confirmation (at height {})",
@@ -2115,6 +2154,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
21152154
OnchainEvent::HTLCUpdate { source, .. } => Some(source),
21162155
OnchainEvent::MaturingOutput { .. } => None,
21172156
OnchainEvent::FundingSpendConfirmation { .. } => None,
2157+
OnchainEvent::HTLCSpendConfirmation { .. } => None,
21182158
})
21192159
.collect();
21202160
#[cfg(debug_assertions)]
@@ -2123,7 +2163,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
21232163
// Produce actionable events from on-chain events having reached their threshold.
21242164
for entry in onchain_events_reaching_threshold_conf.drain(..) {
21252165
match entry.event {
2126-
OnchainEvent::HTLCUpdate { ref source, payment_hash, onchain_value_satoshis } => {
2166+
OnchainEvent::HTLCUpdate { ref source, payment_hash, onchain_value_satoshis, input_idx } => {
21272167
// Check for duplicate HTLC resolutions.
21282168
#[cfg(debug_assertions)]
21292169
{
@@ -2147,13 +2187,19 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
21472187
source: source.clone(),
21482188
onchain_value_satoshis,
21492189
}));
2190+
if let Some(idx) = input_idx {
2191+
self.htlcs_resolved_on_chain.push(HTLCIrrevocablyResolved { input_idx: idx, payment_preimage: None });
2192+
}
21502193
},
21512194
OnchainEvent::MaturingOutput { descriptor } => {
21522195
log_debug!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
21532196
self.pending_events.push(Event::SpendableOutputs {
21542197
outputs: vec![descriptor]
21552198
});
21562199
},
2200+
OnchainEvent::HTLCSpendConfirmation { input_idx, our_preimage, .. } => {
2201+
self.htlcs_resolved_on_chain.push(HTLCIrrevocablyResolved { input_idx, payment_preimage: our_preimage });
2202+
},
21572203
OnchainEvent::FundingSpendConfirmation { txid, .. } => {
21582204
self.funding_spend_confirmed = Some(txid);
21592205
},
@@ -2335,6 +2381,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
23352381
|| (input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::AcceptedHTLC) && input.witness[1].len() == 33);
23362382
let accepted_preimage_claim = input.witness.len() == 5 && HTLCType::scriptlen_to_htlctype(input.witness[4].len()) == Some(HTLCType::AcceptedHTLC);
23372383
let offered_preimage_claim = input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::OfferedHTLC);
2384+
let offered_timeout_claim = input.witness.len() == 5 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::OfferedHTLC);
23382385

23392386
macro_rules! log_claim {
23402387
($tx_info: expr, $holder_tx: expr, $htlc: expr, $source_avail: expr) => {
@@ -2394,6 +2441,21 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
23942441
}
23952442
if payment_data.is_none() {
23962443
log_claim!($tx_info, $holder_tx, htlc_output, false);
2444+
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
2445+
txid: tx.txid(), height,
2446+
event: OnchainEvent::HTLCSpendConfirmation {
2447+
input_idx: input.previous_output.vout,
2448+
our_preimage: None,
2449+
// `payment_data.is_none()` implies that this is our
2450+
// payment, as we haven't learned anything to cause us to
2451+
// update another channel or our offchain state. Thus, wait
2452+
// for the CSV delay before dropping the HTLC from
2453+
// claimable balance if the claim was an HTLC-Success or
2454+
// HTLC-Timeout transaction.
2455+
on_to_local_output_csv: if accepted_preimage_claim || offered_timeout_claim {
2456+
Some(self.on_holder_tx_csv) } else { None },
2457+
},
2458+
});
23972459
continue 'outer_loop;
23982460
}
23992461
}
@@ -2424,6 +2486,15 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
24242486
if !self.pending_monitor_events.iter().any(
24252487
|update| if let &MonitorEvent::HTLCEvent(ref upd) = update { upd.source == source } else { false }) {
24262488
payment_preimage.0.copy_from_slice(&input.witness[3]);
2489+
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
2490+
txid: tx.txid(),
2491+
height,
2492+
event: OnchainEvent::HTLCSpendConfirmation {
2493+
input_idx: input.previous_output.vout,
2494+
our_preimage: Some(payment_preimage),
2495+
on_to_local_output_csv: None,
2496+
},
2497+
});
24272498
self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
24282499
source,
24292500
payment_preimage: Some(payment_preimage),
@@ -2437,6 +2508,15 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
24372508
upd.source == source
24382509
} else { false }) {
24392510
payment_preimage.0.copy_from_slice(&input.witness[1]);
2511+
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
2512+
txid: tx.txid(),
2513+
height,
2514+
event: OnchainEvent::HTLCSpendConfirmation {
2515+
input_idx: input.previous_output.vout,
2516+
our_preimage: Some(payment_preimage),
2517+
on_to_local_output_csv: None,
2518+
},
2519+
});
24402520
self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
24412521
source,
24422522
payment_preimage: Some(payment_preimage),
@@ -2454,12 +2534,14 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
24542534
_ => true,
24552535
}
24562536
});
2537+
let txid = tx.txid();
24572538
let entry = OnchainEventEntry {
24582539
txid: tx.txid(),
24592540
height,
24602541
event: OnchainEvent::HTLCUpdate {
24612542
source, payment_hash,
24622543
onchain_value_satoshis: Some(amount_msat / 1000),
2544+
input_idx: Some(input.previous_output.vout),
24632545
},
24642546
};
24652547
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());
@@ -2832,8 +2914,10 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
28322914
}
28332915

28342916
let mut funding_spend_confirmed = None;
2917+
let mut htlcs_resolved_on_chain = Some(Vec::new());
28352918
read_tlv_fields!(reader, {
28362919
(1, funding_spend_confirmed, option),
2920+
(3, htlcs_resolved_on_chain, vec_type),
28372921
});
28382922

28392923
let mut secp_ctx = Secp256k1::new();
@@ -2884,6 +2968,7 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
28842968
lockdown_from_offchain,
28852969
holder_tx_signed,
28862970
funding_spend_confirmed,
2971+
htlcs_resolved_on_chain: htlcs_resolved_on_chain.unwrap(),
28872972

28882973
best_block,
28892974

0 commit comments

Comments
 (0)