Skip to content

Commit 2037515

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

File tree

5 files changed

+51
-36
lines changed

5 files changed

+51
-36
lines changed

lightning/src/ln/channel.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5984,6 +5984,7 @@ mod tests {
59845984
first_hop_htlc_msat: 548,
59855985
payment_id: PaymentId([42; 32]),
59865986
payment_secret: None,
5987+
payment_metadata: None,
59875988
payee: None,
59885989
}
59895990
});

lightning/src/ln/channelmanager.rs

Lines changed: 28 additions & 16 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
payee: Option<Payee>,
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, payee } => {
511+
HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, payment_metadata, first_hop_htlc_msat, payee } => {
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
payee.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
payee: None,
532535
}
533536
}
@@ -733,6 +736,7 @@ pub(crate) enum PendingOutboundPayment {
733736
session_privs: HashSet<[u8; 32]>,
734737
payment_hash: PaymentHash,
735738
payment_secret: Option<PaymentSecret>,
739+
payment_metadata: Option<Vec<u8>>,
736740
pending_amt_msat: u64,
737741
/// Used to track the fee paid. Only present if the payment was serialized on 0.0.103+.
738742
pending_fee_msat: Option<u64>,
@@ -2429,15 +2433,15 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24292433
}
24302434

24312435
// Only public for testing, this should otherwise never be called direcly
2432-
pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payee: &Option<Payee>, payment_hash: &PaymentHash, payment_secret: &Option<PaymentSecret>, total_value: u64, cur_height: u32, payment_id: PaymentId, keysend_preimage: &Option<PaymentPreimage>) -> Result<(), APIError> {
2436+
pub(crate) fn send_payment_along_path(&self, path: &Vec<RouteHop>, payee: &Option<Payee>, 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> {
24332437
log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
24342438
let prng_seed = self.keys_manager.get_secure_random_bytes();
24352439
let session_priv_bytes = self.keys_manager.get_secure_random_bytes();
24362440
let session_priv = SecretKey::from_slice(&session_priv_bytes[..]).expect("RNG is busted");
24372441

24382442
let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
24392443
.map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"})?;
2440-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, cur_height, keysend_preimage)?;
2444+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, payment_metadata.clone(), cur_height, keysend_preimage)?;
24412445
if onion_utils::route_size_insane(&onion_payloads) {
24422446
return Err(APIError::RouteError{err: "Route size too large considering onion data"});
24432447
}
@@ -2471,6 +2475,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24712475
pending_fee_msat: Some(0),
24722476
payment_hash: *payment_hash,
24732477
payment_secret: *payment_secret,
2478+
payment_metadata: payment_metadata.clone(),
24742479
starting_block_height: self.best_block.read().unwrap().height(),
24752480
total_msat: total_value,
24762481
});
@@ -2494,6 +2499,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24942499
first_hop_htlc_msat: htlc_msat,
24952500
payment_id,
24962501
payment_secret: payment_secret.clone(),
2502+
payment_metadata: payment_metadata.clone(),
24972503
payee: payee.clone(),
24982504
}, onion_packet, &self.logger),
24992505
channel_state, chan)
@@ -2581,7 +2587,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
25812587
self.send_payment_internal(route, payment_hash, payment_secret, None, None, None)
25822588
}
25832589

2584-
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> {
2590+
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> {
25852591
if route.paths.len() < 1 {
25862592
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
25872593
}
@@ -2623,7 +2629,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
26232629
let cur_height = self.best_block.read().unwrap().height() + 1;
26242630
let mut results = Vec::new();
26252631
for path in route.paths.iter() {
2626-
results.push(self.send_payment_along_path(&path, &route.payee, &payment_hash, payment_secret, total_value, cur_height, payment_id, &keysend_preimage));
2632+
results.push(self.send_payment_along_path(&path, &route.payee, &payment_hash, payment_secret, &payment_metadata, total_value, cur_height, payment_id, &keysend_preimage));
26272633
}
26282634
let mut has_ok = false;
26292635
let mut has_err = false;
@@ -2686,20 +2692,20 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
26862692
}
26872693
}
26882694

