Skip to content

Commit 5c3049f

Browse files
committed
Pipe payment metadata through the HTLC send pipeline
...without exposing it to the public `send_payment` API yet.
1 parent 9744e8b commit 5c3049f

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
@@ -6080,6 +6080,7 @@ mod tests {
60806080
first_hop_htlc_msat: 548,
60816081
payment_id: PaymentId([42; 32]),
60826082
payment_secret: None,
6083+
payment_metadata: None,
60836084
payment_params: None,
60846085
}
60856086
});

lightning/src/ln/channelmanager.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ pub(crate) enum HTLCSource {
496496
first_hop_htlc_msat: u64,
497497
payment_id: PaymentId,
498498
payment_secret: Option<PaymentSecret>,
499+
payment_metadata: Option<Vec<u8>>,
499500
payment_params: Option<PaymentParameters>,
500501
},
501502
}
@@ -507,12 +508,13 @@ impl core::hash::Hash for HTLCSource {
507508
0u8.hash(hasher);
508509
prev_hop_data.hash(hasher);
509510
},
510-
HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, first_hop_htlc_msat, payment_params } => {
511+
HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, payment_metadata, first_hop_htlc_msat, payment_params } => {
511512
1u8.hash(hasher);
512513
path.hash(hasher);
513514
session_priv[..].hash(hasher);
514515
payment_id.hash(hasher);
515516
payment_secret.hash(hasher);
517+
payment_metadata.hash(hasher);
516518
first_hop_htlc_msat.hash(hasher);
517519
payment_params.hash(hasher);
518520
},
@@ -528,6 +530,7 @@ impl HTLCSource {
528530
first_hop_htlc_msat: 0,
529531
payment_id: PaymentId([2; 32]),
530532
payment_secret: None,
533+
payment_metadata: None,
531534
payment_params: None,
532535
}
533536
}
@@ -739,6 +742,7 @@ pub(crate) enum PendingOutboundPayment {
739742
session_privs: HashSet<[u8; 32]>,
740743
payment_hash: PaymentHash,
741744
payment_secret: Option<PaymentSecret>,
745+
payment_metadata: Option<Vec<u8>>,
742746
pending_amt_msat: u64,
743747
/// Used to track the fee paid. Only present if the payment was serialized on 0.0.103+.
744748
pending_fee_msat: Option<u64>,
@@ -2433,15 +2437,15 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24332437
}
24342438

24352439
// Only public for testing, this should otherwise never be called direcly
2436-
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> {
2440+
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> {
24372441
log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
24382442
let prng_seed = self.keys_manager.get_secure_random_bytes();
24392443
let session_priv_bytes = self.keys_manager.get_secure_random_bytes();
24402444
let session_priv = SecretKey::from_slice(&session_priv_bytes[..]).expect("RNG is busted");
24412445

24422446
let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
24432447
.map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"})?;
2444-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, cur_height, keysend_preimage)?;
2448+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, payment_metadata.clone(), cur_height, keysend_preimage)?;
24452449
if onion_utils::route_size_insane(&onion_payloads) {
24462450
return Err(APIError::RouteError{err: "Route size too large considering onion data"});
24472451
}
@@ -2475,6 +2479,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24752479
pending_fee_msat: Some(0),
24762480
payment_hash: *payment_hash,
24772481
payment_secret: *payment_secret,
2482+
payment_metadata: payment_metadata.clone(),
24782483
starting_block_height: self.best_block.read().unwrap().height(),
24792484
total_msat: total_value,
24802485
});
@@ -2498,6 +2503,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24982503
first_hop_htlc_msat: htlc_msat,
24992504
payment_id,
25002505
payment_secret: payment_secret.clone(),
2506+
payment_metadata: payment_metadata.clone(),
25012507
payment_params: payment_params.clone(),
25022508
}, onion_packet, &self.logger),
25032509
channel_state, chan)
@@ -2582,10 +2588,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
25822588
/// bit set (either as required or as available). If multiple paths are present in the Route,
25832589
/// we assume the invoice had the basic_mpp feature set.
25842590
pub fn send_payment(&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>) -> Result<PaymentId, PaymentSendFailure> {
2585-
self.send_payment_internal(route, payment_hash, payment_secret, None, None, None)
2591+
self.send_payment_internal(route, payment_hash, payment_secret, None, None, None, None)
25862592
}
25872593

2588-
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> {
2594+
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> {
25892595
if route.paths.len() < 1 {
25902596
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
25912597
}
@@ -2627,7 +2633,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
26272633
let cur_height = self.best_block.read().unwrap().height() + 1;
26282634
let mut results = Vec::new();
26292635
for path in route.paths.iter() {
2630-
results.push(self.send_payment_along_path(&path, &route.payment_params, &payment_hash, payment_secret, total_value, cur_height, payment_id, &keysend_preimage));
2636+
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));
26312637
}
26322638
let mut has_ok = false;
26332639
let mut has_err = false;
@@ -2690,20 +2696,20 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
26902696
}
26912697
}
26922698

