Skip to content

Commit 233e35a

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 d129776 commit 233e35a

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
@@ -211,6 +211,7 @@ pub(crate) enum HTLCSource {
211211
first_hop_htlc_msat: u64,
212212
payment_id: PaymentId,
213213
payment_secret: Option<PaymentSecret>,
214+
payment_metadata: Option<Vec<u8>>,
214215
payment_params: Option<PaymentParameters>,
215216
},
216217
}
@@ -222,12 +223,13 @@ impl core::hash::Hash for HTLCSource {
222223
0u8.hash(hasher);
223224
prev_hop_data.hash(hasher);
224225
},
225-
HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, first_hop_htlc_msat, payment_params } => {
226+
HTLCSource::OutboundRoute { path, session_priv, payment_id, payment_secret, payment_metadata, first_hop_htlc_msat, payment_params } => {
226227
1u8.hash(hasher);
227228
path.hash(hasher);
228229
session_priv[..].hash(hasher);
229230
payment_id.hash(hasher);
230231
payment_secret.hash(hasher);
232+
payment_metadata.hash(hasher);
231233
first_hop_htlc_msat.hash(hasher);
232234
payment_params.hash(hasher);
233235
},
@@ -244,6 +246,7 @@ impl HTLCSource {
244246
first_hop_htlc_msat: 0,
245247
payment_id: PaymentId([2; 32]),
246248
payment_secret: None,
249+
payment_metadata: None,
247250
payment_params: None,
248251
}
249252
}
@@ -469,6 +472,7 @@ pub(crate) enum PendingOutboundPayment {
469472
session_privs: HashSet<[u8; 32]>,
470473
payment_hash: PaymentHash,
471474
payment_secret: Option<PaymentSecret>,
475+
payment_metadata: Option<Vec<u8>>,
472476
pending_amt_msat: u64,
473477
/// Used to track the fee paid. Only present if the payment was serialized on 0.0.103+.
474478
pending_fee_msat: Option<u64>,
@@ -2329,15 +2333,15 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
23292333
}
23302334

23312335
// Only public for testing, this should otherwise never be called direcly
2332-
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> {
2336+
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> {
23332337
log_trace!(self.logger, "Attempting to send payment for path with next hop {}", path.first().unwrap().short_channel_id);
23342338
let prng_seed = self.keys_manager.get_secure_random_bytes();
23352339
let session_priv_bytes = self.keys_manager.get_secure_random_bytes();
23362340
let session_priv = SecretKey::from_slice(&session_priv_bytes[..]).expect("RNG is busted");
23372341

23382342
let onion_keys = onion_utils::construct_onion_keys(&self.secp_ctx, &path, &session_priv)
23392343
.map_err(|_| APIError::RouteError{err: "Pubkey along hop was maliciously selected"})?;
2340-
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, cur_height, keysend_preimage)?;
2344+
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(path, total_value, payment_secret, payment_metadata.clone(), cur_height, keysend_preimage)?;
23412345
if onion_utils::route_size_insane(&onion_payloads) {
23422346
return Err(APIError::RouteError{err: "Route size too large considering onion data"});
23432347
}
@@ -2371,6 +2375,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
23712375
pending_fee_msat: Some(0),
23722376
payment_hash: *payment_hash,
23732377
payment_secret: *payment_secret,
2378+
payment_metadata: payment_metadata.clone(),
23742379
starting_block_height: self.best_block.read().unwrap().height(),
23752380
total_msat: total_value,
23762381
});
@@ -2394,6 +2399,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
23942399
first_hop_htlc_msat: htlc_msat,
23952400
payment_id,
23962401
payment_secret: payment_secret.clone(),
2402+
payment_metadata: payment_metadata.clone(),
23972403
payment_params: payment_params.clone(),
23982404
}, onion_packet, &self.logger),
23992405
channel_state, chan)
@@ -2478,10 +2484,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
24782484
/// bit set (either as required or as available). If multiple paths are present in the Route,
24792485
/// we assume the invoice had the basic_mpp feature set.
24802486
pub fn send_payment(&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>) -> Result<PaymentId, PaymentSendFailure> {
2481-
self.send_payment_internal(route, payment_hash, payment_secret, None, None, None)
2487+
self.send_payment_internal(route, payment_hash, payment_secret, None, None, None, None)
24822488
}
24832489

