Skip to content

Commit 6c8a07b

Browse files
MonitorEvents: HTLC failure reason and skimmed fee
XXX
1 parent d5081ee commit 6c8a07b

File tree

4 files changed

+313
-70
lines changed

4 files changed

+313
-70
lines changed

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};
@@ -13746,60 +13746,62 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1374613746
Some(channel_id),
1374713747
Some(htlc_update.payment_hash),
1374813748
);
13749-
if let Some(preimage) = htlc_update.payment_preimage {
13750-
log_trace!(
13751-
logger,
13752-
"Claiming HTLC with preimage {} from our monitor",
13753-
preimage
13754-
);
13755-
let from_onchain = self
13756-
.per_peer_state
13757-
.read()
13758-
.unwrap()
13759-
.get(&counterparty_node_id)
13760-
.map_or(true, |peer_state_mtx| {
13761-
!peer_state_mtx
13762-
.lock()
13763-
.unwrap()
13764-
.channel_by_id
13765-
.contains_key(&channel_id)
13749+
match htlc_update.resolution {
13750+
OutboundHTLCResolution::Claimed { preimage, skimmed_fee_msat } => {
13751+
log_trace!(
13752+
logger,
13753+
"Claiming HTLC with preimage {} from our monitor",
13754+
preimage
13755+
);
13756+
let from_onchain = self
13757+
.per_peer_state
13758+
.read()
13759+
.unwrap()
13760+
.get(&counterparty_node_id)
13761+
.map_or(true, |peer_state_mtx| {
13762+
!peer_state_mtx
13763+
.lock()
13764+
.unwrap()
13765+
.channel_by_id
13766+
.contains_key(&channel_id)
13767+
});
13768+
// Claim the funds from the previous hop, if there is one. Because this is in response to a
13769+
// chain event, no attribution data is available.
13770+
self.claim_funds_internal(
13771+
htlc_update.source,
13772+
preimage,
13773+
htlc_update.htlc_value_msat,
13774+
skimmed_fee_msat,
13775+
from_onchain,
13776+
counterparty_node_id,
13777+
funding_outpoint,
13778+
channel_id,
13779+
htlc_update.user_channel_id,
13780+
None,
13781+
None,
13782+
Some(event_id),
13783+
);
13784+
},
13785+
OutboundHTLCResolution::Failed { reason } => {
13786+
log_trace!(logger, "Failing HTLC from our monitor");
13787+
let failure_type = htlc_update
13788+
.source
13789+
.failure_type(counterparty_node_id, channel_id);
13790+
let completion_update = Some(PaymentCompleteUpdate {
13791+
counterparty_node_id,
13792+
channel_funding_outpoint: funding_outpoint,
13793+
channel_id,
13794+
htlc_id: SentHTLCId::from_source(&htlc_update.source),
1376613795
});
13767-
// Claim the funds from the previous hop, if there is one. Because this is in response to a
13768-
// chain event, no attribution data is available.
13769-
self.claim_funds_internal(
13770-
htlc_update.source,
13771-
preimage,
13772-
htlc_update.htlc_value_msat,
13773-
None,
13774-
from_onchain,
13775-
counterparty_node_id,
13776-
funding_outpoint,
13777-
channel_id,
13778-
htlc_update.user_channel_id,
13779-
None,
13780-
None,
13781-
Some(event_id),
13782-
);
13783-
} else {
13784-
log_trace!(logger, "Failing HTLC from our monitor");
13785-
let failure_reason = LocalHTLCFailureReason::OnChainTimeout;
13786-
let failure_type =
13787-
htlc_update.source.failure_type(counterparty_node_id, channel_id);
13788-
let reason = HTLCFailReason::from_failure_code(failure_reason);
13789-
let completion_update = Some(PaymentCompleteUpdate {
13790-
counterparty_node_id,
13791-
channel_funding_outpoint: funding_outpoint,
13792-
channel_id,
13793-
htlc_id: SentHTLCId::from_source(&htlc_update.source),
13794-
});
13795-
self.fail_htlc_backwards_internal(
13796-
&htlc_update.source,
13797-
&htlc_update.payment_hash,
13798-
&reason,
13799-
failure_type,
13800-
completion_update,
13801-
);
13802-
self.chain_monitor.ack_monitor_event(monitor_event_source);
13796+
self.fail_htlc_backwards_internal(
13797+
&htlc_update.source,
13798+
&htlc_update.payment_hash,
13799+
&reason,
13800+
failure_type,
13801+
completion_update,
13802+
);
13803+
self.chain_monitor.ack_monitor_event(monitor_event_source);
13804+
},
1380313805
}
1380413806
},
1380513807
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)