lightning/blinded_path/
payment.rs

1// This file is Copyright its original authors, visible in version control
2// history.
3//
4// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7// You may not use this file except in accordance with one or both of these
8// licenses.
9
10//! Data structures and methods for constructing [`BlindedPaymentPath`]s to send a payment over.
11
12use bitcoin::hashes::hmac::Hmac;
13use bitcoin::hashes::sha256::Hash as Sha256;
14use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
15
16use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp};
17use crate::blinded_path::utils;
18use crate::crypto::streams::ChaChaPolyReadAdapter;
19use crate::io;
20use crate::io::Cursor;
21use crate::types::payment::PaymentSecret;
22use crate::ln::channel_state::CounterpartyForwardingInfo;
23use crate::ln::channelmanager::Verification;
24use crate::types::features::BlindedHopFeatures;
25use crate::ln::inbound_payment::ExpandedKey;
26use crate::ln::msgs::DecodeError;
27use crate::ln::onion_utils;
28use crate::offers::invoice_request::InvoiceRequestFields;
29use crate::offers::nonce::Nonce;
30use crate::offers::offer::OfferId;
31use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
32use crate::sign::{EntropySource, NodeSigner, Recipient};
33use crate::types::routing::RoutingFees;
34use crate::util::ser::{FixedLengthReader, LengthReadableArgs, HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer};
35
36use core::mem;
37use core::ops::Deref;
38
39#[allow(unused_imports)]
40use crate::prelude::*;
41
42/// Information needed to route a payment across a [`BlindedPaymentPath`].
43#[derive(Clone, Debug, Hash, Eq, PartialEq)]
44pub struct BlindedPayInfo {
45	/// Base fee charged (in millisatoshi) for the entire blinded path.
46	pub fee_base_msat: u32,
47
48	/// Liquidity fee charged (in millionths of the amount transferred) for the entire blinded path
49	/// (i.e., 10,000 is 1%).
50	pub fee_proportional_millionths: u32,
51
52	/// Number of blocks subtracted from an incoming HTLC's `cltv_expiry` for the entire blinded
53	/// path.
54	pub cltv_expiry_delta: u16,
55
56	/// The minimum HTLC value (in millisatoshi) that is acceptable to all channel peers on the
57	/// blinded path from the introduction node to the recipient, accounting for any fees, i.e., as
58	/// seen by the recipient.
59	pub htlc_minimum_msat: u64,
60
61	/// The maximum HTLC value (in millisatoshi) that is acceptable to all channel peers on the
62	/// blinded path from the introduction node to the recipient, accounting for any fees, i.e., as
63	/// seen by the recipient.
64	pub htlc_maximum_msat: u64,
65
66	/// Features set in `encrypted_data_tlv` for the `encrypted_recipient_data` TLV record in an
67	/// onion payload.
68	pub features: BlindedHopFeatures,
69}
70
71impl_writeable!(BlindedPayInfo, {
72	fee_base_msat,
73	fee_proportional_millionths,
74	cltv_expiry_delta,
75	htlc_minimum_msat,
76	htlc_maximum_msat,
77	features
78});
79
80/// A blinded path to be used for sending or receiving a payment, hiding the identity of the
81/// recipient.
82#[derive(Clone, Debug, Hash, PartialEq, Eq)]
83pub struct BlindedPaymentPath {
84	pub(super) inner_path: BlindedPath,
85	/// The [`BlindedPayInfo`] used to pay this blinded path.
86	pub payinfo: BlindedPayInfo,
87}
88
89impl BlindedPaymentPath {
90	/// Create a one-hop blinded path for a payment.
91	pub fn one_hop<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
92		payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, min_final_cltv_expiry_delta: u16,
93		entropy_source: ES, secp_ctx: &Secp256k1<T>
94	) -> Result<Self, ()> where ES::Target: EntropySource {
95		// This value is not considered in pathfinding for 1-hop blinded paths, because it's intended to
96		// be in relation to a specific channel.
97		let htlc_maximum_msat = u64::max_value();
98		Self::new(
99			&[], payee_node_id, payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta,
100			entropy_source, secp_ctx
101		)
102	}
103
104	/// Create a blinded path for a payment, to be forwarded along `intermediate_nodes`.
105	///
106	/// Errors if:
107	/// * a provided node id is invalid
108	/// * [`BlindedPayInfo`] calculation results in an integer overflow
109	/// * any unknown features are required in the provided [`ForwardTlvs`]
110	//  TODO: make all payloads the same size with padding + add dummy hops
111	pub fn new<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
112		intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey,
113		payee_tlvs: ReceiveTlvs, htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16,
114		entropy_source: ES, secp_ctx: &Secp256k1<T>,
115	) -> Result<Self, ()> where ES::Target: EntropySource {
116		let introduction_node = IntroductionNode::NodeId(
117			intermediate_nodes.first().map_or(payee_node_id, |n| n.node_id)
118		);
119		let blinding_secret_bytes = entropy_source.get_secure_random_bytes();
120		let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
121
122		let blinded_payinfo = compute_payinfo(
123			intermediate_nodes, &payee_tlvs.tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta
124		)?;
125		Ok(Self {
126			inner_path: BlindedPath {
127				introduction_node,
128				blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
129				blinded_hops: blinded_hops(
130					secp_ctx, intermediate_nodes, payee_node_id, payee_tlvs, &blinding_secret
131				).map_err(|_| ())?,
132			},
133			payinfo: blinded_payinfo
134		})
135	}
136
137	/// Returns the introduction [`NodeId`] of the blinded path, if it is publicly reachable (i.e.,
138	/// it is found in the network graph).
139	pub fn public_introduction_node_id<'a>(
140		&self, network_graph: &'a ReadOnlyNetworkGraph
141	) -> Option<&'a NodeId> {
142		self.inner_path.public_introduction_node_id(network_graph)
143	}
144
145	/// The [`IntroductionNode`] of the blinded path.
146	pub fn introduction_node(&self) -> &IntroductionNode {
147		&self.inner_path.introduction_node
148	}
149
150	/// Used by the [`IntroductionNode`] to decrypt its [`encrypted_payload`] to forward the payment.
151	///
152	/// [`encrypted_payload`]: BlindedHop::encrypted_payload
153	pub fn blinding_point(&self) -> PublicKey {
154		self.inner_path.blinding_point
155	}
156
157	/// The [`BlindedHop`]s within the blinded path.
158	pub fn blinded_hops(&self) -> &[BlindedHop] {
159		&self.inner_path.blinded_hops
160	}
161
162	/// Advance the blinded onion payment path by one hop, making the second hop into the new
163	/// introduction node.
164	///
165	/// Will only modify `self` when returning `Ok`.
166	pub fn advance_path_by_one<NS: Deref, NL: Deref, T>(
167		&mut self, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1<T>
168	) -> Result<(), ()>
169	where
170		NS::Target: NodeSigner,
171		NL::Target: NodeIdLookUp,
172		T: secp256k1::Signing + secp256k1::Verification,
173	{
174		let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.inner_path.blinding_point, None)?;
175		let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
176		let encrypted_control_tlvs = &self.inner_path.blinded_hops.get(0).ok_or(())?.encrypted_payload;
177		let mut s = Cursor::new(encrypted_control_tlvs);
178		let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
179		match ChaChaPolyReadAdapter::read(&mut reader, rho) {
180			Ok(ChaChaPolyReadAdapter {
181				readable: BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, .. })
182			}) => {
183				let next_node_id = match node_id_lookup.next_node_id(short_channel_id) {
184					Some(node_id) => node_id,
185					None => return Err(()),
186				};
187				let mut new_blinding_point = onion_utils::next_hop_pubkey(
188					secp_ctx, self.inner_path.blinding_point, control_tlvs_ss.as_ref()
189				).map_err(|_| ())?;
190				mem::swap(&mut self.inner_path.blinding_point, &mut new_blinding_point);
191				self.inner_path.introduction_node = IntroductionNode::NodeId(next_node_id);
192				self.inner_path.blinded_hops.remove(0);
193				Ok(())
194			},
195			_ => Err(())
196		}
197	}
198
199	pub(crate) fn inner_blinded_path(&self) -> &BlindedPath {
200		&self.inner_path
201	}
202
203	pub(crate) fn from_parts(inner_path: BlindedPath, payinfo: BlindedPayInfo) -> Self {
204		Self { inner_path, payinfo }
205	}
206
207	#[cfg(any(test, fuzzing))]
208	pub fn from_raw(
209		introduction_node_id: PublicKey, blinding_point: PublicKey, blinded_hops: Vec<BlindedHop>,
210		payinfo: BlindedPayInfo
211	) -> Self {
212		Self {
213			inner_path: BlindedPath {
214				introduction_node: IntroductionNode::NodeId(introduction_node_id),
215				blinding_point,
216				blinded_hops,
217			},
218			payinfo
219		}
220	}
221
222	#[cfg(test)]
223	pub fn clear_blinded_hops(&mut self) {
224		self.inner_path.blinded_hops.clear()
225	}
226}
227
228/// An intermediate node, its outbound channel, and relay parameters.
229#[derive(Clone, Debug)]
230pub struct PaymentForwardNode {
231	/// The TLVs for this node's [`BlindedHop`], where the fee parameters contained within are also
232	/// used for [`BlindedPayInfo`] construction.
233	pub tlvs: ForwardTlvs,
234	/// This node's pubkey.
235	pub node_id: PublicKey,
236	/// The maximum value, in msat, that may be accepted by this node.
237	pub htlc_maximum_msat: u64,
238}
239
240/// Data to construct a [`BlindedHop`] for forwarding a payment.
241#[derive(Clone, Debug)]
242pub struct ForwardTlvs {
243	/// The short channel id this payment should be forwarded out over.
244	pub short_channel_id: u64,
245	/// Payment parameters for relaying over [`Self::short_channel_id`].
246	pub payment_relay: PaymentRelay,
247	/// Payment constraints for relaying over [`Self::short_channel_id`].
248	pub payment_constraints: PaymentConstraints,
249	/// Supported and required features when relaying a payment onion containing this object's
250	/// corresponding [`BlindedHop::encrypted_payload`].
251	///
252	/// [`BlindedHop::encrypted_payload`]: crate::blinded_path::BlindedHop::encrypted_payload
253	pub features: BlindedHopFeatures,
254	/// Set if this [`BlindedPaymentPath`] is concatenated to another, to indicate the
255	/// [`BlindedPaymentPath::blinding_point`] of the appended blinded path.
256	pub next_blinding_override: Option<PublicKey>,
257}
258
259/// Data to construct a [`BlindedHop`] for receiving a payment. This payload is custom to LDK and
260/// may not be valid if received by another lightning implementation.
261///
262/// Can only be constructed by calling [`UnauthenticatedReceiveTlvs::authenticate`].
263#[derive(Clone, Debug)]
264pub struct ReceiveTlvs {
265	/// The TLVs for which the HMAC in `authentication` is derived.
266	pub(crate) tlvs: UnauthenticatedReceiveTlvs,
267	/// An HMAC of `tlvs` along with a nonce used to construct it.
268	pub(crate) authentication: (Hmac<Sha256>, Nonce),
269}
270
271impl ReceiveTlvs {
272	/// Returns the underlying TLVs.
273	pub fn tlvs(&self) -> &UnauthenticatedReceiveTlvs {
274		&self.tlvs
275	}
276}
277
278/// An unauthenticated [`ReceiveTlvs`].
279#[derive(Clone, Debug)]
280pub struct UnauthenticatedReceiveTlvs {
281	/// Used to authenticate the sender of a payment to the receiver and tie MPP HTLCs together.
282	pub payment_secret: PaymentSecret,
283	/// Constraints for the receiver of this payment.
284	pub payment_constraints: PaymentConstraints,
285	/// Context for the receiver of this payment.
286	pub payment_context: PaymentContext,
287}
288
289impl UnauthenticatedReceiveTlvs {
290	/// Creates an authenticated [`ReceiveTlvs`], which includes an HMAC and the provide [`Nonce`]
291	/// that can be use later to verify it authenticity.
292	pub fn authenticate(self, nonce: Nonce, expanded_key: &ExpandedKey) -> ReceiveTlvs {
293		ReceiveTlvs {
294			authentication: (self.hmac_for_offer_payment(nonce, expanded_key), nonce),
295			tlvs: self,
296		}
297	}
298}
299
300/// Data to construct a [`BlindedHop`] for sending a payment over.
301///
302/// [`BlindedHop`]: crate::blinded_path::BlindedHop
303pub(crate) enum BlindedPaymentTlvs {
304	/// This blinded payment data is for a forwarding node.
305	Forward(ForwardTlvs),
306	/// This blinded payment data is for the receiving node.
307	Receive(ReceiveTlvs),
308}
309
310// Used to include forward and receive TLVs in the same iterator for encoding.
311enum BlindedPaymentTlvsRef<'a> {
312	Forward(&'a ForwardTlvs),
313	Receive(&'a ReceiveTlvs),
314}
315
316/// Parameters for relaying over a given [`BlindedHop`].
317///
318/// [`BlindedHop`]: crate::blinded_path::BlindedHop
319#[derive(Clone, Debug, PartialEq)]
320pub struct PaymentRelay {
321	/// Number of blocks subtracted from an incoming HTLC's `cltv_expiry` for this [`BlindedHop`].
322	pub cltv_expiry_delta: u16,
323	/// Liquidity fee charged (in millionths of the amount transferred) for relaying a payment over
324	/// this [`BlindedHop`], (i.e., 10,000 is 1%).
325	pub fee_proportional_millionths: u32,
326	/// Base fee charged (in millisatoshi) for relaying a payment over this [`BlindedHop`].
327	pub fee_base_msat: u32,
328}
329
330/// Constraints for relaying over a given [`BlindedHop`].
331///
332/// [`BlindedHop`]: crate::blinded_path::BlindedHop
333#[derive(Clone, Debug, PartialEq)]
334pub struct PaymentConstraints {
335	/// The maximum total CLTV that is acceptable when relaying a payment over this [`BlindedHop`].
336	pub max_cltv_expiry: u32,
337	/// The minimum value, in msat, that may be accepted by the node corresponding to this
338	/// [`BlindedHop`].
339	pub htlc_minimum_msat: u64,
340}
341
342/// The context of an inbound payment, which is included in a [`BlindedPaymentPath`] via
343/// [`ReceiveTlvs`] and surfaced in [`PaymentPurpose`].
344///
345/// [`PaymentPurpose`]: crate::events::PaymentPurpose
346#[derive(Clone, Debug, Eq, PartialEq)]
347pub enum PaymentContext {
348	/// The payment was made for an invoice requested from a BOLT 12 [`Offer`].
349	///
350	/// [`Offer`]: crate::offers::offer::Offer
351	Bolt12Offer(Bolt12OfferContext),
352
353	/// The payment was made for an invoice sent for a BOLT 12 [`Refund`].
354	///
355	/// [`Refund`]: crate::offers::refund::Refund
356	Bolt12Refund(Bolt12RefundContext),
357}
358
359// Used when writing PaymentContext in Event::PaymentClaimable to avoid cloning.
360pub(crate) enum PaymentContextRef<'a> {
361	Bolt12Offer(&'a Bolt12OfferContext),
362	Bolt12Refund(&'a Bolt12RefundContext),
363}
364
365/// The context of a payment made for an invoice requested from a BOLT 12 [`Offer`].
366///
367/// [`Offer`]: crate::offers::offer::Offer
368#[derive(Clone, Debug, Eq, PartialEq)]
369pub struct Bolt12OfferContext {
370	/// The identifier of the [`Offer`].
371	///
372	/// [`Offer`]: crate::offers::offer::Offer
373	pub offer_id: OfferId,
374
375	/// Fields from an [`InvoiceRequest`] sent for a [`Bolt12Invoice`].
376	///
377	/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
378	/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
379	pub invoice_request: InvoiceRequestFields,
380}
381
382/// The context of a payment made for an invoice sent for a BOLT 12 [`Refund`].
383///
384/// [`Refund`]: crate::offers::refund::Refund
385#[derive(Clone, Debug, Eq, PartialEq)]
386pub struct Bolt12RefundContext {}
387
388impl TryFrom<CounterpartyForwardingInfo> for PaymentRelay {
389	type Error = ();
390
391	fn try_from(info: CounterpartyForwardingInfo) -> Result<Self, ()> {
392		let CounterpartyForwardingInfo {
393			fee_base_msat, fee_proportional_millionths, cltv_expiry_delta
394		} = info;
395
396		// Avoid exposing esoteric CLTV expiry deltas
397		let cltv_expiry_delta = match cltv_expiry_delta {
398			0..=40 => 40,
399			41..=80 => 80,
400			81..=144 => 144,
401			145..=216 => 216,
402			_ => return Err(()),
403		};
404
405		Ok(Self { cltv_expiry_delta, fee_proportional_millionths, fee_base_msat })
406	}
407}
408
409impl Writeable for ForwardTlvs {
410	fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
411		let features_opt =
412			if self.features == BlindedHopFeatures::empty() { None }
413			else { Some(WithoutLength(&self.features)) };
414		encode_tlv_stream!(w, {
415			(2, self.short_channel_id, required),
416			(10, self.payment_relay, required),
417			(12, self.payment_constraints, required),
418			(14, features_opt, option)
419		});
420		Ok(())
421	}
422}
423
424impl Writeable for ReceiveTlvs {
425	fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
426		encode_tlv_stream!(w, {
427			(12, self.tlvs.payment_constraints, required),
428			(65536, self.tlvs.payment_secret, required),
429			(65537, self.tlvs.payment_context, required),
430			(65539, self.authentication, required),
431		});
432		Ok(())
433	}
434}
435
436impl Writeable for UnauthenticatedReceiveTlvs {
437	fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
438		encode_tlv_stream!(w, {
439			(12, self.payment_constraints, required),
440			(65536, self.payment_secret, required),
441			(65537, self.payment_context, required),
442		});
443		Ok(())
444	}
445}
446
447impl<'a> Writeable for BlindedPaymentTlvsRef<'a> {
448	fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
449		// TODO: write padding
450		match self {
451			Self::Forward(tlvs) => tlvs.write(w)?,
452			Self::Receive(tlvs) => tlvs.write(w)?,
453		}
454		Ok(())
455	}
456}
457
458impl Readable for BlindedPaymentTlvs {
459	fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
460		_init_and_read_tlv_stream!(r, {
461			(1, _padding, option),
462			(2, scid, option),
463			(8, next_blinding_override, option),
464			(10, payment_relay, option),
465			(12, payment_constraints, required),
466			(14, features, (option, encoding: (BlindedHopFeatures, WithoutLength))),
467			(65536, payment_secret, option),
468			(65537, payment_context, option),
469			(65539, authentication, option),
470		});
471		let _padding: Option<utils::Padding> = _padding;
472
473		if let Some(short_channel_id) = scid {
474			if payment_secret.is_some() {
475				return Err(DecodeError::InvalidValue)
476			}
477			Ok(BlindedPaymentTlvs::Forward(ForwardTlvs {
478				short_channel_id,
479				payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?,
480				payment_constraints: payment_constraints.0.unwrap(),
481				next_blinding_override,
482				features: features.unwrap_or_else(BlindedHopFeatures::empty),
483			}))
484		} else {
485			if payment_relay.is_some() || features.is_some() { return Err(DecodeError::InvalidValue) }
486			Ok(BlindedPaymentTlvs::Receive(ReceiveTlvs {
487				tlvs: UnauthenticatedReceiveTlvs {
488					payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
489					payment_constraints: payment_constraints.0.unwrap(),
490					payment_context: payment_context.ok_or(DecodeError::InvalidValue)?,
491				},
492				authentication: authentication.ok_or(DecodeError::InvalidValue)?,
493			}))
494		}
495	}
496}
497
498/// Construct blinded payment hops for the given `intermediate_nodes` and payee info.
499pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
500	secp_ctx: &Secp256k1<T>, intermediate_nodes: &[PaymentForwardNode],
501	payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, session_priv: &SecretKey,
502) -> Result<Vec<BlindedHop>, secp256k1::Error> {
503	let pks = intermediate_nodes.iter().map(|node| node.node_id)
504		.chain(core::iter::once(payee_node_id));
505	let tlvs = intermediate_nodes.iter().map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs))
506		.chain(core::iter::once(BlindedPaymentTlvsRef::Receive(&payee_tlvs)));
507
508	let path = pks.zip(tlvs);
509
510	utils::construct_blinded_hops(secp_ctx, path, session_priv)
511}
512
513/// `None` if underflow occurs.
514pub(crate) fn amt_to_forward_msat(inbound_amt_msat: u64, payment_relay: &PaymentRelay) -> Option<u64> {
515	let inbound_amt = inbound_amt_msat as u128;
516	let base = payment_relay.fee_base_msat as u128;
517	let prop = payment_relay.fee_proportional_millionths as u128;
518
519	let post_base_fee_inbound_amt =
520		if let Some(amt) = inbound_amt.checked_sub(base) { amt } else { return None };
521	let mut amt_to_forward =
522		(post_base_fee_inbound_amt * 1_000_000 + 1_000_000 + prop - 1) / (prop + 1_000_000);
523
524	let fee = ((amt_to_forward * prop) / 1_000_000) + base;
525	if inbound_amt - fee < amt_to_forward {
526		// Rounding up the forwarded amount resulted in underpaying this node, so take an extra 1 msat
527		// in fee to compensate.
528		amt_to_forward -= 1;
529	}
530	debug_assert_eq!(amt_to_forward + fee, inbound_amt);
531	u64::try_from(amt_to_forward).ok()
532}
533
534// Returns (aggregated_base_fee, aggregated_proportional_fee)
535pub(crate) fn compute_aggregated_base_prop_fee<I>(hops_fees: I) -> Result<(u64, u64), ()>
536where
537	I: DoubleEndedIterator<Item = RoutingFees>,
538{
539	let mut curr_base_fee: u64 = 0;
540	let mut curr_prop_mil: u64 = 0;
541	for fees in hops_fees.rev() {
542		let next_base_fee = fees.base_msat as u64;
543		let next_prop_mil = fees.proportional_millionths as u64;
544
545		// Use integer arithmetic to compute `ceil(a/b)` as `(a+b-1)/b`
546		// ((curr_base_fee * (1_000_000 + next_prop_mil)) / 1_000_000) + next_base_fee
547		curr_base_fee = curr_base_fee.checked_mul(1_000_000 + next_prop_mil)
548			.and_then(|f| f.checked_add(1_000_000 - 1))
549			.map(|f| f / 1_000_000)
550			.and_then(|f| f.checked_add(next_base_fee))
551			.ok_or(())?;
552		// ceil(((curr_prop_mil + 1_000_000) * (next_prop_mil + 1_000_000)) / 1_000_000) - 1_000_000
553		curr_prop_mil = curr_prop_mil.checked_add(1_000_000)
554			.and_then(|f1| next_prop_mil.checked_add(1_000_000).and_then(|f2| f2.checked_mul(f1)))
555			.and_then(|f| f.checked_add(1_000_000 - 1))
556			.map(|f| f / 1_000_000)
557			.and_then(|f| f.checked_sub(1_000_000))
558			.ok_or(())?;
559	}
560
561	Ok((curr_base_fee, curr_prop_mil))
562}
563
564pub(super) fn compute_payinfo(
565	intermediate_nodes: &[PaymentForwardNode], payee_tlvs: &UnauthenticatedReceiveTlvs,
566	payee_htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16,
567) -> Result<BlindedPayInfo, ()> {
568	let (aggregated_base_fee, aggregated_prop_fee) =
569		compute_aggregated_base_prop_fee(intermediate_nodes.iter().map(|node| RoutingFees {
570			base_msat: node.tlvs.payment_relay.fee_base_msat,
571			proportional_millionths: node.tlvs.payment_relay.fee_proportional_millionths,
572		}))?;
573
574	let mut htlc_minimum_msat: u64 = 1;
575	let mut htlc_maximum_msat: u64 = 21_000_000 * 100_000_000 * 1_000; // Total bitcoin supply
576	let mut cltv_expiry_delta: u16 = min_final_cltv_expiry_delta;
577	for node in intermediate_nodes.iter() {
578		// In the future, we'll want to take the intersection of all supported features for the
579		// `BlindedPayInfo`, but there are no features in that context right now.
580		if node.tlvs.features.requires_unknown_bits_from(&BlindedHopFeatures::empty()) {
581			return Err(());
582		}
583
584		cltv_expiry_delta =
585			cltv_expiry_delta.checked_add(node.tlvs.payment_relay.cltv_expiry_delta).ok_or(())?;
586
587		// The min htlc for an intermediate node is that node's min minus the fees charged by all of the
588		// following hops for forwarding that min, since that fee amount will automatically be included
589		// in the amount that this node receives and contribute towards reaching its min.
590		htlc_minimum_msat = amt_to_forward_msat(
591			core::cmp::max(node.tlvs.payment_constraints.htlc_minimum_msat, htlc_minimum_msat),
592			&node.tlvs.payment_relay
593		).unwrap_or(1); // If underflow occurs, we definitely reached this node's min
594		htlc_maximum_msat = amt_to_forward_msat(
595			core::cmp::min(node.htlc_maximum_msat, htlc_maximum_msat), &node.tlvs.payment_relay
596		).ok_or(())?; // If underflow occurs, we cannot send to this hop without exceeding their max
597	}
598	htlc_minimum_msat = core::cmp::max(
599		payee_tlvs.payment_constraints.htlc_minimum_msat, htlc_minimum_msat
600	);
601	htlc_maximum_msat = core::cmp::min(payee_htlc_maximum_msat, htlc_maximum_msat);
602
603	if htlc_maximum_msat < htlc_minimum_msat { return Err(()) }
604	Ok(BlindedPayInfo {
605		fee_base_msat: u32::try_from(aggregated_base_fee).map_err(|_| ())?,
606		fee_proportional_millionths: u32::try_from(aggregated_prop_fee).map_err(|_| ())?,
607		cltv_expiry_delta,
608		htlc_minimum_msat,
609		htlc_maximum_msat,
610		features: BlindedHopFeatures::empty(),
611	})
612}
613
614impl Writeable for PaymentRelay {
615	fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
616		self.cltv_expiry_delta.write(w)?;
617		self.fee_proportional_millionths.write(w)?;
618		HighZeroBytesDroppedBigSize(self.fee_base_msat).write(w)
619	}
620}
621impl Readable for PaymentRelay {
622	fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
623		let cltv_expiry_delta: u16 = Readable::read(r)?;
624		let fee_proportional_millionths: u32 = Readable::read(r)?;
625		let fee_base_msat: HighZeroBytesDroppedBigSize<u32> = Readable::read(r)?;
626		Ok(Self { cltv_expiry_delta, fee_proportional_millionths, fee_base_msat: fee_base_msat.0 })
627	}
628}
629
630impl Writeable for PaymentConstraints {
631	fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
632		self.max_cltv_expiry.write(w)?;
633		HighZeroBytesDroppedBigSize(self.htlc_minimum_msat).write(w)
634	}
635}
636impl Readable for PaymentConstraints {
637	fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
638		let max_cltv_expiry: u32 = Readable::read(r)?;
639		let htlc_minimum_msat: HighZeroBytesDroppedBigSize<u64> = Readable::read(r)?;
640		Ok(Self { max_cltv_expiry, htlc_minimum_msat: htlc_minimum_msat.0 })
641	}
642}
643
644impl_writeable_tlv_based_enum_legacy!(PaymentContext,
645	;
646	// 0 for Unknown removed in version 0.1.
647	(1, Bolt12Offer),
648	(2, Bolt12Refund),
649);
650
651impl<'a> Writeable for PaymentContextRef<'a> {
652	fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
653		match self {
654			PaymentContextRef::Bolt12Offer(context) => {
655				1u8.write(w)?;
656				context.write(w)?;
657			},
658			PaymentContextRef::Bolt12Refund(context) => {
659				2u8.write(w)?;
660				context.write(w)?;
661			},
662		}
663
664		Ok(())
665	}
666}
667
668impl_writeable_tlv_based!(Bolt12OfferContext, {
669	(0, offer_id, required),
670	(2, invoice_request, required),
671});
672
673impl_writeable_tlv_based!(Bolt12RefundContext, {});
674
675#[cfg(test)]
676mod tests {
677	use bitcoin::secp256k1::PublicKey;
678	use crate::blinded_path::payment::{Bolt12RefundContext, PaymentForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, UnauthenticatedReceiveTlvs};
679	use crate::types::payment::PaymentSecret;
680	use crate::types::features::BlindedHopFeatures;
681	use crate::ln::functional_test_utils::TEST_FINAL_CLTV;
682
683	#[test]
684	fn compute_payinfo() {
685		// Taken from the spec example for aggregating blinded payment info. See
686		// https://github.com/lightning/bolts/blob/master/proposals/route-blinding.md#blinded-payments
687		let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
688		let intermediate_nodes = vec![PaymentForwardNode {
689			node_id: dummy_pk,
690			tlvs: ForwardTlvs {
691				short_channel_id: 0,
692				payment_relay: PaymentRelay {
693					cltv_expiry_delta: 144,
694					fee_proportional_millionths: 500,
695					fee_base_msat: 100,
696				},
697				payment_constraints: PaymentConstraints {
698					max_cltv_expiry: 0,
699					htlc_minimum_msat: 100,
700				},
701				next_blinding_override: None,
702				features: BlindedHopFeatures::empty(),
703			},
704			htlc_maximum_msat: u64::max_value(),
705		}, PaymentForwardNode {
706			node_id: dummy_pk,
707			tlvs: ForwardTlvs {
708				short_channel_id: 0,
709				payment_relay: PaymentRelay {
710					cltv_expiry_delta: 144,
711					fee_proportional_millionths: 500,
712					fee_base_msat: 100,
713				},
714				payment_constraints: PaymentConstraints {
715					max_cltv_expiry: 0,
716					htlc_minimum_msat: 1_000,
717				},
718				next_blinding_override: None,
719				features: BlindedHopFeatures::empty(),
720			},
721			htlc_maximum_msat: u64::max_value(),
722		}];
723		let recv_tlvs = UnauthenticatedReceiveTlvs {
724			payment_secret: PaymentSecret([0; 32]),
725			payment_constraints: PaymentConstraints {
726				max_cltv_expiry: 0,
727				htlc_minimum_msat: 1,
728			},
729			payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
730		};
731		let htlc_maximum_msat = 100_000;
732		let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, 12).unwrap();
733		assert_eq!(blinded_payinfo.fee_base_msat, 201);
734		assert_eq!(blinded_payinfo.fee_proportional_millionths, 1001);
735		assert_eq!(blinded_payinfo.cltv_expiry_delta, 300);
736		assert_eq!(blinded_payinfo.htlc_minimum_msat, 900);
737		assert_eq!(blinded_payinfo.htlc_maximum_msat, htlc_maximum_msat);
738	}
739
740	#[test]
741	fn compute_payinfo_1_hop() {
742		let recv_tlvs = UnauthenticatedReceiveTlvs {
743			payment_secret: PaymentSecret([0; 32]),
744			payment_constraints: PaymentConstraints {
745				max_cltv_expiry: 0,
746				htlc_minimum_msat: 1,
747			},
748			payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
749		};
750		let blinded_payinfo = super::compute_payinfo(&[], &recv_tlvs, 4242, TEST_FINAL_CLTV as u16).unwrap();
751		assert_eq!(blinded_payinfo.fee_base_msat, 0);
752		assert_eq!(blinded_payinfo.fee_proportional_millionths, 0);
753		assert_eq!(blinded_payinfo.cltv_expiry_delta, TEST_FINAL_CLTV as u16);
754		assert_eq!(blinded_payinfo.htlc_minimum_msat, 1);
755		assert_eq!(blinded_payinfo.htlc_maximum_msat, 4242);
756	}
757
758	#[test]
759	fn simple_aggregated_htlc_min() {
760		// If no hops charge fees, the htlc_minimum_msat should just be the maximum htlc_minimum_msat
761		// along the path.
762		let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
763		let intermediate_nodes = vec![PaymentForwardNode {
764			node_id: dummy_pk,
765			tlvs: ForwardTlvs {
766				short_channel_id: 0,
767				payment_relay: PaymentRelay {
768					cltv_expiry_delta: 0,
769					fee_proportional_millionths: 0,
770					fee_base_msat: 0,
771				},
772				payment_constraints: PaymentConstraints {
773					max_cltv_expiry: 0,
774					htlc_minimum_msat: 1,
775				},
776				next_blinding_override: None,
777				features: BlindedHopFeatures::empty(),
778			},
779			htlc_maximum_msat: u64::max_value()
780		}, PaymentForwardNode {
781			node_id: dummy_pk,
782			tlvs: ForwardTlvs {
783				short_channel_id: 0,
784				payment_relay: PaymentRelay {
785					cltv_expiry_delta: 0,
786					fee_proportional_millionths: 0,
787					fee_base_msat: 0,
788				},
789				payment_constraints: PaymentConstraints {
790					max_cltv_expiry: 0,
791					htlc_minimum_msat: 2_000,
792				},
793				next_blinding_override: None,
794				features: BlindedHopFeatures::empty(),
795			},
796			htlc_maximum_msat: u64::max_value()
797		}];
798		let recv_tlvs = UnauthenticatedReceiveTlvs {
799			payment_secret: PaymentSecret([0; 32]),
800			payment_constraints: PaymentConstraints {
801				max_cltv_expiry: 0,
802				htlc_minimum_msat: 3,
803			},
804			payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
805		};
806		let htlc_maximum_msat = 100_000;
807		let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, TEST_FINAL_CLTV as u16).unwrap();
808		assert_eq!(blinded_payinfo.htlc_minimum_msat, 2_000);
809	}
810
811	#[test]
812	fn aggregated_htlc_min() {
813		// Create a path with varying fees and htlc_mins, and make sure htlc_minimum_msat ends up as the
814		// max (htlc_min - following_fees) along the path.
815		let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
816		let intermediate_nodes = vec![PaymentForwardNode {
817			node_id: dummy_pk,
818			tlvs: ForwardTlvs {
819				short_channel_id: 0,
820				payment_relay: PaymentRelay {
821					cltv_expiry_delta: 0,
822					fee_proportional_millionths: 500,
823					fee_base_msat: 1_000,
824				},
825				payment_constraints: PaymentConstraints {
826					max_cltv_expiry: 0,
827					htlc_minimum_msat: 5_000,
828				},
829				next_blinding_override: None,
830				features: BlindedHopFeatures::empty(),
831			},
832			htlc_maximum_msat: u64::max_value()
833		}, PaymentForwardNode {
834			node_id: dummy_pk,
835			tlvs: ForwardTlvs {
836				short_channel_id: 0,
837				payment_relay: PaymentRelay {
838					cltv_expiry_delta: 0,
839					fee_proportional_millionths: 500,
840					fee_base_msat: 200,
841				},
842				payment_constraints: PaymentConstraints {
843					max_cltv_expiry: 0,
844					htlc_minimum_msat: 2_000,
845				},
846				next_blinding_override: None,
847				features: BlindedHopFeatures::empty(),
848			},
849			htlc_maximum_msat: u64::max_value()
850		}];
851		let recv_tlvs = UnauthenticatedReceiveTlvs {
852			payment_secret: PaymentSecret([0; 32]),
853			payment_constraints: PaymentConstraints {
854				max_cltv_expiry: 0,
855				htlc_minimum_msat: 1,
856			},
857			payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
858		};
859		let htlc_minimum_msat = 3798;
860		assert!(super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_minimum_msat - 1, TEST_FINAL_CLTV as u16).is_err());
861
862		let htlc_maximum_msat = htlc_minimum_msat + 1;
863		let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, TEST_FINAL_CLTV as u16).unwrap();
864		assert_eq!(blinded_payinfo.htlc_minimum_msat, htlc_minimum_msat);
865		assert_eq!(blinded_payinfo.htlc_maximum_msat, htlc_maximum_msat);
866	}
867
868	#[test]
869	fn aggregated_htlc_max() {
870		// Create a path with varying fees and `htlc_maximum_msat`s, and make sure the aggregated max
871		// htlc ends up as the min (htlc_max - following_fees) along the path.
872		let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
873		let intermediate_nodes = vec![PaymentForwardNode {
874			node_id: dummy_pk,
875			tlvs: ForwardTlvs {
876				short_channel_id: 0,
877				payment_relay: PaymentRelay {
878					cltv_expiry_delta: 0,
879					fee_proportional_millionths: 500,
880					fee_base_msat: 1_000,
881				},
882				payment_constraints: PaymentConstraints {
883					max_cltv_expiry: 0,
884					htlc_minimum_msat: 1,
885				},
886				next_blinding_override: None,
887				features: BlindedHopFeatures::empty(),
888			},
889			htlc_maximum_msat: 5_000,
890		}, PaymentForwardNode {
891			node_id: dummy_pk,
892			tlvs: ForwardTlvs {
893				short_channel_id: 0,
894				payment_relay: PaymentRelay {
895					cltv_expiry_delta: 0,
896					fee_proportional_millionths: 500,
897					fee_base_msat: 1,
898				},
899				payment_constraints: PaymentConstraints {
900					max_cltv_expiry: 0,
901					htlc_minimum_msat: 1,
902				},
903				next_blinding_override: None,
904				features: BlindedHopFeatures::empty(),
905			},
906			htlc_maximum_msat: 10_000
907		}];
908		let recv_tlvs = UnauthenticatedReceiveTlvs {
909			payment_secret: PaymentSecret([0; 32]),
910			payment_constraints: PaymentConstraints {
911				max_cltv_expiry: 0,
912				htlc_minimum_msat: 1,
913			},
914			payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
915		};
916
917		let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, 10_000, TEST_FINAL_CLTV as u16).unwrap();
918		assert_eq!(blinded_payinfo.htlc_maximum_msat, 3997);
919	}
920}