2484-
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> {
2490+
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> {
24852491
if route.paths.len() < 1 {
24862492
return Err(PaymentSendFailure::ParameterError(APIError::RouteError{err: "There must be at least one path to send over"}));
24872493
}
@@ -2523,7 +2529,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
25232529
let cur_height = self.best_block.read().unwrap().height() + 1;
25242530
let mut results = Vec::new();
25252531
for path in route.paths.iter() {
2526-
results.push(self.send_payment_along_path(&path, &route.payment_params, &payment_hash, payment_secret, total_value, cur_height, payment_id, &keysend_preimage));
2532+
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));
25272533
}
25282534
let mut has_ok = false;
25292535
let mut has_err = false;
@@ -2586,20 +2592,20 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
25862592
}
25872593
}
25882594

2589-
let (total_msat, payment_hash, payment_secret) = {
2595+
let (total_msat, payment_hash, payment_secret, payment_metadata) = {
25902596
let outbounds = self.pending_outbound_payments.lock().unwrap();
25912597
if let Some(payment) = outbounds.get(&payment_id) {
25922598
match payment {
25932599
PendingOutboundPayment::Retryable {
2594-
total_msat, payment_hash, payment_secret, pending_amt_msat, ..
2600+
total_msat, payment_hash, payment_secret, pending_amt_msat, payment_metadata, ..
25952601
} => {
25962602
let retry_amt_msat: u64 = route.paths.iter().map(|path| path.last().unwrap().fee_msat).sum();
25972603
if retry_amt_msat + *pending_amt_msat > *total_msat * (100 + RETRY_OVERFLOW_PERCENTAGE) / 100 {
25982604
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
25992605
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()
26002606
}))
26012607
}
2602-
(*total_msat, *payment_hash, *payment_secret)
2608+
(*total_msat, *payment_hash, *payment_secret, payment_metadata.clone())
26032609
},
26042610
PendingOutboundPayment::Legacy { .. } => {
26052611
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
@@ -2623,7 +2629,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
26232629
}))
26242630
}
26252631
};
2626-
return self.send_payment_internal(route, payment_hash, &payment_secret, None, Some(payment_id), Some(total_msat)).map(|_| ())
2632+
return self.send_payment_internal(route, payment_hash, &payment_secret, payment_metadata, None, Some(payment_id), Some(total_msat)).map(|_| ())
26272633
}
26282634

