1 //! Utilities to decode payment onions and do contextless validation of incoming payments.
3 //! Primarily features [`peel_payment_onion`], which allows the decoding of an onion statelessly
4 //! and can be used to predict whether we'd accept a payment.
6 use bitcoin::hashes::{Hash, HashEngine};
7 use bitcoin::hashes::hmac::{Hmac, HmacEngine};
8 use bitcoin::hashes::sha256::Hash as Sha256;
9 use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1};
11 use crate::blinded_path;
12 use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay};
13 use crate::chain::channelmonitor::{HTLC_FAIL_BACK_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS};
14 use crate::ln::PaymentHash;
15 use crate::ln::channelmanager::{BlindedFailure, BlindedForward, CLTV_FAR_FAR_AWAY, HTLCFailureMsg, MIN_CLTV_EXPIRY_DELTA, PendingHTLCInfo, PendingHTLCRouting};
16 use crate::ln::features::BlindedHopFeatures;
18 use crate::ln::onion_utils;
19 use crate::ln::onion_utils::{HTLCFailReason, INVALID_ONION_BLINDING};
20 use crate::sign::{NodeSigner, Recipient};
21 use crate::util::logger::Logger;
23 use crate::prelude::*;
26 /// Invalid inbound onion payment.
28 pub struct InboundHTLCErr {
29 /// BOLT 4 error code.
31 /// Data attached to this error.
32 pub err_data: Vec<u8>,
33 /// Error message text.
34 pub msg: &'static str,
37 fn check_blinded_payment_constraints(
38 amt_msat: u64, cltv_expiry: u32, constraints: &PaymentConstraints
40 if amt_msat < constraints.htlc_minimum_msat ||
41 cltv_expiry > constraints.max_cltv_expiry
46 fn check_blinded_forward(
47 inbound_amt_msat: u64, inbound_cltv_expiry: u32, payment_relay: &PaymentRelay,
48 payment_constraints: &PaymentConstraints, features: &BlindedHopFeatures
49 ) -> Result<(u64, u32), ()> {
50 let amt_to_forward = blinded_path::payment::amt_to_forward_msat(
51 inbound_amt_msat, payment_relay
53 let outgoing_cltv_value = inbound_cltv_expiry.checked_sub(
54 payment_relay.cltv_expiry_delta as u32
56 check_blinded_payment_constraints(inbound_amt_msat, outgoing_cltv_value, payment_constraints)?;
58 if features.requires_unknown_bits_from(&BlindedHopFeatures::empty()) { return Err(()) }
59 Ok((amt_to_forward, outgoing_cltv_value))
62 pub(super) fn create_fwd_pending_htlc_info(
63 msg: &msgs::UpdateAddHTLC, hop_data: msgs::InboundOnionPayload, hop_hmac: [u8; 32],
64 new_packet_bytes: [u8; onion_utils::ONION_DATA_LEN], shared_secret: [u8; 32],
65 next_packet_pubkey_opt: Option<Result<PublicKey, secp256k1::Error>>
66 ) -> Result<PendingHTLCInfo, InboundHTLCErr> {
67 debug_assert!(next_packet_pubkey_opt.is_some());
68 let outgoing_packet = msgs::OnionPacket {
70 public_key: next_packet_pubkey_opt.unwrap_or(Err(secp256k1::Error::InvalidPublicKey)),
71 hop_data: new_packet_bytes,
76 short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point
78 msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } =>
79 (short_channel_id, amt_to_forward, outgoing_cltv_value, None),
80 msgs::InboundOnionPayload::BlindedForward {
81 short_channel_id, payment_relay, payment_constraints, intro_node_blinding_point, features,
83 let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward(
84 msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
86 // We should be returning malformed here if `msg.blinding_point` is set, but this is
87 // unreachable right now since we checked it in `decode_update_add_htlc_onion`.
89 msg: "Underflow calculating outbound amount or cltv value for blinded forward",
90 err_code: INVALID_ONION_BLINDING,
91 err_data: vec![0; 32],
94 (short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point)
96 msgs::InboundOnionPayload::Receive { .. } | msgs::InboundOnionPayload::BlindedReceive { .. } =>
97 return Err(InboundHTLCErr {
98 msg: "Final Node OnionHopData provided for us as an intermediary node",
99 err_code: 0x4000 | 22,
100 err_data: Vec::new(),
105 routing: PendingHTLCRouting::Forward {
106 onion_packet: outgoing_packet,
108 blinded: intro_node_blinding_point.or(msg.blinding_point)
109 .map(|bp| BlindedForward {
110 inbound_blinding_point: bp,
111 failure: intro_node_blinding_point
112 .map(|_| BlindedFailure::FromIntroductionNode)
113 .unwrap_or(BlindedFailure::FromBlindedNode),
116 payment_hash: msg.payment_hash,
117 incoming_shared_secret: shared_secret,
118 incoming_amt_msat: Some(msg.amount_msat),
119 outgoing_amt_msat: amt_to_forward,
121 skimmed_fee_msat: None,
125 pub(super) fn create_recv_pending_htlc_info(
126 hop_data: msgs::InboundOnionPayload, shared_secret: [u8; 32], payment_hash: PaymentHash,
127 amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>, allow_underpay: bool,
128 counterparty_skimmed_fee_msat: Option<u64>, current_height: u32, accept_mpp_keysend: bool,
129 ) -> Result<PendingHTLCInfo, InboundHTLCErr> {
131 payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, onion_cltv_expiry,
132 payment_metadata, requires_blinded_error
134 msgs::InboundOnionPayload::Receive {
135 payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
136 cltv_expiry_height, payment_metadata, ..
138 (payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
139 cltv_expiry_height, payment_metadata, false),
140 msgs::InboundOnionPayload::BlindedReceive {
141 sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
142 intro_node_blinding_point, payment_constraints, keysend_preimage, ..
144 check_blinded_payment_constraints(
145 sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints
149 err_code: INVALID_ONION_BLINDING,
150 err_data: vec![0; 32],
151 msg: "Amount or cltv_expiry violated blinded payment constraints",
154 let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
155 (Some(payment_data), keysend_preimage, Vec::new(),
156 sender_intended_htlc_amt_msat, cltv_expiry_height, None,
157 intro_node_blinding_point.is_none())
159 msgs::InboundOnionPayload::Forward { .. } => {
160 return Err(InboundHTLCErr {
162 err_data: Vec::new(),
163 msg: "Got non final data with an HMAC of 0",
166 msgs::InboundOnionPayload::BlindedForward { .. } => {
167 return Err(InboundHTLCErr {
168 err_code: INVALID_ONION_BLINDING,
169 err_data: vec![0; 32],
170 msg: "Got blinded non final data with an HMAC of 0",
174 // final_incorrect_cltv_expiry
175 if onion_cltv_expiry > cltv_expiry {
176 return Err(InboundHTLCErr {
177 msg: "Upstream node set CLTV to less than the CLTV set by the sender",
179 err_data: cltv_expiry.to_be_bytes().to_vec()
182 // final_expiry_too_soon
183 // We have to have some headroom to broadcast on chain if we have the preimage, so make sure
184 // we have at least HTLC_FAIL_BACK_BUFFER blocks to go.
186 // Also, ensure that, in the case of an unknown preimage for the received payment hash, our
187 // payment logic has enough time to fail the HTLC backward before our onchain logic triggers a
188 // channel closure (see HTLC_FAIL_BACK_BUFFER rationale).
189 if cltv_expiry <= current_height + HTLC_FAIL_BACK_BUFFER + 1 {
190 let mut err_data = Vec::with_capacity(12);
191 err_data.extend_from_slice(&amt_msat.to_be_bytes());
192 err_data.extend_from_slice(¤t_height.to_be_bytes());
193 return Err(InboundHTLCErr {
194 err_code: 0x4000 | 15, err_data,
195 msg: "The final CLTV expiry is too soon to handle",
198 if (!allow_underpay && onion_amt_msat > amt_msat) ||
199 (allow_underpay && onion_amt_msat >
200 amt_msat.saturating_add(counterparty_skimmed_fee_msat.unwrap_or(0)))
202 return Err(InboundHTLCErr {
204 err_data: amt_msat.to_be_bytes().to_vec(),
205 msg: "Upstream node sent less than we were supposed to receive in payment",
209 let routing = if let Some(payment_preimage) = keysend_preimage {
210 // We need to check that the sender knows the keysend preimage before processing this
211 // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X
212 // could discover the final destination of X, by probing the adjacent nodes on the route
213 // with a keysend payment of identical payment hash to X and observing the processing
214 // time discrepancies due to a hash collision with X.
215 let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array());
216 if hashed_preimage != payment_hash {
217 return Err(InboundHTLCErr {
219 err_data: Vec::new(),
220 msg: "Payment preimage didn't match payment hash",
223 if !accept_mpp_keysend && payment_data.is_some() {
224 return Err(InboundHTLCErr {
226 err_data: Vec::new(),
227 msg: "We don't support MPP keysend payments",
230 PendingHTLCRouting::ReceiveKeysend {
234 incoming_cltv_expiry: onion_cltv_expiry,
236 requires_blinded_error,
238 } else if let Some(data) = payment_data {
239 PendingHTLCRouting::Receive {
242 incoming_cltv_expiry: onion_cltv_expiry,
243 phantom_shared_secret,
245 requires_blinded_error,
248 return Err(InboundHTLCErr {
249 err_code: 0x4000|0x2000|3,
250 err_data: Vec::new(),
251 msg: "We require payment_secrets",
257 incoming_shared_secret: shared_secret,
258 incoming_amt_msat: Some(amt_msat),
259 outgoing_amt_msat: onion_amt_msat,
260 outgoing_cltv_value: onion_cltv_expiry,
261 skimmed_fee_msat: counterparty_skimmed_fee_msat,
265 /// Peel one layer off an incoming onion, returning a [`PendingHTLCInfo`] that contains information
266 /// about the intended next-hop for the HTLC.
268 /// This does all the relevant context-free checks that LDK requires for payment relay or
269 /// acceptance. If the payment is to be received, and the amount matches the expected amount for
270 /// a given invoice, this indicates the [`msgs::UpdateAddHTLC`], once fully committed in the
271 /// channel, will generate an [`Event::PaymentClaimable`].
273 /// [`Event::PaymentClaimable`]: crate::events::Event::PaymentClaimable
274 pub fn peel_payment_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
275 msg: &msgs::UpdateAddHTLC, node_signer: &NS, logger: &L, secp_ctx: &Secp256k1<T>,
276 cur_height: u32, accept_mpp_keysend: bool, allow_skimmed_fees: bool,
277 ) -> Result<PendingHTLCInfo, InboundHTLCErr>
279 NS::Target: NodeSigner,
282 let (hop, shared_secret, next_packet_details_opt) =
283 decode_incoming_update_add_htlc_onion(msg, node_signer, logger, secp_ctx
285 let (err_code, err_data) = match e {
286 HTLCFailureMsg::Malformed(m) => (m.failure_code, Vec::new()),
287 HTLCFailureMsg::Relay(r) => (0x4000 | 22, r.reason.data),
289 let msg = "Failed to decode update add htlc onion";
290 InboundHTLCErr { msg, err_code, err_data }
293 onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => {
294 let NextPacketDetails {
295 next_packet_pubkey, outgoing_amt_msat: _, outgoing_scid: _, outgoing_cltv_value
296 } = match next_packet_details_opt {
297 Some(next_packet_details) => next_packet_details,
298 // Forward should always include the next hop details
299 None => return Err(InboundHTLCErr {
300 msg: "Failed to decode update add htlc onion",
301 err_code: 0x4000 | 22,
302 err_data: Vec::new(),
306 if let Err((err_msg, code)) = check_incoming_htlc_cltv(
307 cur_height, outgoing_cltv_value, msg.cltv_expiry
309 return Err(InboundHTLCErr {
312 err_data: Vec::new(),
316 // TODO: If this is potentially a phantom payment we should decode the phantom payment
317 // onion here and check it.
319 create_fwd_pending_htlc_info(
320 msg, next_hop_data, next_hop_hmac, new_packet_bytes, shared_secret,
321 Some(next_packet_pubkey)
324 onion_utils::Hop::Receive(received_data) => {
325 create_recv_pending_htlc_info(
326 received_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry,
327 None, allow_skimmed_fees, msg.skimmed_fee_msat, cur_height, accept_mpp_keysend,
333 pub(super) struct NextPacketDetails {
334 pub(super) next_packet_pubkey: Result<PublicKey, secp256k1::Error>,
335 pub(super) outgoing_scid: u64,
336 pub(super) outgoing_amt_msat: u64,
337 pub(super) outgoing_cltv_value: u32,
340 pub(super) fn decode_incoming_update_add_htlc_onion<NS: Deref, L: Deref, T: secp256k1::Verification>(
341 msg: &msgs::UpdateAddHTLC, node_signer: &NS, logger: &L, secp_ctx: &Secp256k1<T>,
342 ) -> Result<(onion_utils::Hop, [u8; 32], Option<NextPacketDetails>), HTLCFailureMsg>
344 NS::Target: NodeSigner,
347 macro_rules! return_malformed_err {
348 ($msg: expr, $err_code: expr) => {
350 log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg);
351 let (sha256_of_onion, failure_code) = if msg.blinding_point.is_some() {
352 ([0; 32], INVALID_ONION_BLINDING)
354 (Sha256::hash(&msg.onion_routing_packet.hop_data).to_byte_array(), $err_code)
356 return Err(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
357 channel_id: msg.channel_id,
358 htlc_id: msg.htlc_id,
366 if let Err(_) = msg.onion_routing_packet.public_key {
367 return_malformed_err!("invalid ephemeral pubkey", 0x8000 | 0x4000 | 6);
370 let blinded_node_id_tweak = msg.blinding_point.map(|bp| {
371 let blinded_tlvs_ss = node_signer.ecdh(Recipient::Node, &bp, None).unwrap().secret_bytes();
372 let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
373 hmac.input(blinded_tlvs_ss.as_ref());
374 Scalar::from_be_bytes(Hmac::from_engine(hmac).to_byte_array()).unwrap()
376 let shared_secret = node_signer.ecdh(
377 Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), blinded_node_id_tweak.as_ref()
378 ).unwrap().secret_bytes();
380 if msg.onion_routing_packet.version != 0 {
381 //TODO: Spec doesn't indicate if we should only hash hop_data here (and in other
382 //sha256_of_onion error data packets), or the entire onion_routing_packet. Either way,
383 //the hash doesn't really serve any purpose - in the case of hashing all data, the
384 //receiving node would have to brute force to figure out which version was put in the
385 //packet by the node that send us the message, in the case of hashing the hop_data, the
386 //node knows the HMAC matched, so they already know what is there...
387 return_malformed_err!("Unknown onion packet version", 0x8000 | 0x4000 | 4);
389 macro_rules! return_err {
390 ($msg: expr, $err_code: expr, $data: expr) => {
392 if msg.blinding_point.is_some() {
393 return_malformed_err!($msg, INVALID_ONION_BLINDING)
396 log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg);
397 return Err(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
398 channel_id: msg.channel_id,
399 htlc_id: msg.htlc_id,
400 reason: HTLCFailReason::reason($err_code, $data.to_vec())
401 .get_encrypted_failure_packet(&shared_secret, &None),
407 let next_hop = match onion_utils::decode_next_payment_hop(
408 shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
409 msg.payment_hash, msg.blinding_point, node_signer
412 Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
413 return_malformed_err!(err_msg, err_code);
415 Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => {
416 return_err!(err_msg, err_code, &[0; 0]);
420 let next_packet_details = match next_hop {
421 onion_utils::Hop::Forward {
422 next_hop_data: msgs::InboundOnionPayload::Forward {
423 short_channel_id, amt_to_forward, outgoing_cltv_value
426 let next_packet_pubkey = onion_utils::next_hop_pubkey(secp_ctx,
427 msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
429 next_packet_pubkey, outgoing_scid: short_channel_id,
430 outgoing_amt_msat: amt_to_forward, outgoing_cltv_value
433 onion_utils::Hop::Forward {
434 next_hop_data: msgs::InboundOnionPayload::BlindedForward {
435 short_channel_id, ref payment_relay, ref payment_constraints, ref features, ..
438 let (amt_to_forward, outgoing_cltv_value) = match check_blinded_forward(
439 msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features
441 Ok((amt, cltv)) => (amt, cltv),
443 return_err!("Underflow calculating outbound amount or cltv value for blinded forward",
444 INVALID_ONION_BLINDING, &[0; 32]);
447 let next_packet_pubkey = onion_utils::next_hop_pubkey(&secp_ctx,
448 msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
450 next_packet_pubkey, outgoing_scid: short_channel_id, outgoing_amt_msat: amt_to_forward,
454 onion_utils::Hop::Receive { .. } => return Ok((next_hop, shared_secret, None)),
455 onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::Receive { .. }, .. } |
456 onion_utils::Hop::Forward { next_hop_data: msgs::InboundOnionPayload::BlindedReceive { .. }, .. } =>
458 return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0; 0]);
462 Ok((next_hop, shared_secret, Some(next_packet_details)))
465 pub(super) fn check_incoming_htlc_cltv(
466 cur_height: u32, outgoing_cltv_value: u32, cltv_expiry: u32
467 ) -> Result<(), (&'static str, u16)> {
468 if (cltv_expiry as u64) < (outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
470 "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta",
471 0x1000 | 13, // incorrect_cltv_expiry
474 // Theoretically, channel counterparty shouldn't send us a HTLC expiring now,
475 // but we want to be robust wrt to counterparty packet sanitization (see
476 // HTLC_FAIL_BACK_BUFFER rationale).
477 if cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon
478 return Err(("CLTV expiry is too close", 0x1000 | 14));
480 if cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far
481 return Err(("CLTV expiry is too far in the future", 21));
483 // If the HTLC expires ~now, don't bother trying to forward it to our
484 // counterparty. They should fail it anyway, but we don't want to bother with
485 // the round-trips or risk them deciding they definitely want the HTLC and
486 // force-closing to ensure they get it if we're offline.
487 // We previously had a much more aggressive check here which tried to ensure
488 // our counterparty receives an HTLC which has *our* risk threshold met on it,
489 // but there is no need to do that, and since we're a bit conservative with our
490 // risk threshold it just results in failing to forward payments.
491 if (outgoing_cltv_value) as u64 <= (cur_height + LATENCY_GRACE_PERIOD_BLOCKS) as u64 {
492 return Err(("Outgoing CLTV value is too soon", 0x1000 | 14));
500 use bitcoin::hashes::Hash;
501 use bitcoin::hashes::sha256::Hash as Sha256;
502 use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
503 use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
504 use crate::ln::ChannelId;
505 use crate::ln::channelmanager::RecipientOnionFields;
506 use crate::ln::features::{ChannelFeatures, NodeFeatures};
508 use crate::ln::onion_utils::create_payment_onion;
509 use crate::routing::router::{Path, RouteHop};
510 use crate::util::test_utils;
513 fn fail_construct_onion_on_too_big_payloads() {
514 // Ensure that if we call `construct_onion_packet` and friends where payloads are too large for
515 // the allotted packet length, we'll fail to construct. Previously, senders would happily
516 // construct invalid packets by array-shifting the final node's HMAC out of the packet when
517 // adding an intermediate onion layer, causing the receiver to error with "final payload
518 // provided for us as an intermediate node."
519 let secp_ctx = Secp256k1::new();
520 let bob = crate::sign::KeysManager::new(&[2; 32], 42, 42);
521 let bob_pk = PublicKey::from_secret_key(&secp_ctx, &bob.get_node_secret_key());
522 let charlie = crate::sign::KeysManager::new(&[3; 32], 42, 42);
523 let charlie_pk = PublicKey::from_secret_key(&secp_ctx, &charlie.get_node_secret_key());
526 session_priv, total_amt_msat, cur_height, mut recipient_onion, keysend_preimage, payment_hash,
528 ) = payment_onion_args(bob_pk, charlie_pk);
530 // Ensure the onion will not fit all the payloads by adding a large custom TLV.
531 recipient_onion.custom_tlvs.push((13377331, vec![0; 1156]));
533 let path = Path { hops, blinded_tail: None, };
534 let onion_keys = super::onion_utils::construct_onion_keys(&secp_ctx, &path, &session_priv).unwrap();
535 let (onion_payloads, ..) = super::onion_utils::build_onion_payloads(
536 &path, total_amt_msat, recipient_onion, cur_height + 1, &Some(keysend_preimage)
539 assert!(super::onion_utils::construct_onion_packet(
540 onion_payloads, onion_keys, prng_seed, &payment_hash
545 fn test_peel_payment_onion() {
547 let secp_ctx = Secp256k1::new();
549 let bob = crate::sign::KeysManager::new(&[2; 32], 42, 42);
550 let bob_pk = PublicKey::from_secret_key(&secp_ctx, &bob.get_node_secret_key());
551 let charlie = crate::sign::KeysManager::new(&[3; 32], 42, 42);
552 let charlie_pk = PublicKey::from_secret_key(&secp_ctx, &charlie.get_node_secret_key());
554 let (session_priv, total_amt_msat, cur_height, recipient_onion, preimage, payment_hash,
555 prng_seed, hops, recipient_amount, pay_secret) = payment_onion_args(bob_pk, charlie_pk);
562 let (onion, amount_msat, cltv_expiry) = create_payment_onion(
563 &secp_ctx, &path, &session_priv, total_amt_msat, recipient_onion, cur_height,
564 &payment_hash, &Some(preimage), prng_seed
567 let msg = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, onion);
568 let logger = test_utils::TestLogger::with_id("bob".to_string());
570 let peeled = peel_payment_onion(&msg, &&bob, &&logger, &secp_ctx, cur_height, true, false)
571 .map_err(|e| e.msg).unwrap();
573 let next_onion = match peeled.routing {
574 PendingHTLCRouting::Forward { onion_packet, .. } => {
577 _ => panic!("expected a forwarded onion"),
580 let msg2 = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, next_onion);
581 let peeled2 = peel_payment_onion(&msg2, &&charlie, &&logger, &secp_ctx, cur_height, true, false)
582 .map_err(|e| e.msg).unwrap();
584 match peeled2.routing {
585 PendingHTLCRouting::ReceiveKeysend { payment_preimage, payment_data, incoming_cltv_expiry, .. } => {
586 assert_eq!(payment_preimage, preimage);
587 assert_eq!(peeled2.outgoing_amt_msat, recipient_amount);
588 assert_eq!(incoming_cltv_expiry, peeled2.outgoing_cltv_value);
589 let msgs::FinalOnionHopData{total_msat, payment_secret} = payment_data.unwrap();
590 assert_eq!(total_msat, total_amt_msat);
591 assert_eq!(payment_secret, pay_secret);
593 _ => panic!("expected a received keysend"),
597 fn make_update_add_msg(
598 amount_msat: u64, cltv_expiry: u32, payment_hash: PaymentHash,
599 onion_routing_packet: msgs::OnionPacket
600 ) -> msgs::UpdateAddHTLC {
601 msgs::UpdateAddHTLC {
602 channel_id: ChannelId::from_bytes([0; 32]),
607 onion_routing_packet,
608 skimmed_fee_msat: None,
609 blinding_point: None,
613 fn payment_onion_args(hop_pk: PublicKey, recipient_pk: PublicKey) -> (
614 SecretKey, u64, u32, RecipientOnionFields, PaymentPreimage, PaymentHash, [u8; 32],
615 Vec<RouteHop>, u64, PaymentSecret,
617 let session_priv_bytes = [42; 32];
618 let session_priv = SecretKey::from_slice(&session_priv_bytes).unwrap();
619 let total_amt_msat = 1000;
620 let cur_height = 1000;
621 let pay_secret = PaymentSecret([99; 32]);
622 let recipient_onion = RecipientOnionFields::secret_only(pay_secret);
623 let preimage_bytes = [43; 32];
624 let preimage = PaymentPreimage(preimage_bytes);
625 let rhash_bytes = Sha256::hash(&preimage_bytes).to_byte_array();
626 let payment_hash = PaymentHash(rhash_bytes);
627 let prng_seed = [44; 32];
629 // make a route alice -> bob -> charlie
631 let recipient_amount = total_amt_msat - hop_fee;
636 cltv_expiry_delta: 42,
638 node_features: NodeFeatures::empty(),
639 channel_features: ChannelFeatures::empty(),
640 maybe_announced_channel: false,
643 pubkey: recipient_pk,
644 fee_msat: recipient_amount,
645 cltv_expiry_delta: 42,
647 node_features: NodeFeatures::empty(),
648 channel_features: ChannelFeatures::empty(),
649 maybe_announced_channel: false,
653 (session_priv, total_amt_msat, cur_height, recipient_onion, preimage, payment_hash,
654 prng_seed, hops, recipient_amount, pay_secret)