Skip to content

Commit 561ddc0

Browse files
committed
Check for duplicate HTLC events having matured
1 parent a899965 commit 561ddc0

File tree

2 files changed

+56
-21
lines changed

2 files changed

+56
-21
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ impl OnchainEventEntry {
480480
}
481481

482482
fn has_reached_confirmation_threshold(&self, height: u32) -> bool {
483-
self.confirmation_threshold() == height
483+
height >= self.confirmation_threshold()
484484
}
485485
}
486486

@@ -1874,9 +1874,9 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
18741874
let mut watch_outputs = Vec::new();
18751875

18761876
macro_rules! wait_threshold_conf {
1877-
($height: expr, $source: expr, $commitment_tx: expr, $payment_hash: expr) => {
1877+
($source: expr, $commitment_tx: expr, $payment_hash: expr) => {
18781878
self.onchain_events_waiting_threshold_conf.retain(|ref entry| {
1879-
if entry.height != $height { return true; }
1879+
if entry.height != height { return true; }
18801880
match entry.event {
18811881
OnchainEvent::HTLCUpdate { ref htlc_update } => {
18821882
htlc_update.0 != $source
@@ -1925,7 +1925,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
19251925
for &(ref htlc, _, ref source) in &$holder_tx.htlc_outputs {
19261926
if htlc.transaction_output_index.is_none() {
19271927
if let &Some(ref source) = source {
1928-
wait_threshold_conf!(height, source.clone(), "lastest", htlc.payment_hash.clone());
1928+
wait_threshold_conf!(source.clone(), "lastest", htlc.payment_hash.clone());
19291929
}
19301930
}
19311931
}
@@ -2065,31 +2065,66 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
20652065
claimable_outpoints.append(&mut new_outpoints);
20662066
}
20672067

2068+
// Find which on-chain events have reached their confirmation threshold.
20682069
let onchain_events_waiting_threshold_conf =
20692070
self.onchain_events_waiting_threshold_conf.drain(..).collect::<Vec<_>>();
2071+
let mut onchain_events_reaching_threshold_conf = Vec::new();
20702072
for entry in onchain_events_waiting_threshold_conf {
20712073
if entry.has_reached_confirmation_threshold(height) {
2072-
match entry.event {
2073-
OnchainEvent::HTLCUpdate { htlc_update } => {
2074-
log_trace!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!((htlc_update.1).0));
2075-
self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
2076-
payment_hash: htlc_update.1,
2077-
payment_preimage: None,
2078-
source: htlc_update.0,
2079-
}));
2080-
},
2081-
OnchainEvent::MaturingOutput { descriptor } => {
2082-
log_trace!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
2083-
self.pending_events.push(Event::SpendableOutputs {
2084-
outputs: vec![descriptor]
2085-
});
2086-
}
2087-
}
2074+
onchain_events_reaching_threshold_conf.push(entry);
20882075
} else {
20892076
self.onchain_events_waiting_threshold_conf.push(entry);
20902077
}
20912078
}
20922079

2080+
// Used to check for duplicate HTLC resolutions.
2081+
#[cfg(debug_assertions)]
2082+
let unmatured_htlcs: Vec<_> = self.onchain_events_waiting_threshold_conf
2083+
.iter()
2084+
.filter_map(|entry| match &entry.event {
2085+
OnchainEvent::HTLCUpdate { htlc_update } => Some(htlc_update.0.clone()),
2086+
OnchainEvent::MaturingOutput { .. } => None,
2087+
})
2088+
.collect();
2089+
#[cfg(debug_assertions)]
2090+
let mut matured_htlcs = Vec::new();
2091+
2092+
// Produce actionable events from on-chain events having reached their threshold.
2093+
for entry in onchain_events_reaching_threshold_conf.drain(..) {
2094+
match entry.event {
2095+
OnchainEvent::HTLCUpdate { htlc_update } => {
2096+
// Check for duplicate HTLC resolutions.
2097+
#[cfg(debug_assertions)]
2098+
{
2099+
debug_assert!(
2100+
unmatured_htlcs.iter().find(|&htlc| htlc == &htlc_update.0).is_none(),
2101+
"An unmature HTLC transaction conflicts with a maturing one; failed to \
2102+
call block_disconnected for a block containing the conflicting \
2103+
transaction.");
2104+
debug_assert!(
2105+
matured_htlcs.iter().find(|&htlc| htlc == &htlc_update.0).is_none(),
2106+
"A matured HTLC transaction conflicts with a maturing one; failed to \
2107+
call block_disconnected for a block containing the conflicting \
2108+
transaction.");
2109+
matured_htlcs.push(htlc_update.0.clone());
2110+
}
2111+
2112+
log_trace!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!((htlc_update.1).0));
2113+
self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
2114+
payment_hash: htlc_update.1,
2115+
payment_preimage: None,
2116+
source: htlc_update.0,
2117+
}));
2118+
},
2119+
OnchainEvent::MaturingOutput { descriptor } => {
2120+
log_trace!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
2121+
self.pending_events.push(Event::SpendableOutputs {
2122+
outputs: vec![descriptor]
2123+
});
2124+
}
2125+
}
2126+
}
2127+
20932128
self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, Some(height), &&*broadcaster, &&*fee_estimator, &&*logger);
20942129
self.last_block_hash = block_hash;
20952130

lightning/src/ln/onchaintx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl OnchainEventEntry {
5454
}
5555

5656
fn has_reached_confirmation_threshold(&self, height: u32) -> bool {
57-
self.confirmation_threshold() == height
57+
height >= self.confirmation_threshold()
5858
}
5959
}
6060

0 commit comments

Comments
 (0)