Skip to content

Commit b8414b7

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 49bbe82 commit b8414b7

File tree

1 file changed

+88
-5
lines changed

1 file changed

+88
-5
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,11 @@ impl OnchainEventEntry {
367367
// it's broadcastable when we see the previous block.
368368
conf_threshold = cmp::max(conf_threshold, self.height + csv as u32 - 1);
369369
},
370+
OnchainEvent::HTLCSpendConfirmation { on_to_local_output_csv: Some(csv), .. } => {
371+
// A CSV'd transaction is confirmable in block (input height) + CSV delay, which means
372+
// it's broadcastable when we see the previous block.
373+
conf_threshold = cmp::max(conf_threshold, self.height + csv as u32 - 1);
374+
},
370375
_ => {},
371376
}
372377
conf_threshold
@@ -387,6 +392,7 @@ enum OnchainEvent {
387392
HTLCUpdate {
388393
source: HTLCSource,
389394
payment_hash: PaymentHash,
395+
input_idx: Option<u32>,
390396
},
391397
MaturingOutput {
392398
descriptor: SpendableOutputDescriptor,
@@ -395,6 +401,12 @@ enum OnchainEvent {
395401
txid: Txid,
396402
on_local_output_csv: Option<u16>,
397403
},
404+
HTLCSpendConfirmation {
405+
input_idx: u32,
406+
/// Only set if the claim was made by us with a preimage
407+
our_preimage: Option<PaymentPreimage>,
408+
on_to_local_output_csv: Option<u16>,
409+
},
398410
}
399411

400412
impl Writeable for OnchainEventEntry {
@@ -429,6 +441,7 @@ impl MaybeReadable for OnchainEventEntry {
429441
impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
430442
(0, HTLCUpdate) => {
431443
(0, source, required),
444+
(1, input_idx, option),
432445
(2, payment_hash, required),
433446
},
434447
(1, MaturingOutput) => {
@@ -438,6 +451,12 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent,
438451
(0, txid, required),
439452
(2, on_local_output_csv, option),
440453
},
454+
(5, HTLCSpendConfirmation) => {
455+
(0, input_idx, required),
456+
(2, our_preimage, option),
457+
(4, on_to_local_output_csv, option),
458+
},
459+
441460
);
442461

443462
#[cfg_attr(any(test, feature = "fuzztarget", feature = "_test_utils"), derive(PartialEq))]
@@ -492,6 +511,19 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
492511
},
493512
);
494513

