Skip to content

Commit a523f10

Browse files
TheBlueMattandozw
authored andcommitted
Pipe payment metadata through the HTLC send pipeline
...without exposing it to the public `send_payment` API yet.
1 parent c90e20c commit a523f10

File tree

5 files changed

+52
-37
lines changed

5 files changed

+52
-37
lines changed

lightning/src/ln/channel.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6566,6 +6566,7 @@ mod tests {
65666566
first_hop_htlc_msat: 548,
65676567
payment_id: PaymentId([42; 32]),
65686568
payment_secret: None,
6569+
payment_metadata: None,
65696570
payment_params: None,
65706571
}
65716572
});

lightning/src/ln/channelmanager.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ pub(crate) enum HTLCSource {
212212
first_hop_htlc_msat: u64,
213213
payment_id: PaymentId,
214214
payment_secret: Option<PaymentSecret>,
215+
payment_metadata: Option<Vec<u8>>,
215216
payment_params: Option<PaymentParameters>,
216217
},
217218
}
@@ -223,12 +224,13 @@ impl core::hash::Hash for HTLCSource {
223224
0u8.hash(hasher);
224225
prev_hop_data.hash(hasher);
225226
},
226-
HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, first_hop_htlc_msat, payment_params } => {
227+
HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, payment_metadata, first_hop_htlc_msat, payment_params } => {
227228
1u8.hash(hasher);
228229
path.hash(hasher);
229230
session_priv[..].hash(hasher);
230231
payment_id.hash(hasher);
231232
payment_secret.hash(hasher);
233+
payment_metadata.hash(hasher);
232234
first_hop_htlc_msat.hash(hasher);
233235
payment_params.hash(hasher);
234236
},
@@ -245,6 +247,7 @@ impl HTLCSource {
245247
first_hop_htlc_msat: 0,
246248
payment_id: PaymentId([2; 32]),
247249
payment_secret: None,
250+
payment_metadata: None,
248251
payment_params: None,
249252
}
250253
}
@@ -470,6 +473,7 @@ pub(crate) enum PendingOutboundPayment {
470473
session_privs: HashSet<[u8; 32]>,
471474
payment_hash: PaymentHash,
472475
payment_secret: Option<PaymentSecret>,
476+
payment_metadata: Option<Vec<u8>>,
473477
pending_amt_msat: u64,
474478
/// Used to track the fee paid. Only present if the payment was serialized on 0.0.103+.
475479
pending_fee_msat: Option<u64>,
@@ -2331,15 +2335,15 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
23312335
}
23322336

23332337
// Only public for testing, this should otherwise never be called direcly
2334-
pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payment_params: &Option<PaymentParameters>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option<PaymentPreimage>) -> Result<(), APIError> {
2338+
pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payment_params: &Option<PaymentParameters>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, payment_metadata: &Option<Vec<u8>>, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option<PaymentPreimage>) -> Result<(), APIError> {
23352339
log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
23362340
let prng_seed = self.keys_manager.get_secure_random_bytes();
23372341
let session_priv_bytes = self.keys_manager.get_secure_random_bytes();
23382342
let session_priv = SecretKey::from_slice(&session_priv_bytes[..]).expect("RNG is busted");
23392343

23402344
let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
23412345
.map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"})?;
2342-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, cur_height, keysend_preimage)?;
2346+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, payment_metadata.clone(), cur_height, keysend_preimage)?;
23432347
if onion_utils::route_size_insane(&onion_payloads) {
23442348
return Err(APIError::RouteError{err: "Route size too large considering onion data"});
23452349
}
@@ -2373,6 +2377,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
23732377
pending_fee_msat: Some(0),
23742378
payment_hash: *payment_hash,
23752379
payment_secret: *payment_secret,
2380+
payment_metadata: payment_metadata.clone(),
23762381
starting_block_height: self.best_block.read().unwrap().height(),
23772382
total_msat: total_value,
23782383
});
@@ -2396,6 +2401,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
23962401
first_hop_htlc_msat: htlc_msat,
23972402
payment_id,
23982403
payment_secret: payment_secret.clone(),
2404+
payment_metadata: payment_metadata.clone(),
23992405
payment_params: payment_params.clone(),
24002406
}, onion_packet, &self.logger),
24012407
channel_state, chan)
@@ -2480,10 +2486,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24802486
/// bit set (either as required or as available). If multiple paths are present in the Route,
24812487
/// we assume the invoice had the basic_mpp feature set.
24822488
pub fn send_payment(&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>) -> Result<PaymentId, PaymentSendFailure> {
2483-
self.send_payment_internal(route, payment_hash, payment_secret, None, None, None)
2489+
self.send_payment_internal(route, payment_hash, payment_secret, None, None, None, None)
24842490
}
24852491

