Skip to content

Commit 4bd4f02

Browse files
authored
Merge pull request #2478 from waterson/settle-htlcs
Provide the HTLCs that settled a payment.
2 parents cb923c6 + 2e562a2 commit 4bd4f02

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).
@@ -1040,13 +1077,15 @@ impl Writeable for Event {
10401077
// We never write the OpenChannelRequest events as, upon disconnection, peers
10411078
// drop any channels which have not yet exchanged funding_signed.
10421079
},
1043-
&Event::PaymentClaimed { ref payment_hash, ref amount_msat, ref purpose, ref receiver_node_id } => {
1080+
&Event::PaymentClaimed { ref payment_hash, ref amount_msat, ref purpose, ref receiver_node_id, ref htlcs, ref sender_intended_total_msat } => {
10441081
19u8.write(writer)?;
10451082
write_tlv_fields!(writer, {
10461083
(0, payment_hash, required),
10471084
(1, receiver_node_id, option),
10481085
(2, purpose, required),
10491086
(4, amount_msat, required),
1087+
(5, *htlcs, optional_vec),
1088+
(7, sender_intended_total_msat, option),
10501089
});
10511090
},
10521091
&Event::ProbeSuccessful { ref payment_id, ref payment_hash, ref path } => {
@@ -1371,17 +1410,23 @@ impl MaybeReadable for Event {
13711410
let mut purpose = UpgradableRequired(None);
13721411
let mut amount_msat = 0;
13731412
let mut receiver_node_id = None;
1413+
let mut htlcs: Option<Vec<ClaimedHTLC>> = Some(vec![]);
1414+
let mut sender_intended_total_msat: Option<u64> = None;
13741415
read_tlv_fields!(reader, {
13751416
(0, payment_hash, required),
13761417
(1, receiver_node_id, option),
13771418
(2, purpose, upgradable_required),
13781419
(4, amount_msat, required),
1420+
(5, htlcs, optional_vec),
1421+
(7, sender_intended_total_msat, option),
13791422
});
13801423
Ok(Some(Event::PaymentClaimed {
13811424
receiver_node_id,
13821425
payment_hash,
13831426
purpose: _init_tlv_based_struct_field!(purpose, upgradable_required),
13841427
amount_msat,
1428+
htlcs: htlcs.unwrap_or(vec![]),
1429+
sender_intended_total_msat,
13851430
}))
13861431
};
13871432
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 {
@@ -3785,6 +3801,7 @@ where
37853801
if let PendingHTLCRouting::Forward { short_channel_id, .. } = payment.forward_info.routing {
37863802
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
37873803
short_channel_id: payment.prev_short_channel_id,
3804+
user_channel_id: Some(payment.prev_user_channel_id),
37883805
outpoint: payment.prev_funding_outpoint,
37893806
htlc_id: payment.prev_htlc_id,
37903807
incoming_packet_shared_secret: payment.forward_info.incoming_shared_secret,
@@ -3832,6 +3849,7 @@ where
38323849

38333850
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
38343851
short_channel_id: prev_short_channel_id,
3852+
user_channel_id: Some(prev_user_channel_id),
38353853
outpoint: prev_funding_outpoint,
38363854
htlc_id: prev_htlc_id,
38373855
incoming_packet_shared_secret: incoming_shared_secret,
@@ -3936,7 +3954,7 @@ where
39363954
for forward_info in pending_forwards.drain(..) {
39373955
match forward_info {
39383956
HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
3939-
prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id: _,
3957+
prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id,
39403958
forward_info: PendingHTLCInfo {
39413959
incoming_shared_secret, payment_hash, outgoing_amt_msat, outgoing_cltv_value,
39423960
routing: PendingHTLCRouting::Forward { onion_packet, .. }, skimmed_fee_msat, ..
@@ -3945,6 +3963,7 @@ where
39453963
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);
39463964
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
39473965
short_channel_id: prev_short_channel_id,
3966+
user_channel_id: Some(prev_user_channel_id),
39483967
outpoint: prev_funding_outpoint,
39493968
htlc_id: prev_htlc_id,
39503969
incoming_packet_shared_secret: incoming_shared_secret,
@@ -4026,6 +4045,7 @@ where
40264045
let claimable_htlc = ClaimableHTLC {
40274046
prev_hop: HTLCPreviousHopData {
40284047
short_channel_id: prev_short_channel_id,
4048+
user_channel_id: Some(prev_user_channel_id),
40294049
outpoint: prev_funding_outpoint,
40304050
htlc_id: prev_htlc_id,
40314051
incoming_packet_shared_secret: incoming_shared_secret,
@@ -4055,6 +4075,7 @@ where
40554075
);
40564076
failed_forwards.push((HTLCSource::PreviousHopData(HTLCPreviousHopData {
40574077
short_channel_id: $htlc.prev_hop.short_channel_id,
4078+
user_channel_id: $htlc.prev_hop.user_channel_id,
40584079
outpoint: prev_funding_outpoint,
40594080
htlc_id: $htlc.prev_hop.htlc_id,
40604081
incoming_packet_shared_secret: $htlc.prev_hop.incoming_packet_shared_secret,
@@ -4786,7 +4807,7 @@ where
47864807
&self.pending_events, &self.logger)
47874808
{ self.push_pending_forwards_ev(); }
47884809
},
4789-
HTLCSource::PreviousHopData(HTLCPreviousHopData { ref short_channel_id, ref htlc_id, ref incoming_packet_shared_secret, ref phantom_shared_secret, ref outpoint }) => {
4810+
HTLCSource::PreviousHopData(HTLCPreviousHopData { ref short_channel_id, ref htlc_id, ref incoming_packet_shared_secret, ref phantom_shared_secret, ref outpoint, .. }) => {
47904811
log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards from us with {:?}", log_bytes!(payment_hash.0), onion_error);
47914812
let err_packet = onion_error.get_encrypted_failure_packet(incoming_packet_shared_secret, phantom_shared_secret);
47924813

@@ -4873,9 +4894,11 @@ where
48734894
}
48744895
}
48754896

4897+
let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
4898+
let sender_intended_value = payment.htlcs.first().map(|htlc| htlc.total_msat);
48764899
let dup_purpose = claimable_payments.pending_claiming_payments.insert(payment_hash,
48774900
ClaimingPayment { amount_msat: payment.htlcs.iter().map(|source| source.value).sum(),
4878-
payment_purpose: payment.purpose, receiver_node_id,
4901+
payment_purpose: payment.purpose, receiver_node_id, htlcs, sender_intended_value
48794902
});
48804903
if dup_purpose.is_some() {
48814904
debug_assert!(false, "Shouldn't get a duplicate pending claim event ever");
@@ -5139,9 +5162,20 @@ where
51395162
match action {
51405163
MonitorUpdateCompletionAction::PaymentClaimed { payment_hash } => {
51415164
let payment = self.claimable_payments.lock().unwrap().pending_claiming_payments.remove(&payment_hash);
5142-
if let Some(ClaimingPayment { amount_msat, payment_purpose: purpose, receiver_node_id }) = payment {
5165+
if let Some(ClaimingPayment {
5166+
amount_msat,
5167+
payment_purpose: purpose,
5168+
receiver_node_id,
5169+
htlcs,
5170+
sender_intended_value: sender_intended_total_msat,
5171+
}) = payment {
51435172
self.pending_events.lock().unwrap().push_back((events::Event::PaymentClaimed {
5144-
payment_hash, purpose, amount_msat, receiver_node_id: Some(receiver_node_id),
5173+
payment_hash,
5174+
purpose,
5175+
amount_msat,
5176+
receiver_node_id: Some(receiver_node_id),
5177+
htlcs,
5178+
sender_intended_total_msat,
51455179
}, None));
51465180
}
51475181
},
@@ -6019,6 +6053,7 @@ where
60196053
log_info!(self.logger, "Failed to forward incoming HTLC: detected duplicate intercepted payment over short channel id {}", scid);
60206054
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
60216055
short_channel_id: prev_short_channel_id,
6056+
user_channel_id: Some(prev_user_channel_id),
60226057
outpoint: prev_funding_outpoint,
60236058
htlc_id: prev_htlc_id,
60246059
incoming_packet_shared_secret: forward_info.incoming_shared_secret,
@@ -7145,6 +7180,7 @@ where
71457180
if height >= htlc.forward_info.outgoing_cltv_value - HTLC_FAIL_BACK_BUFFER {
71467181
let prev_hop_data = HTLCSource::PreviousHopData(HTLCPreviousHopData {
71477182
short_channel_id: htlc.prev_short_channel_id,
7183+
user_channel_id: Some(htlc.prev_user_channel_id),
71487184
htlc_id: htlc.prev_htlc_id,
71497185
incoming_packet_shared_secret: htlc.forward_info.incoming_shared_secret,
71507186
phantom_shared_secret: None,
@@ -7920,7 +7956,8 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, {
79207956
(1, phantom_shared_secret, option),
79217957
(2, outpoint, required),
79227958
(4, htlc_id, required),
7923-
(6, incoming_packet_shared_secret, required)
7959+
(6, incoming_packet_shared_secret, required),
7960+
(7, user_channel_id, option),
79247961
});
79257962

79267963
impl Writeable for ClaimableHTLC {
@@ -9174,7 +9211,7 @@ where
91749211
.expect("Failed to get node_id for phantom node recipient");
91759212
receiver_node_id = Some(phantom_pubkey)
91769213
}
9177-
for claimable_htlc in payment.htlcs {
9214+
for claimable_htlc in &payment.htlcs {
91789215
claimable_amt_msat += claimable_htlc.value;
91799216

91809217
// Add a holding-cell claim of the payment to the Channel, which should be
@@ -9210,6 +9247,8 @@ where
92109247
payment_hash,
92119248
purpose: payment.purpose,
92129249
amount_msat: claimable_amt_msat,
9250+
htlcs: payment.htlcs.iter().map(events::ClaimedHTLC::from).collect(),
9251+
sender_intended_total_msat: payment.htlcs.first().map(|htlc| htlc.total_msat),
92139252
}, None));
92149253
}
92159254
}

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::{self, 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 {
@@ -2284,11 +2299,34 @@ pub fn pass_claimed_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, '
22842299
let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events();
22852300
assert_eq!(claim_event.len(), 1);
22862301
match claim_event[0] {
2287-
Event::PaymentClaimed { purpose: PaymentPurpose::SpontaneousPayment(preimage), .. }|
2288-
Event::PaymentClaimed { purpose: PaymentPurpose::InvoicePayment { payment_preimage: Some(preimage), ..}, .. } =>
2289-
assert_eq!(preimage, our_payment_preimage),
2290-
Event::PaymentClaimed { purpose: PaymentPurpose::InvoicePayment { .. }, payment_hash, .. } =>
2291-
assert_eq!(&payment_hash.0, &Sha256::hash(&our_payment_preimage.0)[..]),
2302+
Event::PaymentClaimed {
2303+
purpose: PaymentPurpose::SpontaneousPayment(preimage),
2304+
amount_msat,
2305+
ref htlcs,
2306+
.. }
2307+
| Event::PaymentClaimed {
2308+
purpose: PaymentPurpose::InvoicePayment { payment_preimage: Some(preimage), ..},
2309+
ref htlcs,
2310+
amount_msat,
2311+
..
2312+
} => {
2313+
assert_eq!(preimage, our_payment_preimage);
2314+
assert_eq!(htlcs.len(), expected_paths.len()); // One per path.
2315+
assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::<u64>(), amount_msat);
2316+
expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc));
2317+
},
2318+
Event::PaymentClaimed {
2319+
purpose: PaymentPurpose::InvoicePayment { .. },
2320+
payment_hash,
2321+
amount_msat,
2322+
ref htlcs,
2323+
..
2324+
} => {
2325+
assert_eq!(&payment_hash.0, &Sha256::hash(&our_payment_preimage.0)[..]);
2326+
assert_eq!(htlcs.len(), expected_paths.len()); // One per path.
2327+
assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::<u64>(), amount_msat);
2328+
expected_paths.iter().zip(htlcs).for_each(|(path, htlc)| check_claimed_htlc_channel(origin_node, path, htlc));
2329+
}
22922330
_ => panic!(),
22932331
}
22942332

0 commit comments

Comments
 (0)