1use bitcoin::hashes::hmac::Hmac;
13use bitcoin::hashes::sha256::Hash as Sha256;
14use bitcoin::secp256k1::ecdh::SharedSecret;
15use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
16
17use crate::blinded_path::utils::{self, BlindedPathWithPadding};
18use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp};
19use crate::crypto::streams::ChaChaPolyReadAdapter;
20use crate::io;
21use crate::io::Cursor;
22use crate::ln::channel_state::CounterpartyForwardingInfo;
23use crate::ln::channelmanager::Verification;
24use crate::ln::inbound_payment::ExpandedKey;
25use crate::ln::msgs::DecodeError;
26use crate::ln::onion_utils;
27use crate::offers::invoice_request::InvoiceRequestFields;
28use crate::offers::nonce::Nonce;
29use crate::offers::offer::OfferId;
30use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
31use crate::sign::{EntropySource, NodeSigner, Recipient};
32use crate::types::features::BlindedHopFeatures;
33use crate::types::payment::PaymentSecret;
34use crate::types::routing::RoutingFees;
35use crate::util::ser::{
36 FixedLengthReader, HighZeroBytesDroppedBigSize, LengthReadableArgs, Readable, WithoutLength,
37 Writeable, Writer,
38};
39
40use core::mem;
41use core::ops::Deref;
42
43#[allow(unused_imports)]
44use crate::prelude::*;
45
46#[derive(Clone, Debug, Hash, Eq, PartialEq)]
48pub struct BlindedPayInfo {
49 pub fee_base_msat: u32,
51
52 pub fee_proportional_millionths: u32,
55
56 pub cltv_expiry_delta: u16,
59
60 pub htlc_minimum_msat: u64,
64
65 pub htlc_maximum_msat: u64,
69
70 pub features: BlindedHopFeatures,
73}
74
75impl_writeable!(BlindedPayInfo, {
76 fee_base_msat,
77 fee_proportional_millionths,
78 cltv_expiry_delta,
79 htlc_minimum_msat,
80 htlc_maximum_msat,
81 features
82});
83
84#[derive(Clone, Debug, Hash, PartialEq, Eq)]
87pub struct BlindedPaymentPath {
88 pub(super) inner_path: BlindedPath,
89 pub payinfo: BlindedPayInfo,
91}
92
93impl BlindedPaymentPath {
94 pub fn one_hop<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
96 payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, min_final_cltv_expiry_delta: u16,
97 entropy_source: ES, secp_ctx: &Secp256k1<T>,
98 ) -> Result<Self, ()>
99 where
100 ES::Target: EntropySource,
101 {
102 let htlc_maximum_msat = u64::max_value();
105 Self::new(
106 &[],
107 payee_node_id,
108 payee_tlvs,
109 htlc_maximum_msat,
110 min_final_cltv_expiry_delta,
111 entropy_source,
112 secp_ctx,
113 )
114 }
115
116 pub fn new<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
123 intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey,
124 payee_tlvs: ReceiveTlvs, htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16,
125 entropy_source: ES, secp_ctx: &Secp256k1<T>,
126 ) -> Result<Self, ()>
127 where
128 ES::Target: EntropySource,
129 {
130 let introduction_node = IntroductionNode::NodeId(
131 intermediate_nodes.first().map_or(payee_node_id, |n| n.node_id),
132 );
133 let blinding_secret_bytes = entropy_source.get_secure_random_bytes();
134 let blinding_secret =
135 SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
136
137 let blinded_payinfo = compute_payinfo(
138 intermediate_nodes,
139 &payee_tlvs.tlvs,
140 htlc_maximum_msat,
141 min_final_cltv_expiry_delta,
142 )?;
143 Ok(Self {
144 inner_path: BlindedPath {
145 introduction_node,
146 blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
147 blinded_hops: blinded_hops(
148 secp_ctx,
149 intermediate_nodes,
150 payee_node_id,
151 payee_tlvs,
152 &blinding_secret,
153 ),
154 },
155 payinfo: blinded_payinfo,
156 })
157 }
158
159 pub fn public_introduction_node_id<'a>(
162 &self, network_graph: &'a ReadOnlyNetworkGraph,
163 ) -> Option<&'a NodeId> {
164 self.inner_path.public_introduction_node_id(network_graph)
165 }
166
167 pub fn introduction_node(&self) -> &IntroductionNode {
169 &self.inner_path.introduction_node
170 }
171
172 pub fn blinding_point(&self) -> PublicKey {
176 self.inner_path.blinding_point
177 }
178
179 pub fn blinded_hops(&self) -> &[BlindedHop] {
181 &self.inner_path.blinded_hops
182 }
183
184 pub fn advance_path_by_one<NS: Deref, NL: Deref, T>(
189 &mut self, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1<T>,
190 ) -> Result<(), ()>
191 where
192 NS::Target: NodeSigner,
193 NL::Target: NodeIdLookUp,
194 T: secp256k1::Signing + secp256k1::Verification,
195 {
196 match self.decrypt_intro_payload::<NS>(node_signer) {
197 Ok((
198 BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, .. }),
199 control_tlvs_ss,
200 )) => {
201 let next_node_id = match node_id_lookup.next_node_id(short_channel_id) {
202 Some(node_id) => node_id,
203 None => return Err(()),
204 };
205 let mut new_blinding_point = onion_utils::next_hop_pubkey(
206 secp_ctx,
207 self.inner_path.blinding_point,
208 control_tlvs_ss.as_ref(),
209 )
210 .map_err(|_| ())?;
211 mem::swap(&mut self.inner_path.blinding_point, &mut new_blinding_point);
212 self.inner_path.introduction_node = IntroductionNode::NodeId(next_node_id);
213 self.inner_path.blinded_hops.remove(0);
214 Ok(())
215 },
216 _ => Err(()),
217 }
218 }
219
220 pub(crate) fn decrypt_intro_payload<NS: Deref>(
221 &self, node_signer: &NS,
222 ) -> Result<(BlindedPaymentTlvs, SharedSecret), ()>
223 where
224 NS::Target: NodeSigner,
225 {
226 let control_tlvs_ss =
227 node_signer.ecdh(Recipient::Node, &self.inner_path.blinding_point, None)?;
228 let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
229 let encrypted_control_tlvs =
230 &self.inner_path.blinded_hops.get(0).ok_or(())?.encrypted_payload;
231 let mut s = Cursor::new(encrypted_control_tlvs);
232 let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
233 match ChaChaPolyReadAdapter::read(&mut reader, rho) {
234 Ok(ChaChaPolyReadAdapter { readable, .. }) => Ok((readable, control_tlvs_ss)),
235 _ => Err(()),
236 }
237 }
238
239 pub(crate) fn inner_blinded_path(&self) -> &BlindedPath {
240 &self.inner_path
241 }
242
243 pub(crate) fn from_parts(inner_path: BlindedPath, payinfo: BlindedPayInfo) -> Self {
244 Self { inner_path, payinfo }
245 }
246
247 pub fn from_blinded_path_and_payinfo(
257 introduction_node_id: PublicKey, blinding_point: PublicKey, blinded_hops: Vec<BlindedHop>,
258 payinfo: BlindedPayInfo,
259 ) -> Self {
260 Self::from_parts(
261 BlindedPath {
262 introduction_node: IntroductionNode::NodeId(introduction_node_id),
263 blinding_point,
264 blinded_hops,
265 },
266 payinfo,
267 )
268 }
269
270 #[cfg(test)]
271 pub fn clear_blinded_hops(&mut self) {
272 self.inner_path.blinded_hops.clear()
273 }
274}
275
276#[derive(Clone, Debug)]
278pub struct PaymentForwardNode {
279 pub tlvs: ForwardTlvs,
282 pub node_id: PublicKey,
284 pub htlc_maximum_msat: u64,
286}
287
288#[derive(Clone, Debug)]
290pub struct ForwardTlvs {
291 pub short_channel_id: u64,
293 pub payment_relay: PaymentRelay,
295 pub payment_constraints: PaymentConstraints,
297 pub features: BlindedHopFeatures,
302 pub next_blinding_override: Option<PublicKey>,
305}
306
307#[derive(Clone, Debug)]
309pub struct TrampolineForwardTlvs {
310 pub next_trampoline: PublicKey,
312 pub payment_relay: PaymentRelay,
314 pub payment_constraints: PaymentConstraints,
316 pub features: BlindedHopFeatures,
321 pub next_blinding_override: Option<PublicKey>,
324}
325
326#[derive(Clone, Debug)]
331pub struct ReceiveTlvs {
332 pub(crate) tlvs: UnauthenticatedReceiveTlvs,
334 pub(crate) authentication: (Hmac<Sha256>, Nonce),
336}
337
338impl ReceiveTlvs {
339 pub fn tlvs(&self) -> &UnauthenticatedReceiveTlvs {
341 &self.tlvs
342 }
343}
344
345#[derive(Clone, Debug)]
347pub struct UnauthenticatedReceiveTlvs {
348 pub payment_secret: PaymentSecret,
350 pub payment_constraints: PaymentConstraints,
352 pub payment_context: PaymentContext,
354}
355
356impl UnauthenticatedReceiveTlvs {
357 pub fn authenticate(self, nonce: Nonce, expanded_key: &ExpandedKey) -> ReceiveTlvs {
360 ReceiveTlvs {
361 authentication: (self.hmac_for_offer_payment(nonce, expanded_key), nonce),
362 tlvs: self,
363 }
364 }
365}
366
367pub(crate) enum BlindedPaymentTlvs {
371 Forward(ForwardTlvs),
373 Receive(ReceiveTlvs),
375}
376
377pub(crate) enum BlindedTrampolineTlvs {
381 Forward(TrampolineForwardTlvs),
383 Receive(ReceiveTlvs),
385}
386
387enum BlindedPaymentTlvsRef<'a> {
389 Forward(&'a ForwardTlvs),
390 Receive(&'a ReceiveTlvs),
391}
392
393#[derive(Clone, Debug, PartialEq)]
397pub struct PaymentRelay {
398 pub cltv_expiry_delta: u16,
400 pub fee_proportional_millionths: u32,
403 pub fee_base_msat: u32,
405}
406
407#[derive(Clone, Debug, PartialEq)]
411pub struct PaymentConstraints {
412 pub max_cltv_expiry: u32,
414 pub htlc_minimum_msat: u64,
417}
418
419#[derive(Clone, Debug, Eq, PartialEq)]
424pub enum PaymentContext {
425 Bolt12Offer(Bolt12OfferContext),
429
430 AsyncBolt12Offer(AsyncBolt12OfferContext),
434
435 Bolt12Refund(Bolt12RefundContext),
439}
440
441pub(crate) enum PaymentContextRef<'a> {
443 Bolt12Offer(&'a Bolt12OfferContext),
444 Bolt12Refund(&'a Bolt12RefundContext),
445}
446
447#[derive(Clone, Debug, Eq, PartialEq)]
451pub struct Bolt12OfferContext {
452 pub offer_id: OfferId,
456
457 pub invoice_request: InvoiceRequestFields,
462}
463
464#[derive(Clone, Debug, Eq, PartialEq)]
468pub struct AsyncBolt12OfferContext {
469 pub offer_nonce: Nonce,
474}
475
476#[derive(Clone, Debug, Eq, PartialEq)]
480pub struct Bolt12RefundContext {}
481
482impl TryFrom<CounterpartyForwardingInfo> for PaymentRelay {
483 type Error = ();
484
485 fn try_from(info: CounterpartyForwardingInfo) -> Result<Self, ()> {
486 let CounterpartyForwardingInfo {
487 fee_base_msat,
488 fee_proportional_millionths,
489 cltv_expiry_delta,
490 } = info;
491
492 let cltv_expiry_delta = match cltv_expiry_delta {
494 0..=40 => 40,
495 41..=80 => 80,
496 81..=144 => 144,
497 145..=216 => 216,
498 _ => return Err(()),
499 };
500
501 Ok(Self { cltv_expiry_delta, fee_proportional_millionths, fee_base_msat })
502 }
503}
504
505impl Writeable for ForwardTlvs {
506 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
507 let features_opt = if self.features == BlindedHopFeatures::empty() {
508 None
509 } else {
510 Some(WithoutLength(&self.features))
511 };
512 encode_tlv_stream!(w, {
513 (2, self.short_channel_id, required),
514 (10, self.payment_relay, required),
515 (12, self.payment_constraints, required),
516 (14, features_opt, option)
517 });
518 Ok(())
519 }
520}
521
522impl Writeable for TrampolineForwardTlvs {
523 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
524 let features_opt = if self.features == BlindedHopFeatures::empty() {
525 None
526 } else {
527 Some(WithoutLength(&self.features))
528 };
529 encode_tlv_stream!(w, {
530 (4, self.next_trampoline, required),
531 (10, self.payment_relay, required),
532 (12, self.payment_constraints, required),
533 (14, features_opt, option)
534 });
535 Ok(())
536 }
537}
538
539impl Writeable for ReceiveTlvs {
540 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
541 encode_tlv_stream!(w, {
542 (12, self.tlvs.payment_constraints, required),
543 (65536, self.tlvs.payment_secret, required),
544 (65537, self.tlvs.payment_context, required),
545 (65539, self.authentication, required),
546 });
547 Ok(())
548 }
549}
550
551impl Writeable for UnauthenticatedReceiveTlvs {
552 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
553 encode_tlv_stream!(w, {
554 (12, self.payment_constraints, required),
555 (65536, self.payment_secret, required),
556 (65537, self.payment_context, required),
557 });
558 Ok(())
559 }
560}
561
562impl<'a> Writeable for BlindedPaymentTlvsRef<'a> {
563 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
564 match self {
565 Self::Forward(tlvs) => tlvs.write(w)?,
566 Self::Receive(tlvs) => tlvs.write(w)?,
567 }
568 Ok(())
569 }
570}
571
572impl Readable for BlindedPaymentTlvs {
573 fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
574 _init_and_read_tlv_stream!(r, {
575 (2, scid, option),
580 (8, next_blinding_override, option),
581 (10, payment_relay, option),
582 (12, payment_constraints, required),
583 (14, features, (option, encoding: (BlindedHopFeatures, WithoutLength))),
584 (65536, payment_secret, option),
585 (65537, payment_context, option),
586 (65539, authentication, option),
587 });
588
589 if let Some(short_channel_id) = scid {
590 if payment_secret.is_some() {
591 return Err(DecodeError::InvalidValue);
592 }
593 Ok(BlindedPaymentTlvs::Forward(ForwardTlvs {
594 short_channel_id,
595 payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?,
596 payment_constraints: payment_constraints.0.unwrap(),
597 next_blinding_override,
598 features: features.unwrap_or_else(BlindedHopFeatures::empty),
599 }))
600 } else {
601 if payment_relay.is_some() || features.is_some() {
602 return Err(DecodeError::InvalidValue);
603 }
604 Ok(BlindedPaymentTlvs::Receive(ReceiveTlvs {
605 tlvs: UnauthenticatedReceiveTlvs {
606 payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
607 payment_constraints: payment_constraints.0.unwrap(),
608 payment_context: payment_context.ok_or(DecodeError::InvalidValue)?,
609 },
610 authentication: authentication.ok_or(DecodeError::InvalidValue)?,
611 }))
612 }
613 }
614}
615
616impl Readable for BlindedTrampolineTlvs {
617 fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
618 _init_and_read_tlv_stream!(r, {
619 (4, next_trampoline, option),
620 (8, next_blinding_override, option),
621 (10, payment_relay, option),
622 (12, payment_constraints, required),
623 (14, features, (option, encoding: (BlindedHopFeatures, WithoutLength))),
624 (65536, payment_secret, option),
625 (65537, payment_context, option),
626 (65539, authentication, option),
627 });
628
629 if let Some(next_trampoline) = next_trampoline {
630 if payment_secret.is_some() {
631 return Err(DecodeError::InvalidValue);
632 }
633 Ok(BlindedTrampolineTlvs::Forward(TrampolineForwardTlvs {
634 next_trampoline,
635 payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?,
636 payment_constraints: payment_constraints.0.unwrap(),
637 next_blinding_override,
638 features: features.unwrap_or_else(BlindedHopFeatures::empty),
639 }))
640 } else {
641 if payment_relay.is_some() || features.is_some() {
642 return Err(DecodeError::InvalidValue);
643 }
644 Ok(BlindedTrampolineTlvs::Receive(ReceiveTlvs {
645 tlvs: UnauthenticatedReceiveTlvs {
646 payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
647 payment_constraints: payment_constraints.0.unwrap(),
648 payment_context: payment_context.ok_or(DecodeError::InvalidValue)?,
649 },
650 authentication: authentication.ok_or(DecodeError::InvalidValue)?,
651 }))
652 }
653 }
654}
655
656pub(crate) const PAYMENT_PADDING_ROUND_OFF: usize = 30;
659
660pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
662 secp_ctx: &Secp256k1<T>, intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey,
663 payee_tlvs: ReceiveTlvs, session_priv: &SecretKey,
664) -> Vec<BlindedHop> {
665 let pks = intermediate_nodes
666 .iter()
667 .map(|node| (node.node_id, None))
668 .chain(core::iter::once((payee_node_id, None)));
669 let tlvs = intermediate_nodes
670 .iter()
671 .map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs))
672 .chain(core::iter::once(BlindedPaymentTlvsRef::Receive(&payee_tlvs)));
673
674 let path = pks.zip(
675 tlvs.map(|tlv| BlindedPathWithPadding { tlvs: tlv, round_off: PAYMENT_PADDING_ROUND_OFF }),
676 );
677
678 utils::construct_blinded_hops(secp_ctx, path, session_priv)
679}
680
681pub(crate) fn amt_to_forward_msat(
683 inbound_amt_msat: u64, payment_relay: &PaymentRelay,
684) -> Option<u64> {
685 let inbound_amt = inbound_amt_msat as u128;
686 let base = payment_relay.fee_base_msat as u128;
687 let prop = payment_relay.fee_proportional_millionths as u128;
688
689 let post_base_fee_inbound_amt =
690 if let Some(amt) = inbound_amt.checked_sub(base) { amt } else { return None };
691 let mut amt_to_forward =
692 (post_base_fee_inbound_amt * 1_000_000 + 1_000_000 + prop - 1) / (prop + 1_000_000);
693
694 let fee = ((amt_to_forward * prop) / 1_000_000) + base;
695 if inbound_amt - fee < amt_to_forward {
696 amt_to_forward -= 1;
699 }
700 debug_assert_eq!(amt_to_forward + fee, inbound_amt);
701 u64::try_from(amt_to_forward).ok()
702}
703
704pub(crate) fn compute_aggregated_base_prop_fee<I>(hops_fees: I) -> Result<(u64, u64), ()>
706where
707 I: DoubleEndedIterator<Item = RoutingFees>,
708{
709 let mut curr_base_fee: u64 = 0;
710 let mut curr_prop_mil: u64 = 0;
711 for fees in hops_fees.rev() {
712 let next_base_fee = fees.base_msat as u64;
713 let next_prop_mil = fees.proportional_millionths as u64;
714
715 curr_base_fee = curr_base_fee
718 .checked_mul(1_000_000 + next_prop_mil)
719 .and_then(|f| f.checked_add(1_000_000 - 1))
720 .map(|f| f / 1_000_000)
721 .and_then(|f| f.checked_add(next_base_fee))
722 .ok_or(())?;
723 curr_prop_mil = curr_prop_mil
725 .checked_add(1_000_000)
726 .and_then(|f1| next_prop_mil.checked_add(1_000_000).and_then(|f2| f2.checked_mul(f1)))
727 .and_then(|f| f.checked_add(1_000_000 - 1))
728 .map(|f| f / 1_000_000)
729 .and_then(|f| f.checked_sub(1_000_000))
730 .ok_or(())?;
731 }
732
733 Ok((curr_base_fee, curr_prop_mil))
734}
735
736pub(super) fn compute_payinfo(
737 intermediate_nodes: &[PaymentForwardNode], payee_tlvs: &UnauthenticatedReceiveTlvs,
738 payee_htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16,
739) -> Result<BlindedPayInfo, ()> {
740 let (aggregated_base_fee, aggregated_prop_fee) =
741 compute_aggregated_base_prop_fee(intermediate_nodes.iter().map(|node| RoutingFees {
742 base_msat: node.tlvs.payment_relay.fee_base_msat,
743 proportional_millionths: node.tlvs.payment_relay.fee_proportional_millionths,
744 }))?;
745
746 let mut htlc_minimum_msat: u64 = 1;
747 let mut htlc_maximum_msat: u64 = 21_000_000 * 100_000_000 * 1_000; let mut cltv_expiry_delta: u16 = min_final_cltv_expiry_delta;
749 for node in intermediate_nodes.iter() {
750 if node.tlvs.features.requires_unknown_bits_from(&BlindedHopFeatures::empty()) {
753 return Err(());
754 }
755
756 cltv_expiry_delta =
757 cltv_expiry_delta.checked_add(node.tlvs.payment_relay.cltv_expiry_delta).ok_or(())?;
758
759 htlc_minimum_msat = amt_to_forward_msat(
763 core::cmp::max(node.tlvs.payment_constraints.htlc_minimum_msat, htlc_minimum_msat),
764 &node.tlvs.payment_relay,
765 )
766 .unwrap_or(1); htlc_maximum_msat = amt_to_forward_msat(
768 core::cmp::min(node.htlc_maximum_msat, htlc_maximum_msat),
769 &node.tlvs.payment_relay,
770 )
771 .ok_or(())?; }
773 htlc_minimum_msat =
774 core::cmp::max(payee_tlvs.payment_constraints.htlc_minimum_msat, htlc_minimum_msat);
775 htlc_maximum_msat = core::cmp::min(payee_htlc_maximum_msat, htlc_maximum_msat);
776
777 if htlc_maximum_msat < htlc_minimum_msat {
778 return Err(());
779 }
780 Ok(BlindedPayInfo {
781 fee_base_msat: u32::try_from(aggregated_base_fee).map_err(|_| ())?,
782 fee_proportional_millionths: u32::try_from(aggregated_prop_fee).map_err(|_| ())?,
783 cltv_expiry_delta,
784 htlc_minimum_msat,
785 htlc_maximum_msat,
786 features: BlindedHopFeatures::empty(),
787 })
788}
789
790impl Writeable for PaymentRelay {
791 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
792 self.cltv_expiry_delta.write(w)?;
793 self.fee_proportional_millionths.write(w)?;
794 HighZeroBytesDroppedBigSize(self.fee_base_msat).write(w)
795 }
796}
797impl Readable for PaymentRelay {
798 fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
799 let cltv_expiry_delta: u16 = Readable::read(r)?;
800 let fee_proportional_millionths: u32 = Readable::read(r)?;
801 let fee_base_msat: HighZeroBytesDroppedBigSize<u32> = Readable::read(r)?;
802 Ok(Self { cltv_expiry_delta, fee_proportional_millionths, fee_base_msat: fee_base_msat.0 })
803 }
804}
805
806impl Writeable for PaymentConstraints {
807 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
808 self.max_cltv_expiry.write(w)?;
809 HighZeroBytesDroppedBigSize(self.htlc_minimum_msat).write(w)
810 }
811}
812impl Readable for PaymentConstraints {
813 fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
814 let max_cltv_expiry: u32 = Readable::read(r)?;
815 let htlc_minimum_msat: HighZeroBytesDroppedBigSize<u64> = Readable::read(r)?;
816 Ok(Self { max_cltv_expiry, htlc_minimum_msat: htlc_minimum_msat.0 })
817 }
818}
819
820impl_writeable_tlv_based_enum_legacy!(PaymentContext,
821 ;
822 (1, Bolt12Offer),
824 (2, Bolt12Refund),
825 (3, AsyncBolt12Offer),
826);
827
828impl<'a> Writeable for PaymentContextRef<'a> {
829 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
830 match self {
831 PaymentContextRef::Bolt12Offer(context) => {
832 1u8.write(w)?;
833 context.write(w)?;
834 },
835 PaymentContextRef::Bolt12Refund(context) => {
836 2u8.write(w)?;
837 context.write(w)?;
838 },
839 }
840
841 Ok(())
842 }
843}
844
845impl_writeable_tlv_based!(Bolt12OfferContext, {
846 (0, offer_id, required),
847 (2, invoice_request, required),
848});
849
850impl_writeable_tlv_based!(AsyncBolt12OfferContext, {
851 (0, offer_nonce, required),
852});
853
854impl_writeable_tlv_based!(Bolt12RefundContext, {});
855
856#[cfg(test)]
857mod tests {
858 use crate::blinded_path::payment::{
859 Bolt12RefundContext, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentForwardNode,
860 PaymentRelay, UnauthenticatedReceiveTlvs,
861 };
862 use crate::ln::functional_test_utils::TEST_FINAL_CLTV;
863 use crate::types::features::BlindedHopFeatures;
864 use crate::types::payment::PaymentSecret;
865 use bitcoin::secp256k1::PublicKey;
866
867 #[test]
868 fn compute_payinfo() {
869 let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
872 let intermediate_nodes = [
873 PaymentForwardNode {
874 node_id: dummy_pk,
875 tlvs: ForwardTlvs {
876 short_channel_id: 0,
877 payment_relay: PaymentRelay {
878 cltv_expiry_delta: 144,
879 fee_proportional_millionths: 500,
880 fee_base_msat: 100,
881 },
882 payment_constraints: PaymentConstraints {
883 max_cltv_expiry: 0,
884 htlc_minimum_msat: 100,
885 },
886 next_blinding_override: None,
887 features: BlindedHopFeatures::empty(),
888 },
889 htlc_maximum_msat: u64::max_value(),
890 },
891 PaymentForwardNode {
892 node_id: dummy_pk,
893 tlvs: ForwardTlvs {
894 short_channel_id: 0,
895 payment_relay: PaymentRelay {
896 cltv_expiry_delta: 144,
897 fee_proportional_millionths: 500,
898 fee_base_msat: 100,
899 },
900 payment_constraints: PaymentConstraints {
901 max_cltv_expiry: 0,
902 htlc_minimum_msat: 1_000,
903 },
904 next_blinding_override: None,
905 features: BlindedHopFeatures::empty(),
906 },
907 htlc_maximum_msat: u64::max_value(),
908 },
909 ];
910 let recv_tlvs = UnauthenticatedReceiveTlvs {
911 payment_secret: PaymentSecret([0; 32]),
912 payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 },
913 payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
914 };
915 let htlc_maximum_msat = 100_000;
916 let blinded_payinfo =
917 super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, 12)
918 .unwrap();
919 assert_eq!(blinded_payinfo.fee_base_msat, 201);
920 assert_eq!(blinded_payinfo.fee_proportional_millionths, 1001);
921 assert_eq!(blinded_payinfo.cltv_expiry_delta, 300);
922 assert_eq!(blinded_payinfo.htlc_minimum_msat, 900);
923 assert_eq!(blinded_payinfo.htlc_maximum_msat, htlc_maximum_msat);
924 }
925
926 #[test]
927 fn compute_payinfo_1_hop() {
928 let recv_tlvs = UnauthenticatedReceiveTlvs {
929 payment_secret: PaymentSecret([0; 32]),
930 payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 },
931 payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
932 };
933 let blinded_payinfo =
934 super::compute_payinfo(&[], &recv_tlvs, 4242, TEST_FINAL_CLTV as u16).unwrap();
935 assert_eq!(blinded_payinfo.fee_base_msat, 0);
936 assert_eq!(blinded_payinfo.fee_proportional_millionths, 0);
937 assert_eq!(blinded_payinfo.cltv_expiry_delta, TEST_FINAL_CLTV as u16);
938 assert_eq!(blinded_payinfo.htlc_minimum_msat, 1);
939 assert_eq!(blinded_payinfo.htlc_maximum_msat, 4242);
940 }
941
942 #[test]
943 fn simple_aggregated_htlc_min() {
944 let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
947 let intermediate_nodes = [
948 PaymentForwardNode {
949 node_id: dummy_pk,
950 tlvs: ForwardTlvs {
951 short_channel_id: 0,
952 payment_relay: PaymentRelay {
953 cltv_expiry_delta: 0,
954 fee_proportional_millionths: 0,
955 fee_base_msat: 0,
956 },
957 payment_constraints: PaymentConstraints {
958 max_cltv_expiry: 0,
959 htlc_minimum_msat: 1,
960 },
961 next_blinding_override: None,
962 features: BlindedHopFeatures::empty(),
963 },
964 htlc_maximum_msat: u64::max_value(),
965 },
966 PaymentForwardNode {
967 node_id: dummy_pk,
968 tlvs: ForwardTlvs {
969 short_channel_id: 0,
970 payment_relay: PaymentRelay {
971 cltv_expiry_delta: 0,
972 fee_proportional_millionths: 0,
973 fee_base_msat: 0,
974 },
975 payment_constraints: PaymentConstraints {
976 max_cltv_expiry: 0,
977 htlc_minimum_msat: 2_000,
978 },
979 next_blinding_override: None,
980 features: BlindedHopFeatures::empty(),
981 },
982 htlc_maximum_msat: u64::max_value(),
983 },
984 ];
985 let recv_tlvs = UnauthenticatedReceiveTlvs {
986 payment_secret: PaymentSecret([0; 32]),
987 payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 3 },
988 payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
989 };
990 let htlc_maximum_msat = 100_000;
991 let blinded_payinfo = super::compute_payinfo(
992 &intermediate_nodes[..],
993 &recv_tlvs,
994 htlc_maximum_msat,
995 TEST_FINAL_CLTV as u16,
996 )
997 .unwrap();
998 assert_eq!(blinded_payinfo.htlc_minimum_msat, 2_000);
999 }
1000
1001 #[test]
1002 fn aggregated_htlc_min() {
1003 let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
1006 let intermediate_nodes = [
1007 PaymentForwardNode {
1008 node_id: dummy_pk,
1009 tlvs: ForwardTlvs {
1010 short_channel_id: 0,
1011 payment_relay: PaymentRelay {
1012 cltv_expiry_delta: 0,
1013 fee_proportional_millionths: 500,
1014 fee_base_msat: 1_000,
1015 },
1016 payment_constraints: PaymentConstraints {
1017 max_cltv_expiry: 0,
1018 htlc_minimum_msat: 5_000,
1019 },
1020 next_blinding_override: None,
1021 features: BlindedHopFeatures::empty(),
1022 },
1023 htlc_maximum_msat: u64::max_value(),
1024 },
1025 PaymentForwardNode {
1026 node_id: dummy_pk,
1027 tlvs: ForwardTlvs {
1028 short_channel_id: 0,
1029 payment_relay: PaymentRelay {
1030 cltv_expiry_delta: 0,
1031 fee_proportional_millionths: 500,
1032 fee_base_msat: 200,
1033 },
1034 payment_constraints: PaymentConstraints {
1035 max_cltv_expiry: 0,
1036 htlc_minimum_msat: 2_000,
1037 },
1038 next_blinding_override: None,
1039 features: BlindedHopFeatures::empty(),
1040 },
1041 htlc_maximum_msat: u64::max_value(),
1042 },
1043 ];
1044 let recv_tlvs = UnauthenticatedReceiveTlvs {
1045 payment_secret: PaymentSecret([0; 32]),
1046 payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 },
1047 payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
1048 };
1049 let htlc_minimum_msat = 3798;
1050 assert!(super::compute_payinfo(
1051 &intermediate_nodes[..],
1052 &recv_tlvs,
1053 htlc_minimum_msat - 1,
1054 TEST_FINAL_CLTV as u16
1055 )
1056 .is_err());
1057
1058 let htlc_maximum_msat = htlc_minimum_msat + 1;
1059 let blinded_payinfo = super::compute_payinfo(
1060 &intermediate_nodes[..],
1061 &recv_tlvs,
1062 htlc_maximum_msat,
1063 TEST_FINAL_CLTV as u16,
1064 )
1065 .unwrap();
1066 assert_eq!(blinded_payinfo.htlc_minimum_msat, htlc_minimum_msat);
1067 assert_eq!(blinded_payinfo.htlc_maximum_msat, htlc_maximum_msat);
1068 }
1069
1070 #[test]
1071 fn aggregated_htlc_max() {
1072 let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
1075 let intermediate_nodes = [
1076 PaymentForwardNode {
1077 node_id: dummy_pk,
1078 tlvs: ForwardTlvs {
1079 short_channel_id: 0,
1080 payment_relay: PaymentRelay {
1081 cltv_expiry_delta: 0,
1082 fee_proportional_millionths: 500,
1083 fee_base_msat: 1_000,
1084 },
1085 payment_constraints: PaymentConstraints {
1086 max_cltv_expiry: 0,
1087 htlc_minimum_msat: 1,
1088 },
1089 next_blinding_override: None,
1090 features: BlindedHopFeatures::empty(),
1091 },
1092 htlc_maximum_msat: 5_000,
1093 },
1094 PaymentForwardNode {
1095 node_id: dummy_pk,
1096 tlvs: ForwardTlvs {
1097 short_channel_id: 0,
1098 payment_relay: PaymentRelay {
1099 cltv_expiry_delta: 0,
1100 fee_proportional_millionths: 500,
1101 fee_base_msat: 1,
1102 },
1103 payment_constraints: PaymentConstraints {
1104 max_cltv_expiry: 0,
1105 htlc_minimum_msat: 1,
1106 },
1107 next_blinding_override: None,
1108 features: BlindedHopFeatures::empty(),
1109 },
1110 htlc_maximum_msat: 10_000,
1111 },
1112 ];
1113 let recv_tlvs = UnauthenticatedReceiveTlvs {
1114 payment_secret: PaymentSecret([0; 32]),
1115 payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 },
1116 payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
1117 };
1118
1119 let blinded_payinfo = super::compute_payinfo(
1120 &intermediate_nodes[..],
1121 &recv_tlvs,
1122 10_000,
1123 TEST_FINAL_CLTV as u16,
1124 )
1125 .unwrap();
1126 assert_eq!(blinded_payinfo.htlc_maximum_msat, 3997);
1127 }
1128}