2693-
let (total_msat, payment_hash, payment_secret) = {
2699+
let (total_msat, payment_hash, payment_secret, payment_metadata) = {
26942700
let outbounds = self.pending_outbound_payments.lock().unwrap();
26952701
if let Some(payment) = outbounds.get(&payment_id) {
26962702
match payment {
26972703
PendingOutboundPayment::Retryable {
2698-
total_msat, payment_hash, payment_secret, pending_amt_msat, ..
2704+
total_msat, payment_hash, payment_secret, pending_amt_msat, payment_metadata, ..
26992705
} => {
27002706
let retry_amt_msat: u64 = route.paths.iter().map(|path| path.last().unwrap().fee_msat).sum();
27012707
if retry_amt_msat + *pending_amt_msat > *total_msat * (100 + RETRY_OVERFLOW_PERCENTAGE) / 100 {
27022708
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
27032709
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()
27042710
}))
27052711
}
2706-
(*total_msat, *payment_hash, *payment_secret)
2712+
(*total_msat, *payment_hash, *payment_secret, payment_metadata.clone())
27072713
},
27082714
PendingOutboundPayment::Legacy { .. } => {
27092715
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
@@ -2727,7 +2733,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
27272733
}))
27282734
}
27292735
};
2730-
return self.send_payment_internal(route, payment_hash, &payment_secret, None, Some(payment_id), Some(total_msat)).map(|_| ())
2736+
return self.send_payment_internal(route, payment_hash, &payment_secret, payment_metadata, None, Some(payment_id), Some(total_msat)).map(|_| ())
27312737
}
27322738

