Merge pull request #2753 from TheBlueMatt/2023-11-inbound-preimages
[rust-lightning] / lightning / src / ln / onion_payment.rs
1 //! Utilities for channelmanager.rs
2 //!
3 //! Includes a public [`peel_payment_onion`] function for use by external projects or libraries.
4
5 use bitcoin::hashes::Hash;
6 use bitcoin::hashes::sha256::Hash as Sha256;
7 use bitcoin::secp256k1::{self, Secp256k1, PublicKey};
8
9 use crate::blinded_path;
10 use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay};
11 use crate::chain::channelmonitor::{HTLC_FAIL_BACK_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
12 use crate::ln::PaymentHash;
13 use crate::ln::channelmanager::{BlindedForward, CLTV_FAR_FAR_AWAY, HTLCFailureMsg, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
14 use crate::ln::features::BlindedHopFeatures;
15 use crate::ln::msgs;
16 use crate::ln::onion_utils;
17 use crate::ln::onion_utils::{HTLCFailReason, INVALID_ONION_BLINDING};
18 use crate::sign::{NodeSigner, Recipient};
19 use crate::util::logger::Logger;
20
21 use crate::prelude::*;
22 use core::ops::Deref;
23
24 /// Invalid inbound onion payment.
25 pub struct InboundOnionErr {
26         /// BOLT 4 error code.
27         pub err_code: u16,
28         /// Data attached to this error.
29         pub err_data: Vec<u8>,
30         /// Error message text.
31         pub msg: &'static str,
32 }
33
34 fn check_blinded_forward(
35         inbound_amt_msat: u64, inbound_cltv_expiry: u32, payment_relay: &PaymentRelay,
36         payment_constraints: &PaymentConstraints, features: &BlindedHopFeatures
37 ) -> Result<(u64, u32), ()> {
38         let amt_to_forward = blinded_path::payment::amt_to_forward_msat(
39                 inbound_amt_msat, payment_relay
40         ).ok_or(())?;
41         let outgoing_cltv_value = inbound_cltv_expiry.checked_sub(
42                 payment_relay.cltv_expiry_delta as u32
43         ).ok_or(())?;
44         if inbound_amt_msat < payment_constraints.htlc_minimum_msat ||
45                 outgoing_cltv_value > payment_constraints.max_cltv_expiry
46                 { return Err(()) }
47         if features.requires_unknown_bits_from(&BlindedHopFeatures::empty()) { return Err(()) }
48         Ok((amt_to_forward, outgoing_cltv_value))
49 }
50
51 pub(super) fn create_fwd_pending_htlc_info(
52         msg: &msgs::UpdateAddHTLC, hop_data: msgs::InboundOnionPayload, hop_hmac: [u8; 32],
53         new_packet_bytes: [u8; onion_utils::ONION_DATA_LEN], shared_secret: [u8; 32],
54         next_packet_pubkey_opt: Option<Result<PublicKey, secp256k1::Error>>
55 ) -> Result<PendingHTLCInfo, InboundOnionErr> {
56         debug_assert!(next_packet_pubkey_opt.is_some());
57         let outgoing_packet = msgs::OnionPacket {
58                 version: 0,
59                 public_key: next_packet_pubkey_opt.unwrap_or(Err(secp256k1::Error::InvalidPublicKey)),
60                 hop_data: new_packet_bytes,
61                 hmac: hop_hmac,
62         };
63
64         let (
65                 short_channel_id, amt_to_forward, outgoing_cltv_value, inbound_blinding_point
66         ) = match hop_data {
67                 msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } =>
68                         (short_channel_id, amt_to_forward, outgoing_cltv_value, None),
69                 msgs::InboundOnionPayload::BlindedForward {
70                         short_channel_id, payment_relay, payment_constraints, intro_node_blinding_point, features,
71                 } => {
72                         let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
73                                 msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
74                         ).map_err(|()| {
75                                 // We should be returning malformed here if `msg.blinding_point` is set, but this is
76                                 // unreachable right now since we checked it in `decode_update_add_htlc_onion`.
77                                 InboundOnionErr {
78                                         msg: "Underflow calculating outbound amount or cltv value for blinded forward",
79                                         err_code: INVALID_ONION_BLINDING,
80                                         err_data: vec![0; 32],
81                                 }
82                         })?;
83                         (short_channel_id, amt_to_forward, outgoing_cltv_value, Some(intro_node_blinding_point))
84                 },
85                 msgs::InboundOnionPayload::Receive { .. } | msgs::InboundOnionPayload::BlindedReceive { .. } =>
86                         return Err(InboundOnionErr {
87                                 msg: "Final Node OnionHopData provided for us as an intermediary node",
88                                 err_code: 0x4000 | 22,
89                                 err_data: Vec::new(),
90                         }),
91         };
92
93         Ok(PendingHTLCInfo {
94                 routing: PendingHTLCRouting::Forward {
95                         onion_packet: outgoing_packet,
96                         short_channel_id,
97                         blinded: inbound_blinding_point.map(|bp| BlindedForward { inbound_blinding_point: bp }),
98                 },
99                 payment_hash: msg.payment_hash,
100                 incoming_shared_secret: shared_secret,
101                 incoming_amt_msat: Some(msg.amount_msat),
102                 outgoing_amt_msat: amt_to_forward,
103                 outgoing_cltv_value,
104                 skimmed_fee_msat: None,
105         })
106 }
107
108 pub(super) fn create_recv_pending_htlc_info(
109         hop_data: msgs::InboundOnionPayload, shared_secret: [u8; 32], payment_hash: PaymentHash,
110         amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>, allow_underpay: bool,
111         counterparty_skimmed_fee_msat: Option<u64>, current_height: u32, accept_mpp_keysend: bool,
112 ) -> Result<PendingHTLCInfo, InboundOnionErr> {
113         let (payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, outgoing_cltv_value, payment_metadata) = match hop_data {
114                 msgs::InboundOnionPayload::Receive {
115                         payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata, ..
116                 } =>
117                         (payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata),
118                 msgs::InboundOnionPayload::BlindedReceive {
119                         amt_msat, total_msat, outgoing_cltv_value, payment_secret, ..
120                 } => {
121                         let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
122                         (Some(payment_data), None, Vec::new(), amt_msat, outgoing_cltv_value, None)
123                 }
124                 msgs::InboundOnionPayload::Forward { .. } => {
125                         return Err(InboundOnionErr {
126                                 err_code: 0x4000|22,
127                                 err_data: Vec::new(),
128                                 msg: "Got non final data with an HMAC of 0",
129                         })
130                 },
131                 msgs::InboundOnionPayload::BlindedForward { .. } => {
132                         return Err(InboundOnionErr {
133                                 err_code: INVALID_ONION_BLINDING,
134                                 err_data: vec![0; 32],
135                                 msg: "Got blinded non final data with an HMAC of 0",
136                         })
137                 }
138         };
139         // final_incorrect_cltv_expiry
140         if outgoing_cltv_value > cltv_expiry {
141                 return Err(InboundOnionErr {
142                         msg: "Upstream node set CLTV to less than the CLTV set by the sender",
143                         err_code: 18,
144                         err_data: cltv_expiry.to_be_bytes().to_vec()
145                 })
146         }
147         // final_expiry_too_soon
148         // We have to have some headroom to broadcast on chain if we have the preimage, so make sure
149         // we have at least HTLC_FAIL_BACK_BUFFER blocks to go.
150         //
151         // Also, ensure that, in the case of an unknown preimage for the received payment hash, our
152         // payment logic has enough time to fail the HTLC backward before our onchain logic triggers a
153         // channel closure (see HTLC_FAIL_BACK_BUFFER rationale).
154         if cltv_expiry <= current_height + HTLC_FAIL_BACK_BUFFER + 1 {
155                 let mut err_data = Vec::with_capacity(12);
156                 err_data.extend_from_slice(&amt_msat.to_be_bytes());
157                 err_data.extend_from_slice(&current_height.to_be_bytes());
158                 return Err(InboundOnionErr {
159                         err_code: 0x4000 | 15, err_data,
160                         msg: "The final CLTV expiry is too soon to handle",
161                 });
162         }
163         if (!allow_underpay && onion_amt_msat > amt_msat) ||
164                 (allow_underpay && onion_amt_msat >
165                  amt_msat.saturating_add(counterparty_skimmed_fee_msat.unwrap_or(0)))
166         {
167                 return Err(InboundOnionErr {
168                         err_code: 19,
169                         err_data: amt_msat.to_be_bytes().to_vec(),
170                         msg: "Upstream node sent less than we were supposed to receive in payment",
171                 });
172         }
173
174         let routing = if let Some(payment_preimage) = keysend_preimage {
175                 // We need to check that the sender knows the keysend preimage before processing this
176                 // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X
177                 // could discover the final destination of X, by probing the adjacent nodes on the route
178                 // with a keysend payment of identical payment hash to X and observing the processing
179                 // time discrepancies due to a hash collision with X.
180                 let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array());
181                 if hashed_preimage != payment_hash {
182                         return Err(InboundOnionErr {
183                                 err_code: 0x4000|22,
184                                 err_data: Vec::new(),
185                                 msg: "Payment preimage didn't match payment hash",
186                         });
187                 }
188                 if !accept_mpp_keysend && payment_data.is_some() {
189                         return Err(InboundOnionErr {
190                                 err_code: 0x4000|22,
191                                 err_data: Vec::new(),
192                                 msg: "We don't support MPP keysend payments",
193                         });
194                 }
195                 PendingHTLCRouting::ReceiveKeysend {
196                         payment_data,
197                         payment_preimage,
198                         payment_metadata,
199                         incoming_cltv_expiry: outgoing_cltv_value,
200                         custom_tlvs,
201                 }
202         } else if let Some(data) = payment_data {
203                 PendingHTLCRouting::Receive {
204                         payment_data: data,
205                         payment_metadata,
206                         incoming_cltv_expiry: outgoing_cltv_value,
207                         phantom_shared_secret,
208                         custom_tlvs,
209                 }
210         } else {
211                 return Err(InboundOnionErr {
212                         err_code: 0x4000|0x2000|3,
213                         err_data: Vec::new(),
214                         msg: "We require payment_secrets",
215                 });
216         };
217         Ok(PendingHTLCInfo {
218                 routing,
219                 payment_hash,
220                 incoming_shared_secret: shared_secret,
221                 incoming_amt_msat: Some(amt_msat),
222                 outgoing_amt_msat: onion_amt_msat,
223                 outgoing_cltv_value,
224                 skimmed_fee_msat: counterparty_skimmed_fee_msat,
225         })
226 }
227
228 /// Peel one layer off an incoming onion, returning [`PendingHTLCInfo`] (either Forward or Receive).
229 /// This does all the relevant context-free checks that LDK requires for payment relay or
230 /// acceptance. If the payment is to be received, and the amount matches the expected amount for
231 /// a given invoice, this indicates the [`msgs::UpdateAddHTLC`], once fully committed in the
232 /// channel, will generate an [`Event::PaymentClaimable`].
233 ///
234 /// [`Event::PaymentClaimable`]: crate::events::Event::PaymentClaimable
235 pub fn peel_payment_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
236         msg: &msgs::UpdateAddHTLC, node_signer: &NS, logger: &L, secp_ctx: &Secp256k1<T>,
237         cur_height: u32, accept_mpp_keysend: bool,
238 ) -> Result<PendingHTLCInfo, InboundOnionErr>
239 where
240         NS::Target: NodeSigner,
241         L::Target: Logger,
242 {
243         let (hop, shared_secret, next_packet_details_opt) =
244                 decode_incoming_update_add_htlc_onion(msg, node_signer, logger, secp_ctx
245         ).map_err(|e| {
246                 let (err_code, err_data) = match e {
247                         HTLCFailureMsg::Malformed(m) => (m.failure_code, Vec::new()),
248                         HTLCFailureMsg::Relay(r) => (0x4000 | 22, r.reason.data),
249                 };
250                 let msg = "Failed to decode update add htlc onion";
251                 InboundOnionErr { msg, err_code, err_data }
252         })?;
253         Ok(match hop {
254                 onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
255                         let NextPacketDetails {
256                                 next_packet_pubkey, outgoing_amt_msat: _, outgoing_scid: _, outgoing_cltv_value
257                         } = match next_packet_details_opt {
258                                 Some(next_packet_details) => next_packet_details,
259                                 // Forward should always include the next hop details
260                                 None => return Err(InboundOnionErr {
261                                         msg: "Failed to decode update add htlc onion",
262                                         err_code: 0x4000 | 22,
263                                         err_data: Vec::new(),
264                                 }),
265                         };
266
267                         if let Err((err_msg, code)) = check_incoming_htlc_cltv(
268                                 cur_height, outgoing_cltv_value, msg.cltv_expiry
269                         ) {
270                                 return Err(InboundOnionErr {
271                                         msg: err_msg,
272                                         err_code: code,
273                                         err_data: Vec::new(),
274                                 });
275                         }
276                         create_fwd_pending_htlc_info(
277                                 msg, next_hop_data, next_hop_hmac, new_packet_bytes, shared_secret,
278                                 Some(next_packet_pubkey)
279                         )?
280                 },
281                 onion_utils::Hop::Receive(received_data) => {
282                         create_recv_pending_htlc_info(
283                                 received_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry,
284                                 None, false, msg.skimmed_fee_msat, cur_height, accept_mpp_keysend,
285                         )?
286                 }
287         })
288 }
289
290 pub(super) struct NextPacketDetails {
291         pub(super) next_packet_pubkey: Result<PublicKey, secp256k1::Error>,
292         pub(super) outgoing_scid: u64,
293         pub(super) outgoing_amt_msat: u64,
294         pub(super) outgoing_cltv_value: u32,
295 }
296
297 pub(super) fn decode_incoming_update_add_htlc_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
298         msg: &msgs::UpdateAddHTLC, node_signer: &NS, logger: &L, secp_ctx: &Secp256k1<T>,
299 ) -> Result<(onion_utils::Hop, [u8; 32], Option<NextPacketDetails>), HTLCFailureMsg>
300 where
301         NS::Target: NodeSigner,
302         L::Target: Logger,
303 {
304         macro_rules! return_malformed_err {
305                 ($msg: expr, $err_code: expr) => {
306                         {
307                                 log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg);
308                                 return Err(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
309                                         channel_id: msg.channel_id,
310                                         htlc_id: msg.htlc_id,
311                                         sha256_of_onion: Sha256::hash(&msg.onion_routing_packet.hop_data).to_byte_array(),
312                                         failure_code: $err_code,
313                                 }));
314                         }
315                 }
316         }
317
318         if let Err(_) = msg.onion_routing_packet.public_key {
319                 return_malformed_err!("invalid ephemeral pubkey", 0x8000 | 0x4000 | 6);
320         }
321
322         let shared_secret = node_signer.ecdh(
323                 Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), None
324         ).unwrap().secret_bytes();
325
326         if msg.onion_routing_packet.version != 0 {
327                 //TODO: Spec doesn't indicate if we should only hash hop_data here (and in other
328                 //sha256_of_onion error data packets), or the entire onion_routing_packet. Either way,
329                 //the hash doesn't really serve any purpose - in the case of hashing all data, the
330                 //receiving node would have to brute force to figure out which version was put in the
331                 //packet by the node that send us the message, in the case of hashing the hop_data, the
332                 //node knows the HMAC matched, so they already know what is there...
333                 return_malformed_err!("Unknown onion packet version", 0x8000 | 0x4000 | 4);
334         }
335         macro_rules! return_err {
336                 ($msg: expr, $err_code: expr, $data: expr) => {
337                         {
338                                 log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg);
339                                 return Err(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
340                                         channel_id: msg.channel_id,
341                                         htlc_id: msg.htlc_id,
342                                         reason: HTLCFailReason::reason($err_code, $data.to_vec())
343                                                 .get_encrypted_failure_packet(&shared_secret, &None),
344                                 }));
345                         }
346                 }
347         }
348
349         let next_hop = match onion_utils::decode_next_payment_hop(
350                 shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
351                 msg.payment_hash, node_signer
352         ) {
353                 Ok(res) => res,
354                 Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
355                         return_malformed_err!(err_msg, err_code);
356                 },
357                 Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => {
358                         return_err!(err_msg, err_code, &[0; 0]);
359                 },
360         };
361
362         let next_packet_details = match next_hop {
363                 onion_utils::Hop::Forward {
364                         next_hop_data: msgs::InboundOnionPayload::Forward {
365                                 short_channel_id, amt_to_forward, outgoing_cltv_value
366                         }, ..
367                 } => {
368                         let next_packet_pubkey = onion_utils::next_hop_pubkey(secp_ctx,
369                                 msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
370                         NextPacketDetails {
371                                 next_packet_pubkey, outgoing_scid: short_channel_id,
372                                 outgoing_amt_msat: amt_to_forward, outgoing_cltv_value
373                         }
374                 },
375                 onion_utils::Hop::Forward {
376                         next_hop_data: msgs::InboundOnionPayload::BlindedForward {
377                                 short_channel_id, ref payment_relay, ref payment_constraints, ref features, ..
378                         }, ..
379                 } => {
380                         let (amt_to_forward, outgoing_cltv_value) = match check_blinded_forward(
381                                 msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
382                         ) {
383                                 Ok((amt, cltv)) => (amt, cltv),
384                                 Err(()) => {
385                                         return_err!("Underflow calculating outbound amount or cltv value for blinded forward",
386                                                 INVALID_ONION_BLINDING, &[0; 32]);
387                                 }
388                         };
389                         let next_packet_pubkey = onion_utils::next_hop_pubkey(&secp_ctx,
390                                 msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
391                         NextPacketDetails {
392                                 next_packet_pubkey, outgoing_scid: short_channel_id, outgoing_amt_msat: amt_to_forward,
393                                 outgoing_cltv_value
394                         }
395                 },
396                 onion_utils::Hop::Receive { .. } => return Ok((next_hop, shared_secret, None)),
397                 onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::Receive { .. }, .. } |
398                         onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::BlindedReceive { .. }, .. } =>
399                 {
400                         return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0; 0]);
401                 }
402         };
403
404         Ok((next_hop, shared_secret, Some(next_packet_details)))
405 }
406
407 pub(super) fn check_incoming_htlc_cltv(
408         cur_height: u32, outgoing_cltv_value: u32, cltv_expiry: u32
409 ) -> Result<(), (&'static str, u16)> {
410         if (cltv_expiry as u64) < (outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
411                 return Err((
412                         "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta",
413                         0x1000 | 13, // incorrect_cltv_expiry
414                 ));
415         }
416         // Theoretically, channel counterparty shouldn't send us a HTLC expiring now,
417         // but we want to be robust wrt to counterparty packet sanitization (see
418         // HTLC_FAIL_BACK_BUFFER rationale).
419         if cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon
420                 return Err(("CLTV expiry is too close", 0x1000 | 14));
421         }
422         if cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far
423                 return Err(("CLTV expiry is too far in the future", 21));
424         }
425         // If the HTLC expires ~now, don't bother trying to forward it to our
426         // counterparty. They should fail it anyway, but we don't want to bother with
427         // the round-trips or risk them deciding they definitely want the HTLC and
428         // force-closing to ensure they get it if we're offline.
429         // We previously had a much more aggressive check here which tried to ensure
430         // our counterparty receives an HTLC which has *our* risk threshold met on it,
431         // but there is no need to do that, and since we're a bit conservative with our
432         // risk threshold it just results in failing to forward payments.
433         if (outgoing_cltv_value) as u64 <= (cur_height + LATENCY_GRACE_PERIOD_BLOCKS) as u64 {
434                 return Err(("Outgoing CLTV value is too soon", 0x1000 | 14));
435         }
436
437         Ok(())
438 }
439
440 #[cfg(test)]
441 mod tests {
442         use bitcoin::hashes::Hash;
443         use bitcoin::hashes::sha256::Hash as Sha256;
444         use bitcoin::secp256k1::{PublicKey, SecretKey};
445         use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
446         use crate::ln::ChannelId;
447         use crate::ln::channelmanager::RecipientOnionFields;
448         use crate::ln::features::{ChannelFeatures, NodeFeatures};
449         use crate::ln::msgs;
450         use crate::ln::onion_utils::create_payment_onion;
451         use crate::routing::router::{Path, RouteHop};
452         use crate::util::test_utils;
453
454         #[test]
455         fn test_peel_payment_onion() {
456                 use super::*;
457                 let secp_ctx = Secp256k1::new();
458
459                 let bob = crate::sign::KeysManager::new(&[2; 32], 42, 42);
460                 let bob_pk = PublicKey::from_secret_key(&secp_ctx, &bob.get_node_secret_key());
461                 let charlie = crate::sign::KeysManager::new(&[3; 32], 42, 42);
462                 let charlie_pk = PublicKey::from_secret_key(&secp_ctx, &charlie.get_node_secret_key());
463
464                 let (session_priv, total_amt_msat, cur_height, recipient_onion, preimage, payment_hash,
465                         prng_seed, hops, recipient_amount, pay_secret) = payment_onion_args(bob_pk, charlie_pk);
466
467                 let path = Path {
468                         hops: hops,
469                         blinded_tail: None,
470                 };
471
472                 let (onion, amount_msat, cltv_expiry) = create_payment_onion(
473                         &secp_ctx, &path, &session_priv, total_amt_msat, recipient_onion, cur_height,
474                         &payment_hash, &Some(preimage), prng_seed
475                 ).unwrap();
476
477                 let msg = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, onion);
478                 let logger = test_utils::TestLogger::with_id("bob".to_string());
479
480                 let peeled = peel_payment_onion(&msg, &&bob, &&logger, &secp_ctx, cur_height, true)
481                         .map_err(|e| e.msg).unwrap();
482
483                 let next_onion = match peeled.routing {
484                         PendingHTLCRouting::Forward { onion_packet, .. } => {
485                                 onion_packet
486                         },
487                         _ => panic!("expected a forwarded onion"),
488                 };
489
490                 let msg2 = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, next_onion);
491                 let peeled2 = peel_payment_onion(&msg2, &&charlie, &&logger, &secp_ctx, cur_height, true)
492                         .map_err(|e| e.msg).unwrap();
493
494                 match peeled2.routing {
495                         PendingHTLCRouting::ReceiveKeysend { payment_preimage, payment_data, incoming_cltv_expiry, .. } => {
496                                 assert_eq!(payment_preimage, preimage);
497                                 assert_eq!(peeled2.outgoing_amt_msat, recipient_amount);
498                                 assert_eq!(incoming_cltv_expiry, peeled2.outgoing_cltv_value);
499                                 let msgs::FinalOnionHopData{total_msat, payment_secret} = payment_data.unwrap();
500                                 assert_eq!(total_msat, total_amt_msat);
501                                 assert_eq!(payment_secret, pay_secret);
502                         },
503                         _ => panic!("expected a received keysend"),
504                 };
505         }
506
507         fn make_update_add_msg(
508                 amount_msat: u64, cltv_expiry: u32, payment_hash: PaymentHash,
509                 onion_routing_packet: msgs::OnionPacket
510         ) -> msgs::UpdateAddHTLC {
511                 msgs::UpdateAddHTLC {
512                         channel_id: ChannelId::from_bytes([0; 32]),
513                         htlc_id: 0,
514                         amount_msat,
515                         cltv_expiry,
516                         payment_hash,
517                         onion_routing_packet,
518                         skimmed_fee_msat: None,
519                         blinding_point: None,
520                 }
521         }
522
523         fn payment_onion_args(hop_pk: PublicKey, recipient_pk: PublicKey) -> (
524                 SecretKey, u64, u32, RecipientOnionFields, PaymentPreimage, PaymentHash, [u8; 32],
525                 Vec<RouteHop>, u64, PaymentSecret,
526         ) {
527                 let session_priv_bytes = [42; 32];
528                 let session_priv = SecretKey::from_slice(&session_priv_bytes).unwrap();
529                 let total_amt_msat = 1000;
530                 let cur_height = 1000;
531                 let pay_secret = PaymentSecret([99; 32]);
532                 let recipient_onion = RecipientOnionFields::secret_only(pay_secret);
533                 let preimage_bytes = [43; 32];
534                 let preimage = PaymentPreimage(preimage_bytes);
535                 let rhash_bytes = Sha256::hash(&preimage_bytes).to_byte_array();
536                 let payment_hash = PaymentHash(rhash_bytes);
537                 let prng_seed = [44; 32];
538
539                 // make a route alice -> bob -> charlie
540                 let hop_fee = 1;
541                 let recipient_amount = total_amt_msat - hop_fee;
542                 let hops = vec![
543                         RouteHop {
544                                 pubkey: hop_pk,
545                                 fee_msat: hop_fee,
546                                 cltv_expiry_delta: 42,
547                                 short_channel_id: 1,
548                                 node_features: NodeFeatures::empty(),
549                                 channel_features: ChannelFeatures::empty(),
550                                 maybe_announced_channel: false,
551                         },
552                         RouteHop {
553                                 pubkey: recipient_pk,
554                                 fee_msat: recipient_amount,
555                                 cltv_expiry_delta: 42,
556                                 short_channel_id: 2,
557                                 node_features: NodeFeatures::empty(),
558                                 channel_features: ChannelFeatures::empty(),
559                                 maybe_announced_channel: false,
560                         }
561                 ];
562
563                 (session_priv, total_amt_msat, cur_height, recipient_onion, preimage, payment_hash,
564                         prng_seed, hops, recipient_amount, pay_secret)
565         }
566
567 }