514+
/// An HTLC which has been irrevocably resolved on-chain, and has reached ANTI_REORG_DELAY.
515+
#[derive(PartialEq)]
516+
struct HTLCIrrevocablyResolved {
517+
input_idx: u32,
518+
/// Only set if the HTLC claim was ours using a payment preimage
519+
payment_preimage: Option<PaymentPreimage>,
520+
}
521+
522+
impl_writeable_tlv_based!(HTLCIrrevocablyResolved, {
523+
(0, input_idx, required),
524+
(2, payment_preimage, option),
525+
});
526+
495527
/// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates
496528
/// on-chain transactions to ensure no loss of funds occurs.
497529
///
@@ -602,6 +634,9 @@ pub(crate) struct ChannelMonitorImpl<Signer: Sign> {
602634
holder_tx_signed: bool,
603635

604636
funding_spend_confirmed: Option<Txid>,
637+
/// The set of HTLCs which have been either claimed or failed on chain and have reached
638+
/// ANTI_REORG_DELAY confirmations on the claim/fail transaction.
639+
htlcs_resolved_on_chain: Vec<HTLCIrrevocablyResolved>,
605640

606641
// We simply modify best_block in Channel's block_connected so that serialization is
607642
// consistent but hopefully the users' copy handles block_connected in a consistent way.
@@ -662,7 +697,8 @@ impl<Signer: Sign> PartialEq for ChannelMonitorImpl<Signer> {
662697
self.outputs_to_watch != other.outputs_to_watch ||
663698
self.lockdown_from_offchain != other.lockdown_from_offchain ||
664699
self.holder_tx_signed != other.holder_tx_signed ||
665-
self.funding_spend_confirmed != other.funding_spend_confirmed
700+
self.funding_spend_confirmed != other.funding_spend_confirmed ||
701+
self.htlcs_resolved_on_chain != other.htlcs_resolved_on_chain
666702
{
667703
false
668704
} else {
@@ -826,6 +862,7 @@ impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
826862

827863
write_tlv_fields!(writer, {
828864
(1, self.funding_spend_confirmed, option),
865+
(3, self.htlcs_resolved_on_chain, vec_type),
829866
});
830867

831868
Ok(())
@@ -927,6 +964,7 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
927964
lockdown_from_offchain: false,
928965
holder_tx_signed: false,
929966
funding_spend_confirmed: None,
967+
htlcs_resolved_on_chain: Vec::new(),
930968

931969
best_block,
932970

@@ -1280,6 +1318,7 @@ macro_rules! fail_unbroadcast_htlcs {
12801318
event: OnchainEvent::HTLCUpdate {
12811319
source: (**source).clone(),
12821320
payment_hash: htlc.payment_hash.clone(),
1321+
input_idx: None,
12831322
},
12841323
};
12851324
log_trace!($logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of {} commitment transaction, waiting for confirmation (at height {})",
@@ -2082,6 +2121,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
20822121
OnchainEvent::HTLCUpdate { source, .. } => Some(source),
20832122
OnchainEvent::MaturingOutput { .. } => None,
20842123
OnchainEvent::FundingSpendConfirmation { .. } => None,
2124+
OnchainEvent::HTLCSpendConfirmation { .. } => None,
20852125
})
20862126
.collect();
20872127
#[cfg(debug_assertions)]
@@ -2090,7 +2130,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
20902130
// Produce actionable events from on-chain events having reached their threshold.
20912131
for entry in onchain_events_reaching_threshold_conf.drain(..) {
20922132
match entry.event {
2093-
OnchainEvent::HTLCUpdate { ref source, payment_hash } => {
2133+
OnchainEvent::HTLCUpdate { ref source, payment_hash, input_idx } => {
20942134
// Check for duplicate HTLC resolutions.
20952135
#[cfg(debug_assertions)]
20962136
{
@@ -2113,13 +2153,19 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
21132153
payment_preimage: None,
21142154
source: source.clone(),
21152155
}));
2156+
if let Some(idx) = input_idx {
2157+
self.htlcs_resolved_on_chain.push(HTLCIrrevocablyResolved { input_idx: idx, payment_preimage: None });
2158+
}
21162159
},
21172160
OnchainEvent::MaturingOutput { descriptor } => {
21182161
log_debug!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
21192162
self.pending_events.push(Event::SpendableOutputs {
21202163
outputs: vec![descriptor]
21212164
});
21222165
},
2166+
OnchainEvent::HTLCSpendConfirmation { input_idx, our_preimage, .. } => {
2167+
self.htlcs_resolved_on_chain.push(HTLCIrrevocablyResolved { input_idx, payment_preimage: our_preimage });
2168+
},
21232169
OnchainEvent::FundingSpendConfirmation { txid, .. } => {
21242170
self.funding_spend_confirmed = Some(txid);
21252171
},
@@ -2301,6 +2347,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
23012347
|| (input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::AcceptedHTLC) && input.witness[1].len() == 33);
23022348
let accepted_preimage_claim = input.witness.len() == 5 && HTLCType::scriptlen_to_htlctype(input.witness[4].len()) == Some(HTLCType::AcceptedHTLC);
23032349
let offered_preimage_claim = input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::OfferedHTLC);
2350+
let offered_timeout_claim = input.witness.len() == 5 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::OfferedHTLC);
23042351

