lightning/ln/
onion_payment.rs

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