2486-
fn send_payment_internal(&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, keysend_preimage: Option<PaymentPreimage>, payment_id: Option<PaymentId>, recv_value_msat: Option<u64>) -> Result<PaymentId, PaymentSendFailure> {
2492+
fn send_payment_internal(&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, payment_metadata: Option<Vec<u8>>, keysend_preimage: Option<PaymentPreimage>, payment_id: Option<PaymentId>, recv_value_msat: Option<u64>) -> Result<PaymentId, PaymentSendFailure> {
24872493
if route.paths.len() < 1 {
24882494
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
24892495
}
@@ -2525,7 +2531,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
25252531
let cur_height = self.best_block.read().unwrap().height() + 1;
25262532
let mut results = Vec::new();
25272533
for path in route.paths.iter() {
2528-
results.push(self.send_payment_along_path(&path, &route.payment_params, &payment_hash, payment_secret, total_value, cur_height, payment_id, &keysend_preimage));
2534+
results.push(self.send_payment_along_path(&path, &route.payment_params, &payment_hash, payment_secret, &payment_metadata, total_value, cur_height, payment_id, &keysend_preimage));
25292535
}
25302536
let mut has_ok = false;
25312537
let mut has_err = false;
@@ -2588,20 +2594,20 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
25882594
}
25892595
}
25902596

2591-
let (total_msat, payment_hash, payment_secret) = {
2597+
let (total_msat, payment_hash, payment_secret, payment_metadata) = {
25922598
let outbounds = self.pending_outbound_payments.lock().unwrap();
25932599
if let Some(payment) = outbounds.get(&payment_id) {
25942600
match payment {
25952601
PendingOutboundPayment::Retryable {
2596-
total_msat, payment_hash, payment_secret, pending_amt_msat, ..
2602+
total_msat, payment_hash, payment_secret, pending_amt_msat, payment_metadata, ..
25972603
} => {
25982604
let retry_amt_msat: u64 = route.paths.iter().map(|path| path.last().unwrap().fee_msat).sum();
25992605
if retry_amt_msat + *pending_amt_msat > *total_msat * (100 + RETRY_OVERFLOW_PERCENTAGE) / 100 {
26002606
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
26012607
err: format!("retry_amt_msat of {} will put pending_amt_msat (currently: {}) more than 10% over total_payment_amt_msat of {}", retry_amt_msat, pending_amt_msat, total_msat).to_string()
26022608
}))
26032609
}
2604-
(*total_msat, *payment_hash, *payment_secret)
2610+
(*total_msat, *payment_hash, *payment_secret, payment_metadata.clone())
26052611
},
26062612
PendingOutboundPayment::Legacy { .. } => {
26072613
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
@@ -2625,7 +2631,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
26252631
}))
26262632
}
26272633
};
2628-
return self.send_payment_internal(route, payment_hash, &payment_secret, None, Some(payment_id), Some(total_msat)).map(|_| ())
2634+
return self.send_payment_internal(route, payment_hash, &payment_secret, payment_metadata, None, Some(payment_id), Some(total_msat)).map(|_| ())
26292635
}
26302636