2689-
let (total_msat, payment_hash, payment_secret) = {
2695+
let (total_msat, payment_hash, payment_secret, payment_metadata) = {
26902696
let outbounds = self.pending_outbound_payments.lock().unwrap();
26912697
if let Some(payment) = outbounds.get(&payment_id) {
26922698
match payment {
26932699
PendingOutboundPayment::Retryable {
2694-
total_msat, payment_hash, payment_secret, pending_amt_msat, ..
2700+
total_msat, payment_hash, payment_secret, pending_amt_msat, payment_metadata, ..
26952701
} => {
26962702
let retry_amt_msat: u64 = route.paths.iter().map(|path| path.last().unwrap().fee_msat).sum();
26972703
if retry_amt_msat + *pending_amt_msat > *total_msat * (100 + RETRY_OVERFLOW_PERCENTAGE) / 100 {
26982704
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
26992705
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()
27002706
}))
27012707
}
2702-
(*total_msat, *payment_hash, *payment_secret)
2708+
(*total_msat, *payment_hash, *payment_secret, payment_metadata.clone())
27032709
},
27042710
PendingOutboundPayment::Legacy { .. } => {
27052711
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
@@ -2723,7 +2729,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
27232729
}))
27242730
}
27252731
};
2726-
return self.send_payment_internal(route, payment_hash, &payment_secret, None, Some(payment_id), Some(total_msat)).map(|_| ())
2732+
return self.send_payment_internal(route, payment_hash, &payment_secret, payment_metadata, None, Some(payment_id), Some(total_msat)).map(|_| ())
27272733
}
27282734

