Skip to content

Commit 5248533

Browse files
MonitorEvents: HTLC failure reason and skimmed fee
XXX
1 parent dc00df2 commit 5248533

4 files changed

Lines changed: 313 additions & 70 deletions

File tree

lightning/src/chain/channelmonitor.rs

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ use crate::ln::channel_keys::{
5656
};
5757
use crate::ln::channelmanager::{HTLCSource, PaymentClaimDetails, SentHTLCId};
5858
use crate::ln::msgs::DecodeError;
59+
use crate::ln::onion_utils::{HTLCFailReason, LocalHTLCFailureReason};
5960
use crate::ln::types::ChannelId;
6061
use crate::sign::{
6162
ecdsa::EcdsaChannelSigner, ChannelDerivationParameters, DelayedPaymentOutputDescriptor,
@@ -252,24 +253,76 @@ impl_writeable_tlv_based_enum_upgradable_legacy!(MonitorEvent,
252253
// 6 was `UpdateFailed` until LDK 0.0.117
253254
);
254255

256+
/// The resolution of an outbound HTLC — either claimed with a preimage or failed back. Used in
257+
/// [`MonitorEvent::HTLCEvent`]s to provide resolution data to the `ChannelManager`.
258+
#[derive(Clone, PartialEq, Eq, Debug)]
259+
pub(crate) enum OutboundHTLCResolution {
260+
Claimed {
261+
preimage: PaymentPreimage,
262+
skimmed_fee_msat: Option<u64>,
263+
},
264+
/// The failure resolution may come from on-chain in the [`ChannelMonitor`] or off-chain from the
265+
/// `ChannelManager`, such as from an outbound edge to provide the manager with a resolution for
266+
/// the inbound edge.
267+
Failed {
268+
reason: HTLCFailReason,
269+
},
270+
}
271+
272+
impl OutboundHTLCResolution {
273+
/// Returns an on-chain timeout failure resolution.
274+
pub fn on_chain_timeout() -> Self {
275+
OutboundHTLCResolution::Failed {
276+
reason: HTLCFailReason::from_failure_code(LocalHTLCFailureReason::OnChainTimeout),
277+
}
278+
}
279+
}
280+
281+
impl_writeable_tlv_based_enum!(OutboundHTLCResolution,
282+
(1, Claimed) => {
283+
(1, preimage, required),
284+
(3, skimmed_fee_msat, option),
285+
},
286+
(3, Failed) => {
287+
(1, reason, required),
288+
},
289+
);
290+
255291
/// Simple structure sent back by `chain::Watch` when an HTLC from a forward channel is detected on
256292
/// chain. Used to update the corresponding HTLC in the backward channel. Failing to pass the
257293
/// preimage claim backward will lead to loss of funds.
258294
#[derive(Clone, PartialEq, Eq)]
259295
pub struct HTLCUpdate {
260296
pub(crate) payment_hash: PaymentHash,
261-
pub(crate) payment_preimage: Option<PaymentPreimage>,
262297
pub(crate) source: HTLCSource,
263298
pub(crate) htlc_value_msat: Option<u64>,
264299
pub(crate) user_channel_id: Option<u128>,
300+
pub(crate) resolution: OutboundHTLCResolution,
265301
}
266302
impl_writeable_tlv_based!(HTLCUpdate, {
267303
(0, payment_hash, required),
268304
(1, htlc_value_satoshis, (legacy, u64, |_| Ok(()), |us: &HTLCUpdate| us.htlc_value_msat.map(|v| v / 1000))),
269305
(2, source, required),
270-
(4, payment_preimage, option),
306+
(4, _legacy_payment_preimage, (legacy, Option<PaymentPreimage>,
307+
|v: Option<&Option<PaymentPreimage>>| {
308+
// Only use the legacy preimage if the new `resolution` TLV (9) wasn't read,
309+
// otherwise we'd clobber it (losing e.g. skimmed_fee_msat).
310+
if resolution.0.is_none() {
311+
if let Some(Some(preimage)) = v {
312+
resolution = crate::util::ser::RequiredWrapper(Some(
313+
OutboundHTLCResolution::Claimed { preimage: *preimage, skimmed_fee_msat: None }
314+
));
315+
}
316+
}
317+
Ok(())
318+
},
319+
|us: &HTLCUpdate| match &us.resolution {
320+
OutboundHTLCResolution::Claimed { preimage, .. } => Some(Some(*preimage)),
321+
_ => None,
322+
})),
271323
(5, user_channel_id, option),
272324
(7, htlc_value_msat, (default_value, htlc_value_satoshis.map(|v: u64| v * 1000))),
325+
(9, resolution, (default_value, OutboundHTLCResolution::on_chain_timeout())),
273326
});
274327

275328
/// If an output goes from claimable only by us to claimable by us or our counterparty within this
@@ -3908,7 +3961,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
39083961
if let Some((htlc, source)) = htlc_opt {
39093962
self.push_monitor_event(MonitorEvent::HTLCEvent(HTLCUpdate {
39103963
payment_hash: htlc.payment_hash,
3911-
payment_preimage: Some(claim.preimage),
3964+
resolution: OutboundHTLCResolution::Claimed {
3965+
preimage: claim.preimage,
3966+
skimmed_fee_msat: claim.skimmed_fee_msat,
3967+
},
39123968
source: *source.clone(),
39133969
htlc_value_msat: Some(htlc.amount_msat),
39143970
user_channel_id: self.user_channel_id,
@@ -4645,7 +4701,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
46454701
&mut self.pending_monitor_events,
46464702
MonitorEvent::HTLCEvent(HTLCUpdate {
46474703
payment_hash,
4648-
payment_preimage: None,
4704+
resolution: OutboundHTLCResolution::on_chain_timeout(),
46494705
source: source.clone(),
46504706
htlc_value_msat: Some(amount_msat),
46514707
user_channel_id: self.user_channel_id,
@@ -5983,7 +6039,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
59836039
&payment_hash, entry.txid);
59846040
self.push_monitor_event(MonitorEvent::HTLCEvent(HTLCUpdate {
59856041
payment_hash,
5986-
payment_preimage: None,
6042+
resolution: OutboundHTLCResolution::on_chain_timeout(),
59876043
source,
59886044
htlc_value_msat: htlc_value_satoshis.map(|v| v * 1000),
59896045
user_channel_id: self.user_channel_id,
@@ -6094,7 +6150,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
60946150
expires soon at {}", log_bytes!(htlc.payment_hash.0), inbound_htlc_expiry);
60956151
push_monitor_event(&mut self.pending_monitor_events, MonitorEvent::HTLCEvent(HTLCUpdate {
60966152
source: source.clone(),
6097-
payment_preimage: None,
6153+
resolution: OutboundHTLCResolution::on_chain_timeout(),
60986154
payment_hash: htlc.payment_hash,
60996155
htlc_value_msat: Some(htlc.amount_msat),
61006156
user_channel_id: self.user_channel_id,
@@ -6512,7 +6568,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
65126568
self.counterparty_fulfilled_htlcs.insert(SentHTLCId::from_source(&source), payment_preimage);
65136569
push_monitor_event(&mut self.pending_monitor_events, MonitorEvent::HTLCEvent(HTLCUpdate {
65146570
source,
6515-
payment_preimage: Some(payment_preimage),
6571+
resolution: OutboundHTLCResolution::Claimed { preimage: payment_preimage, skimmed_fee_msat: None },
65166572
payment_hash,
65176573
htlc_value_msat: Some(amount_msat),
65186574
user_channel_id: self.user_channel_id,
@@ -6537,7 +6593,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
65376593
self.counterparty_fulfilled_htlcs.insert(SentHTLCId::from_source(&source), payment_preimage);
65386594
push_monitor_event(&mut self.pending_monitor_events, MonitorEvent::HTLCEvent(HTLCUpdate {
65396595
source,
6540-
payment_preimage: Some(payment_preimage),
6596+
resolution: OutboundHTLCResolution::Claimed { preimage: payment_preimage, skimmed_fee_msat: None },
65416597
payment_hash,
65426598
htlc_value_msat: Some(amount_msat),
65436599
user_channel_id: self.user_channel_id,

lightning/src/ln/channelmanager.rs

Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ use crate::chain::chaininterface::{
4545
use crate::chain::chainmonitor::MonitorEventSource;
4646
use crate::chain::channelmonitor::{
4747
ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, MonitorEvent,
48-
WithChannelMonitor, ANTI_REORG_DELAY, CLTV_CLAIM_BUFFER, HTLC_FAIL_BACK_BUFFER,
49-
LATENCY_GRACE_PERIOD_BLOCKS, MAX_BLOCKS_FOR_CONF,
48+
OutboundHTLCResolution, WithChannelMonitor, ANTI_REORG_DELAY, CLTV_CLAIM_BUFFER,
49+
HTLC_FAIL_BACK_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, MAX_BLOCKS_FOR_CONF,
5050
};
5151
use crate::chain::transaction::{OutPoint, TransactionData};
5252
use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Watch};
@@ -13744,60 +13744,62 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1374413744
Some(channel_id),
1374513745
Some(htlc_update.payment_hash),
1374613746
);
13747-
if let Some(preimage) = htlc_update.payment_preimage {
13748-
log_trace!(
13749-
logger,
13750-
"Claiming HTLC with preimage {} from our monitor",
13751-
preimage
13752-
);
13753-
let from_onchain = self
13754-
.per_peer_state
13755-
.read()
13756-
.unwrap()
13757-
.get(&counterparty_node_id)
13758-
.map_or(true, |peer_state_mtx| {
13759-
!peer_state_mtx
13760-
.lock()
13761-
.unwrap()
13762-
.channel_by_id
13763-
.contains_key(&channel_id)
13747+
match htlc_update.resolution {
13748+
OutboundHTLCResolution::Claimed { preimage, skimmed_fee_msat } => {
13749+
log_trace!(
13750+
logger,
13751+
"Claiming HTLC with preimage {} from our monitor",
13752+
preimage
13753+
);
13754+
let from_onchain = self
13755+
.per_peer_state
13756+
.read()
13757+
.unwrap()
13758+
.get(&counterparty_node_id)
13759+
.map_or(true, |peer_state_mtx| {
13760+
!peer_state_mtx
13761+
.lock()
13762+
.unwrap()
13763+
.channel_by_id
13764+
.contains_key(&channel_id)
13765+
});
13766+
// Claim the funds from the previous hop, if there is one. Because this is in response to a
13767+
// chain event, no attribution data is available.
13768+
self.claim_funds_internal(
13769+
htlc_update.source,
13770+
preimage,
13771+
htlc_update.htlc_value_msat,
13772+
skimmed_fee_msat,
13773+
from_onchain,
13774+
counterparty_node_id,
13775+
funding_outpoint,
13776+
channel_id,
13777+
htlc_update.user_channel_id,
13778+
None,
13779+
None,
13780+
Some(event_id),
13781+
);
13782+
},
13783+
OutboundHTLCResolution::Failed { reason } => {
13784+
log_trace!(logger, "Failing HTLC from our monitor");
13785+
let failure_type = htlc_update
13786+
.source
13787+
.failure_type(counterparty_node_id, channel_id);
13788+
let completion_update = Some(PaymentCompleteUpdate {
13789+
counterparty_node_id,
13790+
channel_funding_outpoint: funding_outpoint,
13791+
channel_id,
13792+
htlc_id: SentHTLCId::from_source(&htlc_update.source),
1376413793
});
13765-
// Claim the funds from the previous hop, if there is one. Because this is in response to a
13766-
// chain event, no attribution data is available.
13767-
self.claim_funds_internal(
13768-
htlc_update.source,
13769-
preimage,
13770-
htlc_update.htlc_value_msat,
13771-
None,
13772-
from_onchain,
13773-
counterparty_node_id,
13774-
funding_outpoint,
13775-
channel_id,
13776-
htlc_update.user_channel_id,
13777-
None,
13778-
None,
13779-
Some(event_id),
13780-
);
13781-
} else {
13782-
log_trace!(logger, "Failing HTLC from our monitor");
13783-
let failure_reason = LocalHTLCFailureReason::OnChainTimeout;
13784-
let failure_type =
13785-
htlc_update.source.failure_type(counterparty_node_id, channel_id);
13786-
let reason = HTLCFailReason::from_failure_code(failure_reason);
13787-
let completion_update = Some(PaymentCompleteUpdate {
13788-
counterparty_node_id,
13789-
channel_funding_outpoint: funding_outpoint,
13790-
channel_id,
13791-
htlc_id: SentHTLCId::from_source(&htlc_update.source),
13792-
});
13793-
self.fail_htlc_backwards_internal(
13794-
&htlc_update.source,
13795-
&htlc_update.payment_hash,
13796-
&reason,
13797-
failure_type,
13798-
completion_update,
13799-
);
13800-
self.chain_monitor.ack_monitor_event(monitor_event_source);
13794+
self.fail_htlc_backwards_internal(
13795+
&htlc_update.source,
13796+
&htlc_update.payment_hash,
13797+
&reason,
13798+
failure_type,
13799+
completion_update,
13800+
);
13801+
self.chain_monitor.ack_monitor_event(monitor_event_source);
13802+
},
1380113803
}
1380213804
},
1380313805
MonitorEvent::HolderForceClosed(_)

lightning/src/ln/onion_utils.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,11 +1908,11 @@ impl From<&HTLCFailReason> for HTLCHandlingFailureReason {
19081908
}
19091909

19101910
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
1911-
#[cfg_attr(test, derive(PartialEq))]
1912-
pub(super) struct HTLCFailReason(HTLCFailReasonRepr);
1911+
#[derive(PartialEq, Eq)]
1912+
pub(crate) struct HTLCFailReason(HTLCFailReasonRepr);
19131913

19141914
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
1915-
#[cfg_attr(test, derive(PartialEq))]
1915+
#[derive(PartialEq, Eq)]
19161916
enum HTLCFailReasonRepr {
19171917
LightningError { err: msgs::OnionErrorPacket, hold_time: Option<u32> },
19181918
Reason { data: Vec<u8>, failure_reason: LocalHTLCFailureReason },
@@ -2071,7 +2071,7 @@ impl HTLCFailReason {
20712071
Self(HTLCFailReasonRepr::Reason { data, failure_reason })
20722072
}
20732073

2074-
pub(super) fn from_failure_code(failure_reason: LocalHTLCFailureReason) -> Self {
2074+
pub(crate) fn from_failure_code(failure_reason: LocalHTLCFailureReason) -> Self {
20752075
Self::reason(failure_reason, Vec::new())
20762076
}
20772077

0 commit comments

Comments
 (0)