Skip to content

Commit 2e562a2

Browse files
committed
Provide the HTLCs that settled a payment.
Creates a new `events::ClaimedHTLC` struct that contains the relevant information about a claimed HTLC; e.g., the channel it arrived on, its ID, the amount of the HTLC, the overall amount of the payment, etc. Adds appropriate serialization support. Adds a `Vec<events::ClaimedHTLC>` to the `ClaimingPayment` structure. Populates this when creating the struct by converting the `payment.htlcs` (which are `ClaimingHTLC` structs) into `event::ClaimedHTLC` structs. This is a straightforward transformation. Adds a `Vec<events::ClaimedHTLC>` to the `events::Event::PaymentClaimed` enum. This is populated directly from the `ClaimingPayment`'s `htlcs` vec. Fixes #2477.
1 parent d4ad826 commit 2e562a2

File tree

3 files changed

+136
-14
lines changed

3 files changed

+136
-14
lines changed

lightning/src/events/mod.rs

+46-1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,37 @@ impl_writeable_tlv_based_enum!(PaymentPurpose,
7979
(2, SpontaneousPayment)
8080
);
8181

82+
/// Information about an HTLC that is part of a payment that can be claimed.
83+
#[derive(Clone, Debug, PartialEq, Eq)]
84+
pub struct ClaimedHTLC {
85+
/// The `channel_id` of the channel over which the HTLC was received.
86+
pub channel_id: [u8; 32],
87+
/// The `user_channel_id` of the channel over which the HTLC was received. This is the value
88+
/// passed in to [`ChannelManager::create_channel`] for outbound channels, or to
89+
/// [`ChannelManager::accept_inbound_channel`] for inbound channels if
90+
/// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true. Otherwise
91+
/// `user_channel_id` will be randomized for an inbound channel.
92+
///
93+
/// This field will be zero for a payment that was serialized prior to LDK version 0.0.117. (This
94+
/// should only happen in the case that a payment was claimable prior to LDK version 0.0.117, but
95+
/// was not actually claimed until after upgrading.)
96+
///
97+
/// [`ChannelManager::create_channel`]: crate::ln::channelmanager::ChannelManager::create_channel
98+
/// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
99+
/// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels
100+
pub user_channel_id: u128,
101+
/// The block height at which this HTLC expires.
102+
pub cltv_expiry: u32,
103+
/// The amount (in msats) of this part of an MPP.
104+
pub value_msat: u64,
105+
}
106+
impl_writeable_tlv_based!(ClaimedHTLC, {
107+
(0, channel_id, required),
108+
(2, user_channel_id, required),
109+
(4, cltv_expiry, required),
110+
(6, value_msat, required),
111+
});
112+
82113
/// When the payment path failure took place and extra details about it. [`PathFailure::OnPath`] may
83114
/// contain a [`NetworkUpdate`] that needs to be applied to the [`NetworkGraph`].
84115
///
@@ -470,6 +501,12 @@ pub enum Event {
470501
/// The purpose of the claimed payment, i.e. whether the payment was for an invoice or a
471502
/// spontaneous payment.
472503
purpose: PaymentPurpose,
504+
/// The HTLCs that comprise the claimed payment. This will be empty for events serialized prior
505+
/// to LDK version 0.0.117.
506+
htlcs: Vec<ClaimedHTLC>,
507+
/// The sender-intended sum total of all the MPP parts. This will be `None` for events
508+
/// serialized prior to LDK version 0.0.117.
509+
sender_intended_total_msat: Option<u64>,
473510
},
474511
/// Indicates an outbound payment we made succeeded (i.e. it made it all the way to its target
475512
/// and we got back the payment preimage for it).
@@ -1035,13 +1072,15 @@ impl Writeable for Event {
10351072
// We never write the OpenChannelRequest events as, upon disconnection, peers
10361073
// drop any channels which have not yet exchanged funding_signed.
10371074
},
1038-
&Event::PaymentClaimed { ref payment_hash, ref amount_msat, ref purpose, ref receiver_node_id } => {
1075+
&Event::PaymentClaimed { ref payment_hash, ref amount_msat, ref purpose, ref receiver_node_id, ref htlcs, ref sender_intended_total_msat } => {
10391076
19u8.write(writer)?;
10401077
write_tlv_fields!(writer, {
10411078
(0, payment_hash, required),
10421079
(1, receiver_node_id, option),
10431080
(2, purpose, required),
10441081
(4, amount_msat, required),
1082+
(5, *htlcs, optional_vec),
1083+
(7, sender_intended_total_msat, option),
10451084
});
10461085
},
10471086
&Event::ProbeSuccessful { ref payment_id, ref payment_hash, ref path } => {
@@ -1366,17 +1405,23 @@ impl MaybeReadable for Event {
13661405
let mut purpose = UpgradableRequired(None);
13671406
let mut amount_msat = 0;
13681407
let mut receiver_node_id = None;
1408+
let mut htlcs: Option<Vec<ClaimedHTLC>> = Some(vec![]);
1409+
let mut sender_intended_total_msat: Option<u64> = None;
13691410
read_tlv_fields!(reader, {
13701411
(0, payment_hash, required),
13711412
(1, receiver_node_id, option),
13721413
(2, purpose, upgradable_required),
13731414
(4, amount_msat, required),
1415+
(5, htlcs, optional_vec),
1416+
(7, sender_intended_total_msat, option),
13741417
});
13751418
Ok(Some(Event::PaymentClaimed {
13761419
receiver_node_id,
13771420
payment_hash,
13781421
purpose: _init_tlv_based_struct_field!(purpose, upgradable_required),
13791422
amount_msat,
1423+
htlcs: htlcs.unwrap_or(vec![]),
1424+
sender_intended_total_msat,
13801425
}))
13811426
};
13821427
f()

lightning/src/ln/channelmanager.rs

+46-7
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ pub(super) enum HTLCForwardInfo {
181181
pub(crate) struct HTLCPreviousHopData {
182182
// Note that this may be an outbound SCID alias for the associated channel.
183183
short_channel_id: u64,
184+
user_channel_id: Option<u128>,
184185
htlc_id: u64,
185186
incoming_packet_shared_secret: [u8; 32],
186187
phantom_shared_secret: Option<[u8; 32]>,
@@ -221,6 +222,17 @@ struct ClaimableHTLC {
221222
counterparty_skimmed_fee_msat: Option<u64>,
222223
}
223224

225+
impl From<&ClaimableHTLC> for events::ClaimedHTLC {
226+
fn from(val: &ClaimableHTLC) -> Self {
227+
events::ClaimedHTLC {
228+
channel_id: val.prev_hop.outpoint.to_channel_id(),
229+
user_channel_id: val.prev_hop.user_channel_id.unwrap_or(0),
230+
cltv_expiry: val.cltv_expiry,
231+
value_msat: val.value,
232+
}
233+
}
234+
}
235+
224236
/// A payment identifier used to uniquely identify a payment to LDK.
225237
///
226238
/// This is not exported to bindings users as we just use [u8; 32] directly
@@ -496,11 +508,15 @@ struct ClaimingPayment {
496508
amount_msat: u64,
497509
payment_purpose: events::PaymentPurpose,
498510
receiver_node_id: PublicKey,
511+
htlcs: Vec<events::ClaimedHTLC>,
512+
sender_intended_value: Option<u64>,
499513
}
500514
impl_writeable_tlv_based!(ClaimingPayment, {
501515
(0, amount_msat, required),
502516
(2, payment_purpose, required),
503517
(4, receiver_node_id, required),
518+
(5, htlcs, optional_vec),
519+
(7, sender_intended_value, option),
504520
});
505521

506522
struct ClaimablePayment {
@@ -3781,6 +3797,7 @@ where
37813797
if let PendingHTLCRouting::Forward { short_channel_id, .. } = payment.forward_info.routing {
37823798
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
37833799
short_channel_id: payment.prev_short_channel_id,
3800+
user_channel_id: Some(payment.prev_user_channel_id),
37843801
outpoint: payment.prev_funding_outpoint,
37853802
htlc_id: payment.prev_htlc_id,
37863803
incoming_packet_shared_secret: payment.forward_info.incoming_shared_secret,
@@ -3828,6 +3845,7 @@ where
38283845

38293846
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
38303847
short_channel_id: prev_short_channel_id,
3848+
user_channel_id: Some(prev_user_channel_id),
38313849
outpoint: prev_funding_outpoint,
38323850
htlc_id: prev_htlc_id,
38333851
incoming_packet_shared_secret: incoming_shared_secret,
@@ -3932,7 +3950,7 @@ where
39323950
for forward_info in pending_forwards.drain(..) {
39333951
match forward_info {
39343952
HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
3935-
prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id: _,
3953+
prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id,
39363954
forward_info: PendingHTLCInfo {
39373955
incoming_shared_secret, payment_hash, outgoing_amt_msat, outgoing_cltv_value,
39383956
routing: PendingHTLCRouting::Forward { onion_packet, .. }, skimmed_fee_msat, ..
@@ -3941,6 +3959,7 @@ where
39413959
log_trace!(self.logger, "Adding HTLC from short id {} with payment_hash {} to channel with short id {} after delay", prev_short_channel_id, log_bytes!(payment_hash.0), short_chan_id);
39423960
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
39433961
short_channel_id: prev_short_channel_id,
3962+
user_channel_id: Some(prev_user_channel_id),
39443963
outpoint: prev_funding_outpoint,
39453964
htlc_id: prev_htlc_id,
39463965
incoming_packet_shared_secret: incoming_shared_secret,
@@ -4022,6 +4041,7 @@ where
40224041
let claimable_htlc = ClaimableHTLC {
40234042
prev_hop: HTLCPreviousHopData {
40244043
short_channel_id: prev_short_channel_id,
4044+
user_channel_id: Some(prev_user_channel_id),
40254045
outpoint: prev_funding_outpoint,
40264046
htlc_id: prev_htlc_id,
40274047
incoming_packet_shared_secret: incoming_shared_secret,
@@ -4051,6 +4071,7 @@ where
40514071
);
40524072
failed_forwards.push((HTLCSource::PreviousHopData(HTLCPreviousHopData {
40534073
short_channel_id: $htlc.prev_hop.short_channel_id,
4074+
user_channel_id: $htlc.prev_hop.user_channel_id,
40544075
outpoint: prev_funding_outpoint,
40554076
htlc_id: $htlc.prev_hop.htlc_id,
40564077
incoming_packet_shared_secret: $htlc.prev_hop.incoming_packet_shared_secret,
@@ -4782,7 +4803,7 @@ where
47824803
&self.pending_events, &self.logger)
47834804
{ self.push_pending_forwards_ev(); }
47844805
},
4785-
HTLCSource::PreviousHopData(HTLCPreviousHopData { ref short_channel_id, ref htlc_id, ref incoming_packet_shared_secret, ref phantom_shared_secret, ref outpoint }) => {
4806+
HTLCSource::PreviousHopData(HTLCPreviousHopData { ref short_channel_id, ref htlc_id, ref incoming_packet_shared_secret, ref phantom_shared_secret, ref outpoint, .. }) => {
47864807
log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards from us with {:?}", log_bytes!(payment_hash.0), onion_error);
47874808
let err_packet = onion_error.get_encrypted_failure_packet(incoming_packet_shared_secret, phantom_shared_secret);
47884809

@@ -4869,9 +4890,11 @@ where
48694890
}
48704891
}
48714892

4893+
let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
4894+
let sender_intended_value = payment.htlcs.first().map(|htlc| htlc.total_msat);
48724895
let dup_purpose = claimable_payments.pending_claiming_payments.insert(payment_hash,
48734896
ClaimingPayment { amount_msat: payment.htlcs.iter().map(|source| source.value).sum(),
4874-
payment_purpose: payment.purpose, receiver_node_id,
4897+
payment_purpose: payment.purpose, receiver_node_id, htlcs, sender_intended_value
48754898
});
48764899
if dup_purpose.is_some() {
48774900
debug_assert!(false, "Shouldn't get a duplicate pending claim event ever");
@@ -5129,9 +5152,20 @@ where
51295152
match action {
51305153
MonitorUpdateCompletionAction::PaymentClaimed { payment_hash } => {
51315154
let payment = self.claimable_payments.lock().unwrap().pending_claiming_payments.remove(&payment_hash);
5132-
if let Some(ClaimingPayment { amount_msat, payment_purpose: purpose, receiver_node_id }) = payment {
5155+
if let Some(ClaimingPayment {
5156+
amount_msat,
5157+
payment_purpose: purpose,
5158+
receiver_node_id,
5159+
htlcs,
5160+
sender_intended_value: sender_intended_total_msat,
5161+
}) = payment {
51335162
self.pending_events.lock().unwrap().push_back((events::Event::PaymentClaimed {
5134-
payment_hash, purpose, amount_msat, receiver_node_id: Some(receiver_node_id),
5163+
payment_hash,
5164+
purpose,
5165+
amount_msat,
5166+
receiver_node_id: Some(receiver_node_id),
5167+
htlcs,
5168+
sender_intended_total_msat,
51355169
}, None));
51365170
}
51375171
},
@@ -6006,6 +6040,7 @@ where
60066040
log_info!(self.logger, "Failed to forward incoming HTLC: detected duplicate intercepted payment over short channel id {}", scid);
60076041
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
60086042
short_channel_id: prev_short_channel_id,
6043+
user_channel_id: Some(prev_user_channel_id),
60096044
outpoint: prev_funding_outpoint,
60106045
htlc_id: prev_htlc_id,
60116046
incoming_packet_shared_secret: forward_info.incoming_shared_secret,
@@ -7124,6 +7159,7 @@ where
71247159
if height >= htlc.forward_info.outgoing_cltv_value - HTLC_FAIL_BACK_BUFFER {
71257160
let prev_hop_data = HTLCSource::PreviousHopData(HTLCPreviousHopData {
71267161
short_channel_id: htlc.prev_short_channel_id,
7162+
user_channel_id: Some(htlc.prev_user_channel_id),
71277163
htlc_id: htlc.prev_htlc_id,
71287164
incoming_packet_shared_secret: htlc.forward_info.incoming_shared_secret,
71297165
phantom_shared_secret: None,
@@ -7899,7 +7935,8 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, {
78997935
(1, phantom_shared_secret, option),
79007936
(2, outpoint, required),
79017937
(4, htlc_id, required),
7902-
(6, incoming_packet_shared_secret, required)
7938+
(6, incoming_packet_shared_secret, required),
7939+
(7, user_channel_id, option),
79037940
});
79047941

79057942
impl Writeable for ClaimableHTLC {
@@ -9147,7 +9184,7 @@ where
91479184
.expect("Failed to get node_id for phantom node recipient");
91489185
receiver_node_id = Some(phantom_pubkey)
91499186
}
9150-
for claimable_htlc in payment.htlcs {
9187+
for claimable_htlc in &payment.htlcs {
91519188
claimable_amt_msat += claimable_htlc.value;
91529189

91539190
// Add a holding-cell claim of the payment to the Channel, which should be
@@ -9183,6 +9220,8 @@ where
91839220
payment_hash,
91849221
purpose: payment.purpose,
91859222
amount_msat: claimable_amt_msat,
9223+
htlcs: payment.htlcs.iter().map(events::ClaimedHTLC::from).collect(),
9224+
sender_intended_total_msat: payment.htlcs.first().map(|htlc| htlc.total_msat),
91869225
}, None));
91879226
}
91889227
}

lightning/src/ln/functional_test_utils.rs

+44-6
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch
1414
use crate::sign::EntropySource;
1515
use crate::chain::channelmonitor::ChannelMonitor;
1616
use crate::chain::transaction::OutPoint;
17-
use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason};
17+
use crate::events::{ClaimedHTLC, ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason};
1818
use crate::events::bump_transaction::{BumpTransactionEventHandler, Wallet, WalletSource};
1919
use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
2020
use crate::ln::channelmanager::{AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, PaymentId, MIN_CLTV_EXPIRY_DELTA};
@@ -933,6 +933,21 @@ macro_rules! check_added_monitors {
933933
}
934934
}
935935

936+
/// Checks whether the claimed HTLC for the specified path has the correct channel information.
937+
///
938+
/// This will panic if the path is empty, if the HTLC's channel ID is not actually a channel that
939+
/// connects the final two nodes in the path, or if the `user_channel_id` is incorrect.
940+
pub fn check_claimed_htlc_channel<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, path: &[&Node<'a, 'b, 'c>], htlc: &ClaimedHTLC) {
941+
let mut nodes = path.iter().rev();
942+
let dest = nodes.next().expect("path should have a destination").node;
943+
let prev = nodes.next().unwrap_or(&origin_node).node;
944+
let dest_channels = dest.list_channels();
945+
let ch = dest_channels.iter().find(|ch| ch.channel_id == htlc.channel_id)
946+
.expect("HTLC's channel should be one of destination node's channels");
947+
assert_eq!(htlc.user_channel_id, ch.user_channel_id);
948+
assert_eq!(ch.counterparty.node_id, prev.get_our_node_id());
949+
}
950+
936951
pub fn _reload_node<'a, 'b, 'c>(node: &'a Node<'a, 'b, 'c>, default_config: UserConfig, chanman_encoded: &[u8], monitors_encoded: &[&[u8]]) -> TestChannelManager<'b, 'c> {
937952
let mut monitors_read = Vec::with_capacity(monitors_encoded.len());
938953
for encoded in monitors_encoded {
@@ -2271,11 +2286,34 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, '
22712286
let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events();
22722287
assert_eq!(claim_event.len(), 1);
22732288
match claim_event[0] {
2274-
Event::PaymentClaimed { purpose: PaymentPurpose::SpontaneousPayment(preimage), .. }|
2275-
Event::PaymentClaimed { purpose: PaymentPurpose::InvoicePayment { payment_preimage: Some(preimage), ..}, .. } =>
2276-
assert_eq!(preimage, our_payment_preimage),
2277-
Event::PaymentClaimed { purpose: PaymentPurpose::InvoicePayment { .. }, payment_hash, .. } =>
2278-
assert_eq!(&payment_hash.0, &Sha256::hash(&our_payment_preimage.0)[..]),
2289+
Event::PaymentClaimed {
2290+
purpose: PaymentPurpose::SpontaneousPayment(preimage),
2291+
amount_msat,
2292+
ref htlcs,
2293+
.. }
2294+
| Event::PaymentClaimed {
2295+
purpose: PaymentPurpose::InvoicePayment { payment_preimage: Some(preimage), ..},
2296+
ref htlcs,
2297+
amount_msat,
2298+
..
2299+
} => {
2300+
assert_eq!(preimage, our_payment_preimage);
2301+
assert_eq!(htlcs.len(), expected_paths.len()); // One per path.
2302+
assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::<u64>(), amount_msat);
2303+
expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc));
2304+
},
2305+
Event::PaymentClaimed {
2306+
purpose: PaymentPurpose::InvoicePayment { .. },
2307+
payment_hash,
2308+
amount_msat,
2309+
ref htlcs,
2310+
..
2311+
} => {
2312+
assert_eq!(&payment_hash.0, &Sha256::hash(&our_payment_preimage.0)[..]);
2313+
assert_eq!(htlcs.len(), expected_paths.len()); // One per path.
2314+
assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::<u64>(), amount_msat);
2315+
expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc));
2316+
}
22792317
_ => panic!(),
22802318
}
22812319

0 commit comments

Comments
 (0)