27332739
/// Signals that no further retries for the given payment will occur.
@@ -2781,7 +2787,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
27812787
None => PaymentPreimage(self.keys_manager.get_secure_random_bytes()),
27822788
};
27832789
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
2784-
match self.send_payment_internal(route, payment_hash, &None, Some(preimage), None, None) {
2790+
match self.send_payment_internal(route, payment_hash, &None, None, Some(preimage), None, None) {
27852791
Ok(payment_id) => Ok((payment_hash, payment_id)),
27862792
Err(e) => Err(e)
27872793
}
@@ -6006,13 +6012,15 @@ impl Readable for HTLCSource {
60066012
let mut payment_id = None;
60076013
let mut payment_secret = None;
60086014
let mut payment_params = None;
6015+
let mut payment_metadata = None;
60096016
read_tlv_fields!(reader, {
60106017
(0, session_priv, required),
60116018
(1, payment_id, option),
60126019
(2, first_hop_htlc_msat, required),
60136020
(3, payment_secret, option),
60146021
(4, path, vec_type),
60156022
(5, payment_params, option),
6023+
(7, payment_metadata, option),
60166024
});
60176025
if payment_id.is_none() {
60186026
// For backwards compat, if there was no payment_id written, use the session_priv bytes
@@ -6026,6 +6034,7 @@ impl Readable for HTLCSource {
60266034
payment_id: payment_id.unwrap(),
60276035
payment_secret,
60286036
payment_params,
6037+
payment_metadata,
60296038
})
60306039
}
60316040
1 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
@@ -6037,7 +6046,7 @@ impl Readable for HTLCSource {
60376046
impl Writeable for HTLCSource {
60386047
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::io::Error> {
60396048
match self {
6040-
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, payment_params } => {
6049+
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, ref payment_metadata, payment_params } => {
60416050
0u8.write(writer)?;
60426051
let payment_id_opt = Some(payment_id);
60436052
write_tlv_fields!(writer, {
@@ -6047,6 +6056,7 @@ impl Writeable for HTLCSource {
60476056
(3, payment_secret, option),
60486057
(4, path, vec_type),
60496058
(5, payment_params, option),
6059+
(7, payment_metadata, option),
60506060
});
60516061
}
60526062
HTLCSource::PreviousHopData(ref field) => {
@@ -6101,6 +6111,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
61016111
(0, session_privs, required),
61026112
(1, pending_fee_msat, option),
61036113
(2, payment_hash, required),
6114+
(3, payment_metadata, option),
61046115
(4, payment_secret, option),
61056116
(6, total_msat, required),
61066117
(8, pending_amt_msat, required),
@@ -6557,7 +6568,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
65576568
for (_, monitor) in args.channel_monitors {
65586569
if by_id.get(&monitor.get_funding_txo().0.to_channel_id()).is_none() {
65596570
for (htlc_source, htlc) in monitor.get_pending_outbound_htlcs() {
6560-
if let HTLCSource::OutboundRoute { payment_id, session_priv, path, payment_secret, .. } = htlc_source {
6571+
if let HTLCSource::OutboundRoute { payment_id, session_priv, path, payment_secret, payment_metadata, .. } = htlc_source {
65616572
if path.is_empty() {
65626573
log_error!(args.logger, "Got an empty path for a pending payment");
65636574
return Err(DecodeError::InvalidValue);
@@ -6577,6 +6588,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
65776588
session_privs: [session_priv_bytes].iter().map(|a| *a).collect(),
65786589
payment_hash: htlc.payment_hash,
65796590
payment_secret,
6591+
payment_metadata,
65806592
pending_amt_msat: path_amt,
65816593
pending_fee_msat: Some(path_fee),
65826594
total_msat: path_amt,
@@ -6818,7 +6830,7 @@ mod tests {
68186830
// Use the utility function send_payment_along_path to send the payment with MPP data which
68196831
// indicates there are more HTLCs coming.
68206832
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.
6821-
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();
6833+
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();
68226834
check_added_monitors!(nodes[0], 1);
68236835
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
68246836
assert_eq!(events.len(), 1);
@@ -6848,7 +6860,7 @@ mod tests {
68486860
expect_payment_failed!(nodes[0], our_payment_hash, true);
68496861

68506862
// Send the second half of the original MPP payment.
6851-
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();
6863+
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();
68526864
check_added_monitors!(nodes[0], 1);
68536865
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
68546866
assert_eq!(events.len(), 1);
@@ -7040,7 +7052,7 @@ mod tests {
70407052

70417053
let test_preimage = PaymentPreimage([42; 32]);
70427054
let mismatch_payment_hash = PaymentHash([43; 32]);
7043-
let _ = nodes[0].node.send_payment_internal(&route, mismatch_payment_hash, &None, Some(test_preimage), None, None).unwrap();
7055+
let _ = nodes[0].node.send_payment_internal(&route, mismatch_payment_hash, &None, None, Some(test_preimage), None, None).unwrap();
70447056
check_added_monitors!(nodes[0], 1);
70457057

70467058
let updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
@@ -7084,7 +7096,7 @@ mod tests {
70847096
let test_preimage = PaymentPreimage([42; 32]);
70857097
let test_secret = PaymentSecret([43; 32]);
70867098
let payment_hash = PaymentHash(Sha256::hash(&test_preimage.0).into_inner());
7087-
let _ = nodes[0].node.send_payment_internal(&route, payment_hash, &Some(test_secret), Some(test_preimage), None, None).unwrap();
7099+
let _ = nodes[0].node.send_payment_internal(&route, payment_hash, &Some(test_secret), None, Some(test_preimage), None, None).unwrap();
70887100
check_added_monitors!(nodes[0], 1);
70897101

70907102
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
@@ -1388,7 +1388,7 @@ fn test_fee_spike_violation_fails_htlc() {
13881388
let cur_height = nodes[1].node.best_block.read().unwrap().height() + 1;
13891389

13901390
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
1391-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, &Some(payment_secret), cur_height, &None).unwrap();
1391+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, &Some(payment_secret), None, cur_height, &None).unwrap();
13921392
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
13931393
let msg = msgs::UpdateAddHTLC {
13941394
channel_id: chan.2,
@@ -1565,7 +1565,7 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() {
15651565
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
15661566
let cur_height = nodes[1].node.best_block.read().unwrap().height() + 1;
15671567
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
1568-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 700_000, &Some(payment_secret), cur_height, &None).unwrap();
1568+
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();
15691569
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
15701570
let msg = msgs::UpdateAddHTLC {
15711571
channel_id: chan.2,
@@ -1735,7 +1735,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() {
17351735
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
17361736
let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
17371737
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route_2.paths[0], &session_priv).unwrap();
1738-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route_2.paths[0], recv_value_2, &None, cur_height, &None).unwrap();
1738+
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();
17391739
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1);
17401740
let msg = msgs::UpdateAddHTLC {
17411741
channel_id: chan.2,
@@ -3321,7 +3321,7 @@ fn fail_backward_pending_htlc_upon_channel_failure() {
33213321
let secp_ctx = Secp256k1::new();
33223322
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
33233323
let current_height = nodes[1].node.best_block.read().unwrap().height() + 1;
3324-
let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads(&route.paths[0], 50_000, &Some(payment_secret), current_height, &None).unwrap();
3324+
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();
33253325
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
33263326
let onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
33273327

@@ -4099,7 +4099,7 @@ fn do_test_htlc_timeout(send_partial_mpp: bool) {
40994099
// indicates there are more HTLCs coming.
41004100
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.
41014101
let payment_id = PaymentId([42; 32]);
4102-
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();
4102+
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();
41034103
check_added_monitors!(nodes[0], 1);
41044104
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
41054105
assert_eq!(events.len(), 1);
@@ -6554,7 +6554,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() {
65546554
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
65556555
let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
65566556
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::signing_only(), &route.paths[0], &session_priv).unwrap();
6557-
let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3999999, &Some(our_payment_secret), cur_height, &None).unwrap();
6557+
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();
65586558
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash);
65596559

65606560
let mut msg = msgs::UpdateAddHTLC {

0 commit comments

Comments
 (0)