26292635
/// Signals that no further retries for the given payment will occur.
@@ -2677,7 +2683,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
26772683
None => PaymentPreimage(self.keys_manager.get_secure_random_bytes()),
26782684
};
26792685
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
2680-
match self.send_payment_internal(route, payment_hash, &None, Some(preimage), None, None) {
2686+
match self.send_payment_internal(route, payment_hash, &None, None, Some(preimage), None, None) {
26812687
Ok(payment_id) => Ok((payment_hash, payment_id)),
26822688
Err(e) => Err(e)
26832689
}
@@ -6149,13 +6155,15 @@ impl Readable for HTLCSource {
61496155
let mut payment_id = None;
61506156
let mut payment_secret = None;
61516157
let mut payment_params = None;
6158+
let mut payment_metadata = None;
61526159
read_tlv_fields!(reader, {
61536160
(0, session_priv, required),
61546161
(1, payment_id, option),
61556162
(2, first_hop_htlc_msat, required),
61566163
(3, payment_secret, option),
61576164
(4, path, vec_type),
61586165
(5, payment_params, option),
6166+
(7, payment_metadata, option),
61596167
});
61606168
if payment_id.is_none() {
61616169
// For backwards compat, if there was no payment_id written, use the session_priv bytes
@@ -6169,6 +6177,7 @@ impl Readable for HTLCSource {
61696177
payment_id: payment_id.unwrap(),
61706178
payment_secret,
61716179
payment_params,
6180+
payment_metadata,
61726181
})
61736182
}
61746183
1 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
@@ -6180,7 +6189,7 @@ impl Readable for HTLCSource {
61806189
impl Writeable for HTLCSource {
61816190
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::io::Error> {
61826191
match self {
6183-
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, payment_params } => {
6192+
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, payment_secret, ref payment_metadata, payment_params } => {
61846193
0u8.write(writer)?;
61856194
let payment_id_opt = Some(payment_id);
61866195
write_tlv_fields!(writer, {
@@ -6190,6 +6199,7 @@ impl Writeable for HTLCSource {
61906199
(3, payment_secret, option),
61916200
(4, path, vec_type),
61926201
(5, payment_params, option),
6202+
(7, payment_metadata, option),
61936203
});
61946204
}
61956205
HTLCSource::PreviousHopData(ref field) => {
@@ -6244,6 +6254,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
62446254
(0, session_privs, required),
62456255
(1, pending_fee_msat, option),
62466256
(2, payment_hash, required),
6257+
(3, payment_metadata, option),
62476258
(4, payment_secret, option),
62486259
(6, total_msat, required),
62496260
(8, pending_amt_msat, required),
@@ -6706,7 +6717,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
67066717
for (_, monitor) in args.channel_monitors {
67076718
if by_id.get(&monitor.get_funding_txo().0.to_channel_id()).is_none() {
67086719
for (htlc_source, htlc) in monitor.get_pending_outbound_htlcs() {
6709-
if let HTLCSource::OutboundRoute { payment_id, session_priv, path, payment_secret, .. } = htlc_source {
6720+
if let HTLCSource::OutboundRoute { payment_id, session_priv, path, payment_secret, payment_metadata, .. } = htlc_source {
67106721
if path.is_empty() {
67116722
log_error!(args.logger, "Got an empty path for a pending payment");
67126723
return Err(DecodeError::InvalidValue);
@@ -6726,6 +6737,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
67266737
session_privs: [session_priv_bytes].iter().map(|a| *a).collect(),
67276738
payment_hash: htlc.payment_hash,
67286739
payment_secret,
6740+
payment_metadata,
67296741
pending_amt_msat: path_amt,
67306742
pending_fee_msat: Some(path_fee),
67316743
total_msat: path_amt,
@@ -7001,7 +7013,7 @@ mod tests {
70017013
// Use the utility function send_payment_along_path to send the payment with MPP data which
70027014
// indicates there are more HTLCs coming.
70037015
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.
7004-
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();
7016+
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();
70057017
check_added_monitors!(nodes[0], 1);
70067018
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
70077019
assert_eq!(events.len(), 1);
@@ -7031,7 +7043,7 @@ mod tests {
70317043
expect_payment_failed!(nodes[0], our_payment_hash, true);
70327044

70337045
// Send the second half of the original MPP payment.
7034-
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();
7046+
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();
70357047
check_added_monitors!(nodes[0], 1);
70367048
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
70377049
assert_eq!(events.len(), 1);
@@ -7225,7 +7237,7 @@ mod tests {
72257237

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

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

72767288
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

@@ -4166,7 +4166,7 @@ fn do_test_htlc_timeout(send_partial_mpp: bool) {
41664166
// indicates there are more HTLCs coming.
41674167
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.
41684168
let payment_id = PaymentId([42; 32]);
4169-
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();
4169+
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();
41704170
check_added_monitors!(nodes[0], 1);
41714171
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
41724172
assert_eq!(events.len(), 1);
@@ -6629,7 +6629,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() {
66296629
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
66306630
let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
66316631
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::signing_only(), &route.paths[0], &session_priv).unwrap();
6632-
let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3999999, &Some(our_payment_secret), cur_height, &None).unwrap();
6632+
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();
66336633
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash);
66346634

66356635
let mut msg = msgs::UpdateAddHTLC {

0 commit comments

Comments
 (0)