23052352
macro_rules! log_claim {
23062353
($tx_info: expr, $holder_tx: expr, $htlc: expr, $source_avail: expr) => {
@@ -2360,6 +2407,21 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
23602407
}
23612408
if payment_data.is_none() {
23622409
log_claim!($tx_info, $holder_tx, htlc_output, false);
2410+
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
2411+
txid: tx.txid(), height,
2412+
event: OnchainEvent::HTLCSpendConfirmation {
2413+
input_idx: input.previous_output.vout,
2414+
our_preimage: None,
2415+
// `payment_data.is_none()` implies that this is our
2416+
// payment, as we haven't learned anything to cause us to
2417+
// update another channel or our offchain state. Thus, wait
2418+
// for the CSV delay before dropping the HTLC from
2419+
// claimable balance if the claim was an HTLC-Success or
2420+
// HTLC-Timeout transaction.
2421+
on_to_local_output_csv: if accepted_preimage_claim || offered_timeout_claim {
2422+
Some(self.on_holder_tx_csv) } else { None },
2423+
},
2424+
});
23632425
continue 'outer_loop;
23642426
}
23652427
}
@@ -2390,6 +2452,15 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
23902452
if !self.pending_monitor_events.iter().any(
23912453
|update| if let &MonitorEvent::HTLCEvent(ref upd) = update { upd.source == source } else { false }) {
23922454
payment_preimage.0.copy_from_slice(&input.witness[3]);
2455+
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
2456+
txid: tx.txid(),
2457+
height,
2458+
event: OnchainEvent::HTLCSpendConfirmation {
2459+
input_idx: input.previous_output.vout,
2460+
our_preimage: Some(payment_preimage),
2461+
on_to_local_output_csv: None,
2462+
},
2463+
});
23932464
self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
23942465
source,
23952466
payment_preimage: Some(payment_preimage),
@@ -2402,6 +2473,15 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
24022473
upd.source == source
24032474
} else { false }) {
24042475
payment_preimage.0.copy_from_slice(&input.witness[1]);
2476+
self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
2477+
txid: tx.txid(),
2478+
height,
2479+
event: OnchainEvent::HTLCSpendConfirmation {
2480+
input_idx: input.previous_output.vout,
2481+
our_preimage: Some(payment_preimage),
2482+
on_to_local_output_csv: None,
2483+
},
2484+
});
24052485
self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
24062486
source,
24072487
payment_preimage: Some(payment_preimage),
@@ -2418,10 +2498,10 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
24182498
_ => true,
24192499
}
24202500
});
2501+
let txid = tx.txid();
24212502
let entry = OnchainEventEntry {
2422-
txid: tx.txid(),
2423-
height,
2424-
event: OnchainEvent::HTLCUpdate { source: source, payment_hash: payment_hash },
2503+
txid, height,
2504+
event: OnchainEvent::HTLCUpdate { source: source, payment_hash: payment_hash, input_idx: Some(input.previous_output.vout) },
24252505
};
24262506
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());
24272507
self.onchain_events_awaiting_threshold_conf.push(entry);
@@ -2790,8 +2870,10 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
27902870
}
27912871

27922872
let mut funding_spend_confirmed = None;
2873+
let mut htlcs_resolved_on_chain = Some(Vec::new());
27932874
read_tlv_fields!(reader, {
27942875
(1, funding_spend_confirmed, option),
2876+
(3, htlcs_resolved_on_chain, vec_type),
27952877
});
27962878

27972879
let mut secp_ctx = Secp256k1::new();
@@ -2842,6 +2924,7 @@ impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
28422924
lockdown_from_offchain,
28432925
holder_tx_signed,
28442926
funding_spend_confirmed,
2927+
htlcs_resolved_on_chain: htlcs_resolved_on_chain.unwrap(),
28452928

28462929
best_block,
28472930

0 commit comments

Comments
 (0)