26312637
/// Signals that no further retries for the given payment will occur.
@@ -2679,7 +2685,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
26792685
None => PaymentPreimage(self.keys_manager.get_secure_random_bytes()),
26802686
};
26812687
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
2682-
match self.send_payment_internal(route, payment_hash, &None, Some(preimage), None, None) {
2688+
match self.send_payment_internal(route, payment_hash, &None, None, Some(preimage), None, None) {
26832689
Ok(payment_id) => Ok((payment_hash, payment_id)),
26842690
Err(e) => Err(e)
26852691
}
@@ -6152,13 +6158,15 @@ impl Readable for HTLCSource {
61526158
let mut payment_id = None;
61536159
let mut payment_secret = None;
61546160
let mut payment_params = None;
6161+
let mut payment_metadata = None;
61556162
read_tlv_fields!(reader, {
61566163
(0, session_priv, required),
61576164
(1, payment_id, option),
61586165
(2, first_hop_htlc_msat, required),
61596166
(3, payment_secret, option),
61606167
(4, path, vec_type),
61616168
(5, payment_params, option),
6169+
(7, payment_metadata, option),
61626170
});
61636171
if payment_id.is_none() {
61646172
// For backwards compat, if there was no payment_id written, use the session_priv bytes
@@ -6172,6 +6180,7 @@ impl Readable for HTLCSource {
61726180
payment_id: payment_id.unwrap(),
61736181
payment_secret,
61746182
payment_params,
6183+
payment_metadata,
61756184
})
61766185
}
61776186
1 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
@@ -6183,7 +6192,7 @@ impl Readable for HTLCSource {
61836192
impl Writeable for HTLCSource {
61846193
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::io::Error> {
61856194
match self {
6186-
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, payment_params } => {
6195+
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, ref payment_metadata, payment_params } => {
61876196
0u8.write(writer)?;
61886197
let payment_id_opt = Some(payment_id);
61896198
write_tlv_fields!(writer, {
@@ -6193,6 +6202,7 @@ impl Writeable for HTLCSource {
61936202
(3, payment_secret, option),
61946203
(4, path, vec_type),
61956204
(5, payment_params, option),
6205+
(7, payment_metadata, option),
61966206
});
61976207
}
61986208
HTLCSource::PreviousHopData(ref field) => {
@@ -6247,6 +6257,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
62476257
(0, session_privs, required),
62486258
(1, pending_fee_msat, option),
62496259
(2, payment_hash, required),
6260+
(3, payment_metadata, option),
62506261
(4, payment_secret, option),
62516262
(6, total_msat, required),
62526263
(8, pending_amt_msat, required),
@@ -6709,7 +6720,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
67096720
for (_, monitor) in args.channel_monitors {
67106721
if by_id.get(&monitor.get_funding_txo().0.to_channel_id()).is_none() {
67116722
for (htlc_source, htlc) in monitor.get_pending_outbound_htlcs() {
6712-
if let HTLCSource::OutboundRoute { payment_id, session_priv, path, payment_secret, .. } = htlc_source {
6723+
if let HTLCSource::OutboundRoute { payment_id, session_priv, path, payment_secret, payment_metadata, .. } = htlc_source {
67136724
if path.is_empty() {
67146725
log_error!(args.logger, "Got an empty path for a pending payment");
67156726
return Err(DecodeError::InvalidValue);
@@ -6729,6 +6740,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
67296740
session_privs: [session_priv_bytes].iter().map(|a| *a).collect(),
67306741
payment_hash: htlc.payment_hash,
67316742
payment_secret,
6743+
payment_metadata,
67326744
pending_amt_msat: path_amt,
67336745
pending_fee_msat: Some(path_fee),
67346746
total_msat: path_amt,
@@ -7004,7 +7016,7 @@ mod tests {
70047016
// Use the utility function send_payment_along_path to send the payment with MPP data which
70057017
// indicates there are more HTLCs coming.
70067018
let cur_height = CHAN_CONFIRM_DEPTH + 1; // route_payment calls send_payment, which adds 1 to the current height. So we do the same here to match.
7007-
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payment_params, &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap();
7019+
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payment_params, &our_payment_hash, &Some(payment_secret), &None, 200_000, cur_height, payment_id, &None).unwrap();
70087020
check_added_monitors!(nodes[0], 1);
70097021
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
70107022
assert_eq!(events.len(), 1);
@@ -7034,7 +7046,7 @@ mod tests {
70347046
expect_payment_failed!(nodes[0], our_payment_hash, true);
70357047

70367048
// Send the second half of the original MPP payment.
7037-
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payment_params, &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap();
7049+
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payment_params, &our_payment_hash, &Some(payment_secret), &None, 200_000, cur_height, payment_id, &None).unwrap();
70387050
check_added_monitors!(nodes[0], 1);
70397051
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
70407052
assert_eq!(events.len(), 1);
@@ -7228,7 +7240,7 @@ mod tests {
72287240

72297241
let test_preimage = PaymentPreimage([42; 32]);
72307242
let mismatch_payment_hash = PaymentHash([43; 32]);
7231-
let _ = nodes[0].node.send_payment_internal(&route, mismatch_payment_hash, &None, Some(test_preimage), None, None).unwrap();
7243+
let _ = nodes[0].node.send_payment_internal(&route, mismatch_payment_hash, &None, None, Some(test_preimage), None, None).unwrap();
72327244
check_added_monitors!(nodes[0], 1);
72337245

72347246
let updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
@@ -7273,7 +7285,7 @@ mod tests {
72737285
let test_preimage = PaymentPreimage([42; 32]);
72747286
let test_secret = PaymentSecret([43; 32]);
72757287
let payment_hash = PaymentHash(Sha256::hash(&test_preimage.0).into_inner());
7276-
let _ = nodes[0].node.send_payment_internal(&route, payment_hash, &Some(test_secret), Some(test_preimage), None, None).unwrap();
7288+
let _ = nodes[0].node.send_payment_internal(&route, payment_hash, &Some(test_secret), None, Some(test_preimage), None, None).unwrap();
72777289
check_added_monitors!(nodes[0], 1);
72787290

72797291
let updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());

lightning/src/ln/functional_tests.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,7 +1371,7 @@ fn test_fee_spike_violation_fails_htlc() {
13711371
let cur_height = nodes[1].node.best_block.read().unwrap().height() + 1;
13721372

13731373
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
1374-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, &Some(payment_secret), cur_height, &None).unwrap();
1374+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, &Some(payment_secret), None, cur_height, &None).unwrap();
13751375
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
13761376
let msg = msgs::UpdateAddHTLC {
13771377
channel_id: chan.2,
@@ -1548,7 +1548,7 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() {
15481548
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
15491549
let cur_height = nodes[1].node.best_block.read().unwrap().height() + 1;
15501550
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
1551-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 700_000, &Some(payment_secret), cur_height, &None).unwrap();
1551+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 700_000, &Some(payment_secret), None, cur_height, &None).unwrap();
15521552
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
15531553
let msg = msgs::UpdateAddHTLC {
15541554
channel_id: chan.2,
@@ -1718,7 +1718,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() {
17181718
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
17191719
let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
17201720
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route_2.paths[0], &session_priv).unwrap();
1721-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route_2.paths[0], recv_value_2, &None, cur_height, &None).unwrap();
1721+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route_2.paths[0], recv_value_2, &None, None, cur_height, &None).unwrap();
17221722
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1);
17231723
let msg = msgs::UpdateAddHTLC {
17241724
channel_id: chan.2,
@@ -3317,7 +3317,7 @@ fn fail_backward_pending_htlc_upon_channel_failure() {
33173317
let secp_ctx = Secp256k1::new();
33183318
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
33193319
let current_height = nodes[1].node.best_block.read().unwrap().height() + 1;
3320-
let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads(&route.paths[0], 50_000, &Some(payment_secret), current_height, &None).unwrap();
3320+
let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads(&route.paths[0], 50_000, &Some(payment_secret), None, current_height, &None).unwrap();
33213321
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
33223322
let onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
33233323

@@ -4207,7 +4207,7 @@ fn do_test_htlc_timeout(send_partial_mpp: bool) {
42074207
// indicates there are more HTLCs coming.
42084208
let cur_height = CHAN_CONFIRM_DEPTH + 1; // route_payment calls send_payment, which adds 1 to the current height. So we do the same here to match.
42094209
let payment_id = PaymentId([42; 32]);
4210-
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payment_params, &our_payment_hash, &Some(payment_secret), 200000, cur_height, payment_id, &None).unwrap();
4210+
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payment_params, &our_payment_hash, &Some(payment_secret), &None, 200000, cur_height, payment_id, &None).unwrap();
42114211
check_added_monitors!(nodes[0], 1);
42124212
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
42134213
assert_eq!(events.len(), 1);
@@ -6670,7 +6670,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() {
66706670
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
66716671
let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
66726672
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::signing_only(), &route.paths[0], &session_priv).unwrap();
6673-
let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3999999, &Some(our_payment_secret), cur_height, &None).unwrap();
6673+
let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3999999, &Some(our_payment_secret), None, cur_height, &None).unwrap();
66746674
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash);
66756675

66766676
let mut msg = msgs::UpdateAddHTLC {

0 commit comments

Comments
 (0)