27292735
/// Signals that no further retries for the given payment will occur.
@@ -2777,7 +2783,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
27772783
None => PaymentPreimage(self.keys_manager.get_secure_random_bytes()),
27782784
};
27792785
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
2780-
match self.send_payment_internal(route, payment_hash, &None, Some(preimage), None, None) {
2786+
match self.send_payment_internal(route, payment_hash, &None, None, Some(preimage), None, None) {
27812787
Ok(payment_id) => Ok((payment_hash, payment_id)),
27822788
Err(e) => Err(e)
27832789
}
@@ -6001,6 +6007,7 @@ impl Readable for HTLCSource {
60016007
let mut path = Some(Vec::new());
60026008
let mut payment_id = None;
60036009
let mut payment_secret = None;
6010+
let mut payment_metadata = None;
60046011
let mut payee = None;
60056012
read_tlv_fields!(reader, {
60066013
(0, session_priv, required),
@@ -6009,6 +6016,7 @@ impl Readable for HTLCSource {
60096016
(3, payment_secret, option),
60106017
(4, path, vec_type),
60116018
(5, payee, option),
6019+
(7, payment_metadata, option),
60126020
});
60136021
if payment_id.is_none() {
60146022
// For backwards compat, if there was no payment_id written, use the session_priv bytes
@@ -6021,6 +6029,7 @@ impl Readable for HTLCSource {
60216029
path: path.unwrap(),
60226030
payment_id: payment_id.unwrap(),
60236031
payment_secret,
6032+
payment_metadata,
60246033
payee,
60256034
})
60266035
}
@@ -6033,7 +6042,7 @@ impl Readable for HTLCSource {
60336042
impl Writeable for HTLCSource {
60346043
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::io::Error> {
60356044
match self {
6036-
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, payee } => {
6045+
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, ref payment_metadata, payee } => {
60376046
0u8.write(writer)?;
60386047
let payment_id_opt = Some(payment_id);
60396048
write_tlv_fields!(writer, {
@@ -6043,6 +6052,7 @@ impl Writeable for HTLCSource {
60436052
(3, payment_secret, option),
60446053
(4, path, vec_type),
60456054
(5, payee, option),
6055+
(7, payment_metadata, option),
60466056
});
60476057
}
60486058
HTLCSource::PreviousHopData(ref field) => {
@@ -6097,6 +6107,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
60976107
(0, session_privs, required),
60986108
(1, pending_fee_msat, option),
60996109
(2, payment_hash, required),
6110+
(3, payment_metadata, option),
61006111
(4, payment_secret, option),
61016112
(6, total_msat, required),
61026113
(8, pending_amt_msat, required),
@@ -6549,7 +6560,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
65496560
for (_, monitor) in args.channel_monitors {
65506561
if by_id.get(&monitor.get_funding_txo().0.to_channel_id()).is_none() {
65516562
for (htlc_source, htlc) in monitor.get_pending_outbound_htlcs() {
6552-
if let HTLCSource::OutboundRoute { payment_id, session_priv, path, payment_secret, .. } = htlc_source {
6563+
if let HTLCSource::OutboundRoute { payment_id, session_priv, path, payment_secret, payment_metadata, .. } = htlc_source {
65536564
if path.is_empty() {
65546565
log_error!(args.logger, "Got an empty path for a pending payment");
65556566
return Err(DecodeError::InvalidValue);
@@ -6569,6 +6580,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
65696580
session_privs: [session_priv_bytes].iter().map(|a| *a).collect(),
65706581
payment_hash: htlc.payment_hash,
65716582
payment_secret,
6583+
payment_metadata,
65726584
pending_amt_msat: path_amt,
65736585
pending_fee_msat: Some(path_fee),
65746586
total_msat: path_amt,
@@ -6802,7 +6814,7 @@ mod tests {
68026814
// Use the utility function send_payment_along_path to send the payment with MPP data which
68036815
// indicates there are more HTLCs coming.
68046816
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.
6805-
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payee, &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap();
6817+
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payee, &our_payment_hash, &Some(payment_secret), &None, 200_000, cur_height, payment_id, &None).unwrap();
68066818
check_added_monitors!(nodes[0], 1);
68076819
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
68086820
assert_eq!(events.len(), 1);
@@ -6832,7 +6844,7 @@ mod tests {
68326844
expect_payment_failed!(nodes[0], our_payment_hash, true);
68336845

68346846
// Send the second half of the original MPP payment.
6835-
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payee, &our_payment_hash, &Some(payment_secret), 200_000, cur_height, payment_id, &None).unwrap();
6847+
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payee, &our_payment_hash, &Some(payment_secret), &None, 200_000, cur_height, payment_id, &None).unwrap();
68366848
check_added_monitors!(nodes[0], 1);
68376849
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
68386850
assert_eq!(events.len(), 1);
@@ -7024,7 +7036,7 @@ mod tests {
70247036

70257037
let test_preimage = PaymentPreimage([42; 32]);
70267038
let mismatch_payment_hash = PaymentHash([43; 32]);
7027-
let _ = nodes[0].node.send_payment_internal(&route, mismatch_payment_hash, &None, Some(test_preimage), None, None).unwrap();
7039+
let _ = nodes[0].node.send_payment_internal(&route, mismatch_payment_hash, &None, None, Some(test_preimage), None, None).unwrap();
70287040
check_added_monitors!(nodes[0], 1);
70297041

70307042
let updates = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
@@ -7068,7 +7080,7 @@ mod tests {
70687080
let test_preimage = PaymentPreimage([42; 32]);
70697081
let test_secret = PaymentSecret([43; 32]);
70707082
let payment_hash = PaymentHash(Sha256::hash(&test_preimage.0).into_inner());
7071-
let _ = nodes[0].node.send_payment_internal(&route, payment_hash, &Some(test_secret), Some(test_preimage), None, None).unwrap();
7083+
let _ = nodes[0].node.send_payment_internal(&route, payment_hash, &Some(test_secret), None, Some(test_preimage), None, None).unwrap();
70727084
check_added_monitors!(nodes[0], 1);
70737085

70747086
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
@@ -1385,7 +1385,7 @@ fn test_fee_spike_violation_fails_htlc() {
13851385
let cur_height = nodes[1].node.best_block.read().unwrap().height() + 1;
13861386

13871387
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
1388-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, &Some(payment_secret), cur_height, &None).unwrap();
1388+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, &Some(payment_secret), None, cur_height, &None).unwrap();
13891389
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
13901390
let msg = msgs::UpdateAddHTLC {
13911391
channel_id: chan.2,
@@ -1558,7 +1558,7 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() {
15581558
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
15591559
let cur_height = nodes[1].node.best_block.read().unwrap().height() + 1;
15601560
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
1561-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 700_000, &Some(payment_secret), cur_height, &None).unwrap();
1561+
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();
15621562
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
15631563
let msg = msgs::UpdateAddHTLC {
15641564
channel_id: chan.2,
@@ -1723,7 +1723,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() {
17231723
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
17241724
let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
17251725
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route_2.paths[0], &session_priv).unwrap();
1726-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route_2.paths[0], recv_value_2, &None, cur_height, &None).unwrap();
1726+
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();
17271727
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1);
17281728
let msg = msgs::UpdateAddHTLC {
17291729
channel_id: chan.2,
@@ -3308,7 +3308,7 @@ fn fail_backward_pending_htlc_upon_channel_failure() {
33083308
let secp_ctx = Secp256k1::new();
33093309
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
33103310
let current_height = nodes[1].node.best_block.read().unwrap().height() + 1;
3311-
let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads(&route.paths[0], 50_000, &Some(payment_secret), current_height, &None).unwrap();
3311+
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();
33123312
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
33133313
let onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
33143314

@@ -4086,7 +4086,7 @@ fn do_test_htlc_timeout(send_partial_mpp: bool) {
40864086
// indicates there are more HTLCs coming.
40874087
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.
40884088
let payment_id = PaymentId([42; 32]);
4089-
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payee, &our_payment_hash, &Some(payment_secret), 200000, cur_height, payment_id, &None).unwrap();
4089+
nodes[0].node.send_payment_along_path(&route.paths[0], &route.payee, &our_payment_hash, &Some(payment_secret), &None, 200000, cur_height, payment_id, &None).unwrap();
40904090
check_added_monitors!(nodes[0], 1);
40914091
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
40924092
assert_eq!(events.len(), 1);
@@ -6537,7 +6537,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() {
65376537
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
65386538
let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
65396539
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::signing_only(), &route.paths[0], &session_priv).unwrap();
6540-
let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3999999, &Some(our_payment_secret), cur_height, &None).unwrap();
6540+
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();
65416541
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash);
65426542

65436543
let mut msg = msgs::UpdateAddHTLC {

0 commit comments

Comments
 (0)