From 7038906890cd006021eab47601a3c23a3503bac2 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Mon, 19 Aug 2024 11:25:05 -0400 Subject: [PATCH] Move BlindedPayInfo into BlindedPaymentPath. Also removes the implementation of Writeable for BlindedPaymentPath, to ensure callsites are explicit about what they're writing. --- fuzz/src/chanmon_consistency.rs | 4 +- fuzz/src/full_stack.rs | 4 +- fuzz/src/router.rs | 8 +- lightning/src/blinded_path/mod.rs | 2 +- lightning/src/blinded_path/payment.rs | 83 +++---- lightning/src/ln/blinded_payment_tests.rs | 13 +- lightning/src/ln/channelmanager.rs | 4 +- .../src/ln/max_payment_path_len_tests.rs | 26 +-- lightning/src/ln/offers_tests.rs | 14 +- lightning/src/ln/onion_utils.rs | 3 +- lightning/src/ln/outbound_payment.rs | 2 +- lightning/src/offers/invoice.rs | 56 ++--- lightning/src/offers/invoice_macros.rs | 2 +- lightning/src/offers/invoice_request.rs | 11 +- lightning/src/offers/refund.rs | 9 +- lightning/src/offers/static_invoice.rs | 22 +- lightning/src/offers/test_utils.rs | 47 ++-- lightning/src/routing/router.rs | 202 +++++++++--------- lightning/src/util/ser.rs | 13 ++ lightning/src/util/test_utils.rs | 8 +- 20 files changed, 276 insertions(+), 257 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index a34df1d5a..84cc4bf26 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -56,7 +56,7 @@ use lightning::ln::msgs::{ }; use lightning::ln::script::ShutdownScript; use lightning::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret}; -use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice}; +use lightning::offers::invoice::UnsignedBolt12Invoice; use lightning::offers::invoice_request::UnsignedInvoiceRequest; use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath}; use lightning::routing::router::{InFlightHtlcs, Path, Route, RouteHop, RouteParameters, Router}; @@ -126,7 +126,7 @@ impl Router for FuzzRouter { fn create_blinded_payment_paths( &self, _recipient: PublicKey, _first_hops: Vec, _tlvs: ReceiveTlvs, _amount_msats: u64, _secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { unreachable!() } } diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 57aa0632b..90449248e 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -49,7 +49,7 @@ use lightning::ln::peer_handler::{ }; use lightning::ln::script::ShutdownScript; use lightning::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret}; -use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice}; +use lightning::offers::invoice::UnsignedBolt12Invoice; use lightning::offers::invoice_request::UnsignedInvoiceRequest; use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath}; use lightning::routing::gossip::{NetworkGraph, P2PGossipSync}; @@ -163,7 +163,7 @@ impl Router for FuzzRouter { fn create_blinded_payment_paths( &self, _recipient: PublicKey, _first_hops: Vec, _tlvs: ReceiveTlvs, _amount_msats: u64, _secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { unreachable!() } } diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs index 5aa029088..c315f58e2 100644 --- a/fuzz/src/router.rs +++ b/fuzz/src/router.rs @@ -381,7 +381,7 @@ pub fn do_test(data: &[u8], out: Out) { let mut last_hops_unblinded = Vec::new(); last_hops!(last_hops_unblinded); let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap(); - let last_hops: Vec<(BlindedPayInfo, BlindedPaymentPath)> = last_hops_unblinded + let last_hops: Vec = last_hops_unblinded .into_iter() .map(|hint| { let hop = &hint.0[0]; @@ -401,9 +401,11 @@ pub fn do_test(data: &[u8], out: Out) { encrypted_payload: Vec::new(), }); } - ( + BlindedPaymentPath::from_raw( + hop.src_node_id, + dummy_pk, + blinded_hops, payinfo, - BlindedPaymentPath::from_raw(hop.src_node_id, dummy_pk, blinded_hops), ) }) .collect(); diff --git a/lightning/src/blinded_path/mod.rs b/lightning/src/blinded_path/mod.rs index 70ee11617..168bc7174 100644 --- a/lightning/src/blinded_path/mod.rs +++ b/lightning/src/blinded_path/mod.rs @@ -26,7 +26,7 @@ use crate::prelude::*; /// Onion messages and payments can be sent and received to blinded paths, which serve to hide the /// identity of the recipient. #[derive(Clone, Debug, Hash, PartialEq, Eq)] -struct BlindedPath { +pub(crate) struct BlindedPath { /// To send to a blinded path, the sender first finds a route to the unblinded /// `introduction_node`, which can unblind its [`encrypted_payload`] to find out the onion /// message or payment's next hop and forward it along. diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index 70f2220dc..4c7066b9a 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -37,18 +37,10 @@ use crate::prelude::*; /// A blinded path to be used for sending or receiving a payment, hiding the identity of the /// recipient. #[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct BlindedPaymentPath(pub(super) BlindedPath); - -impl Writeable for BlindedPaymentPath { - fn write(&self, w: &mut W) -> Result<(), io::Error> { - self.0.write(w) - } -} - -impl Readable for BlindedPaymentPath { - fn read(r: &mut R) -> Result { - Ok(Self(BlindedPath::read(r)?)) - } +pub struct BlindedPaymentPath { + pub(super) inner_path: BlindedPath, + /// The [`BlindedPayInfo`] used to pay this blinded path. + pub payinfo: BlindedPayInfo, } impl BlindedPaymentPath { @@ -56,7 +48,7 @@ impl BlindedPaymentPath { pub fn one_hop( payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, min_final_cltv_expiry_delta: u16, entropy_source: ES, secp_ctx: &Secp256k1 - ) -> Result<(BlindedPayInfo, Self), ()> where ES::Target: EntropySource { + ) -> Result where ES::Target: EntropySource { // This value is not considered in pathfinding for 1-hop blinded paths, because it's intended to // be in relation to a specific channel. let htlc_maximum_msat = u64::max_value(); @@ -77,7 +69,7 @@ impl BlindedPaymentPath { intermediate_nodes: &[ForwardNode], payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16, entropy_source: ES, secp_ctx: &Secp256k1 - ) -> Result<(BlindedPayInfo, Self), ()> where ES::Target: EntropySource { + ) -> Result where ES::Target: EntropySource { let introduction_node = IntroductionNode::NodeId( intermediate_nodes.first().map_or(payee_node_id, |n| n.node_id) ); @@ -87,13 +79,16 @@ impl BlindedPaymentPath { let blinded_payinfo = compute_payinfo( intermediate_nodes, &payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta )?; - Ok((blinded_payinfo, Self(BlindedPath { - introduction_node, - blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret), - blinded_hops: blinded_hops( - secp_ctx, intermediate_nodes, payee_node_id, payee_tlvs, &blinding_secret - ).map_err(|_| ())?, - }))) + Ok(Self { + inner_path: BlindedPath { + introduction_node, + blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret), + blinded_hops: blinded_hops( + secp_ctx, intermediate_nodes, payee_node_id, payee_tlvs, &blinding_secret + ).map_err(|_| ())?, + }, + payinfo: blinded_payinfo + }) } /// Returns the introduction [`NodeId`] of the blinded path, if it is publicly reachable (i.e., @@ -101,24 +96,24 @@ impl BlindedPaymentPath { pub fn public_introduction_node_id<'a>( &self, network_graph: &'a ReadOnlyNetworkGraph ) -> Option<&'a NodeId> { - self.0.public_introduction_node_id(network_graph) + self.inner_path.public_introduction_node_id(network_graph) } /// The [`IntroductionNode`] of the blinded path. pub fn introduction_node(&self) -> &IntroductionNode { - &self.0.introduction_node + &self.inner_path.introduction_node } /// Used by the [`IntroductionNode`] to decrypt its [`encrypted_payload`] to forward the payment. /// /// [`encrypted_payload`]: BlindedHop::encrypted_payload pub fn blinding_point(&self) -> PublicKey { - self.0.blinding_point + self.inner_path.blinding_point } /// The [`BlindedHop`]s within the blinded path. pub fn blinded_hops(&self) -> &[BlindedHop] { - &self.0.blinded_hops + &self.inner_path.blinded_hops } /// Advance the blinded onion payment path by one hop, making the second hop into the new @@ -133,9 +128,9 @@ impl BlindedPaymentPath { NL::Target: NodeIdLookUp, T: secp256k1::Signing + secp256k1::Verification, { - let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.0.blinding_point, None)?; + let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.inner_path.blinding_point, None)?; let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes()); - let encrypted_control_tlvs = &self.0.blinded_hops.get(0).ok_or(())?.encrypted_payload; + let encrypted_control_tlvs = &self.inner_path.blinded_hops.get(0).ok_or(())?.encrypted_payload; let mut s = Cursor::new(encrypted_control_tlvs); let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64); match ChaChaPolyReadAdapter::read(&mut reader, rho) { @@ -147,31 +142,43 @@ impl BlindedPaymentPath { None => return Err(()), }; let mut new_blinding_point = onion_utils::next_hop_pubkey( - secp_ctx, self.0.blinding_point, control_tlvs_ss.as_ref() + secp_ctx, self.inner_path.blinding_point, control_tlvs_ss.as_ref() ).map_err(|_| ())?; - mem::swap(&mut self.0.blinding_point, &mut new_blinding_point); - self.0.introduction_node = IntroductionNode::NodeId(next_node_id); - self.0.blinded_hops.remove(0); + mem::swap(&mut self.inner_path.blinding_point, &mut new_blinding_point); + self.inner_path.introduction_node = IntroductionNode::NodeId(next_node_id); + self.inner_path.blinded_hops.remove(0); Ok(()) }, _ => Err(()) } } + pub(crate) fn inner_blinded_path(&self) -> &BlindedPath { + &self.inner_path + } + + pub(crate) fn from_parts(inner_path: BlindedPath, payinfo: BlindedPayInfo) -> Self { + Self { inner_path, payinfo } + } + #[cfg(any(test, fuzzing))] pub fn from_raw( - introduction_node_id: PublicKey, blinding_point: PublicKey, blinded_hops: Vec + introduction_node_id: PublicKey, blinding_point: PublicKey, blinded_hops: Vec, + payinfo: BlindedPayInfo ) -> Self { - Self(BlindedPath { - introduction_node: IntroductionNode::NodeId(introduction_node_id), - blinding_point, - blinded_hops, - }) + Self { + inner_path: BlindedPath { + introduction_node: IntroductionNode::NodeId(introduction_node_id), + blinding_point, + blinded_hops, + }, + payinfo + } } #[cfg(test)] pub fn clear_blinded_hops(&mut self) { - self.0.blinded_hops.clear() + self.inner_path.blinded_hops.clear() } } diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 12c0dc33a..eecbb9c4b 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -25,7 +25,7 @@ use crate::ln::onion_payment; use crate::ln::onion_utils; use crate::ln::onion_utils::INVALID_ONION_BLINDING; use crate::ln::outbound_payment::{Retry, IDEMPOTENCY_TIMEOUT_TICKS}; -use crate::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice}; +use crate::offers::invoice::UnsignedBolt12Invoice; use crate::offers::invoice_request::UnsignedInvoiceRequest; use crate::prelude::*; use crate::routing::router::{BlindedTail, Path, Payee, PaymentParameters, RouteHop, RouteParameters}; @@ -39,7 +39,7 @@ fn blinded_payment_path( payment_secret: PaymentSecret, intro_node_min_htlc: u64, intro_node_max_htlc: u64, node_ids: Vec, channel_upds: &[&msgs::UnsignedChannelUpdate], keys_manager: &test_utils::TestKeysInterface -) -> (BlindedPayInfo, BlindedPaymentPath) { +) -> BlindedPaymentPath { let mut intermediate_nodes = Vec::new(); let mut intro_node_min_htlc_opt = Some(intro_node_min_htlc); let mut intro_node_max_htlc_opt = Some(intro_node_max_htlc); @@ -839,11 +839,12 @@ fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) { nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(), &[&high_htlc_minimum_upd], &chanmon_cfgs[2].keys_manager); if let Payee::Blinded { route_hints, .. } = high_htlc_min_params.payment_params.payee { - route_hints[0].1.clone() + route_hints[0].clone() } else { panic!() } }; if let Payee::Blinded { ref mut route_hints, .. } = route_params.payment_params.payee { - route_hints[0].1 = high_htlc_min_bp; + route_hints[0] = high_htlc_min_bp; + route_hints[0].payinfo.htlc_minimum_msat = amt_msat; } else { panic!() } find_route(&nodes[0], &route_params).unwrap() } else { @@ -1121,7 +1122,7 @@ fn min_htlc() { nodes[2].node.get_our_node_id(), nodes[3].node.get_our_node_id()], &[&chan_1_2.0.contents, &chan_2_3.0.contents], &chanmon_cfgs[3].keys_manager); assert_eq!(min_htlc_msat, - route_params.payment_params.payee.blinded_route_hints()[0].0.htlc_minimum_msat); + route_params.payment_params.payee.blinded_route_hints()[0].payinfo.htlc_minimum_msat); nodes[0].node.send_payment(payment_hash, RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap(); check_added_monitors(&nodes[0], 1); @@ -1133,7 +1134,7 @@ fn min_htlc() { nodes[0].node.timer_tick_occurred(); } if let Payee::Blinded { ref mut route_hints, .. } = route_params.payment_params.payee { - route_hints[0].0.htlc_minimum_msat -= 1; + route_hints[0].payinfo.htlc_minimum_msat -= 1; } else { panic!() } route_params.final_value_msat -= 1; nodes[0].node.send_payment(payment_hash, RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap(); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index f49d8b639..167ab0ac8 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -62,7 +62,7 @@ use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError}; use crate::ln::outbound_payment; use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment, SendAlongPathArgs, StaleExpiration}; use crate::ln::wire::Encode; -use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice}; +use crate::offers::invoice::{Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice}; use crate::offers::invoice_error::InvoiceError; use crate::offers::invoice_request::{DerivedPayerId, InvoiceRequestBuilder}; use crate::offers::nonce::Nonce; @@ -9373,7 +9373,7 @@ where /// [`Router::create_blinded_payment_paths`]. fn create_blinded_payment_paths( &self, amount_msats: u64, payment_secret: PaymentSecret, payment_context: PaymentContext - ) -> Result, ()> { + ) -> Result, ()> { let secp_ctx = &self.secp_ctx; let first_hops = self.list_usable_channels(); diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index 8e5edd4e9..a22d7d164 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -182,8 +182,8 @@ fn one_hop_blinded_path_with_custom_tlv() { sender_intended_htlc_amt_msat: MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, total_msat: MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, cltv_expiry_height: nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, - encrypted_tlvs: &blinded_path.1.blinded_hops()[0].encrypted_payload, - intro_node_blinding_point: Some(blinded_path.1.blinding_point()), + encrypted_tlvs: &blinded_path.blinded_hops()[0].encrypted_payload, + intro_node_blinding_point: Some(blinded_path.blinding_point()), keysend_preimage: None, custom_tlvs: &Vec::new() }.serialized_length(); @@ -354,15 +354,7 @@ fn bolt12_invoice_too_large_blinded_paths() { let nodes = create_network(2, &node_cfgs, &node_chanmgrs); create_announced_chan_between_nodes(&nodes, 0, 1); - nodes[1].router.expect_blinded_payment_paths(vec![( - BlindedPayInfo { - fee_base_msat: 42, - fee_proportional_millionths: 42, - cltv_expiry_delta: 42, - htlc_minimum_msat: 42, - htlc_maximum_msat: 42_000_000, - features: BlindedHopFeatures::empty(), - }, + nodes[1].router.expect_blinded_payment_paths(vec![ BlindedPaymentPath::from_raw( PublicKey::from_slice(&[2; 33]).unwrap(), PublicKey::from_slice(&[2; 33]).unwrap(), vec![ @@ -374,9 +366,17 @@ fn bolt12_invoice_too_large_blinded_paths() { blinded_node_id: PublicKey::from_slice(&[2; 33]).unwrap(), encrypted_payload: vec![42; 1300], }, - ] + ], + BlindedPayInfo { + fee_base_msat: 42, + fee_proportional_millionths: 42, + cltv_expiry_delta: 42, + htlc_minimum_msat: 42, + htlc_maximum_msat: 42_000_000, + features: BlindedHopFeatures::empty(), + } ) - )]); + ]); let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap(); let payment_id = PaymentId([1; 32]); diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 8edeefcf8..b1c09fd54 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -584,7 +584,7 @@ fn creates_and_pays_for_offer_using_two_hop_blinded_path() { assert_eq!(invoice.amount_msats(), 10_000_000); assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); - for (_, path) in invoice.payment_paths() { + for path in invoice.payment_paths() { assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } @@ -665,7 +665,7 @@ fn creates_and_pays_for_refund_using_two_hop_blinded_path() { assert_eq!(invoice.amount_msats(), 10_000_000); assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); - for (_, path) in invoice.payment_paths() { + for path in invoice.payment_paths() { assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } @@ -730,7 +730,7 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() { assert_eq!(invoice.amount_msats(), 10_000_000); assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); - for (_, path) in invoice.payment_paths() { + for path in invoice.payment_paths() { assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } @@ -785,7 +785,7 @@ fn creates_and_pays_for_refund_using_one_hop_blinded_path() { assert_eq!(invoice.amount_msats(), 10_000_000); assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); - for (_, path) in invoice.payment_paths() { + for path in invoice.payment_paths() { assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } @@ -1109,7 +1109,7 @@ fn pays_bolt12_invoice_asynchronously() { assert_eq!(invoice.amount_msats(), 10_000_000); assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); - for (_, path) in invoice.payment_paths() { + for path in invoice.payment_paths() { assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } @@ -1193,7 +1193,7 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() { let (invoice, _) = extract_invoice(bob, &onion_message); assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); - for (_, path) in invoice.payment_paths() { + for path in invoice.payment_paths() { assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } @@ -1243,7 +1243,7 @@ fn creates_refund_with_blinded_path_using_unannounced_introduction_node() { assert_eq!(invoice, expected_invoice); assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); - for (_, path) in invoice.payment_paths() { + for path in invoice.payment_paths() { assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } } diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index a3372dda8..5ad684076 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -337,8 +337,7 @@ pub(crate) fn set_max_path_length( .payee .blinded_route_hints() .iter() - .map(|(_, path)| path) - .max_by_key(|path| path.serialized_length()) + .max_by_key(|path| path.inner_blinded_path().serialized_length()) .map(|largest_path| BlindedTailHopIter { hops: largest_path.blinded_hops().iter(), blinding_point: largest_path.blinding_point(), diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index aff236777..1fda94337 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -833,7 +833,7 @@ impl OutboundPayments { // Advance any blinded path where the introduction node is our node. if let Ok(our_node_id) = node_signer.get_node_id(Recipient::Node) { - for (_, path) in payment_params.payee.blinded_route_hints_mut().iter_mut() { + for path in payment_params.payee.blinded_route_hints_mut().iter_mut() { let introduction_node_id = match path.introduction_node() { IntroductionNode::NodeId(pubkey) => *pubkey, IntroductionNode::DirectedShortChannelId(direction, scid) => { diff --git a/lightning/src/offers/invoice.rs b/lightning/src/offers/invoice.rs index 3c2c2cb99..693e8e00f 100644 --- a/lightning/src/offers/invoice.rs +++ b/lightning/src/offers/invoice.rs @@ -32,7 +32,7 @@ //! # use lightning::offers::invoice::{BlindedPayInfo, ExplicitSigningPubkey, InvoiceBuilder}; //! # use lightning::blinded_path::payment::BlindedPaymentPath; //! # -//! # fn create_payment_paths() -> Vec<(BlindedPayInfo, BlindedPaymentPath)> { unimplemented!() } +//! # fn create_payment_paths() -> Vec { unimplemented!() } //! # fn create_payment_hash() -> PaymentHash { unimplemented!() } //! # //! # fn parse_invoice_request(bytes: Vec) -> Result<(), lightning::offers::parse::Bolt12ParseError> { @@ -110,6 +110,7 @@ use bitcoin::address::Address; use core::time::Duration; use core::hash::{Hash, Hasher}; use crate::io; +use crate::blinded_path::BlindedPath; use crate::blinded_path::message::BlindedMessagePath; use crate::blinded_path::payment::BlindedPaymentPath; use crate::ln::types::PaymentHash; @@ -212,7 +213,7 @@ impl SigningPubkeyStrategy for DerivedSigningPubkey {} macro_rules! invoice_explicit_signing_pubkey_builder_methods { ($self: ident, $self_type: ty) => { #[cfg_attr(c_bindings, allow(dead_code))] pub(super) fn for_offer( - invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, + invoice_request: &'a InvoiceRequest, payment_paths: Vec, created_at: Duration, payment_hash: PaymentHash, signing_pubkey: PublicKey ) -> Result { let amount_msats = Self::amount_msats(invoice_request)?; @@ -228,7 +229,7 @@ macro_rules! invoice_explicit_signing_pubkey_builder_methods { ($self: ident, $s #[cfg_attr(c_bindings, allow(dead_code))] pub(super) fn for_refund( - refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration, + refund: &'a Refund, payment_paths: Vec, created_at: Duration, payment_hash: PaymentHash, signing_pubkey: PublicKey ) -> Result { let amount_msats = refund.amount_msats(); @@ -270,7 +271,7 @@ macro_rules! invoice_explicit_signing_pubkey_builder_methods { ($self: ident, $s macro_rules! invoice_derived_signing_pubkey_builder_methods { ($self: ident, $self_type: ty) => { #[cfg_attr(c_bindings, allow(dead_code))] pub(super) fn for_offer_using_keys( - invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, + invoice_request: &'a InvoiceRequest, payment_paths: Vec, created_at: Duration, payment_hash: PaymentHash, keys: Keypair ) -> Result { let amount_msats = Self::amount_msats(invoice_request)?; @@ -287,7 +288,7 @@ macro_rules! invoice_derived_signing_pubkey_builder_methods { ($self: ident, $se #[cfg_attr(c_bindings, allow(dead_code))] pub(super) fn for_refund_using_keys( - refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration, + refund: &'a Refund, payment_paths: Vec, created_at: Duration, payment_hash: PaymentHash, keys: Keypair, ) -> Result { let amount_msats = refund.amount_msats(); @@ -356,8 +357,8 @@ macro_rules! invoice_builder_methods { ( #[cfg_attr(c_bindings, allow(dead_code))] fn fields( - payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration, - payment_hash: PaymentHash, amount_msats: u64, signing_pubkey: PublicKey + payment_paths: Vec, created_at: Duration, payment_hash: PaymentHash, + amount_msats: u64, signing_pubkey: PublicKey ) -> InvoiceFields { InvoiceFields { payment_paths, created_at, relative_expiry: None, payment_hash, amount_msats, @@ -603,7 +604,7 @@ enum InvoiceContents { /// Invoice-specific fields for an `invoice` message. #[derive(Clone, Debug, PartialEq)] struct InvoiceFields { - payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, + payment_paths: Vec, created_at: Duration, relative_expiry: Option, payment_hash: PaymentHash, @@ -988,7 +989,7 @@ impl InvoiceContents { } } - fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPaymentPath)] { + fn payment_paths(&self) -> &[BlindedPaymentPath] { &self.fields().payment_paths[..] } @@ -1124,8 +1125,8 @@ impl InvoiceFields { }; InvoiceTlvStreamRef { - paths: Some(Iterable(self.payment_paths.iter().map(|(_, path)| path))), - blindedpay: Some(Iterable(self.payment_paths.iter().map(|(payinfo, _)| payinfo))), + paths: Some(Iterable(self.payment_paths.iter().map(|path| path.inner_blinded_path()))), + blindedpay: Some(Iterable(self.payment_paths.iter().map(|path| &path.payinfo))), created_at: Some(self.created_at.as_secs()), relative_expiry: self.relative_expiry.map(|duration| duration.as_secs() as u32), payment_hash: Some(&self.payment_hash), @@ -1192,7 +1193,7 @@ impl TryFrom> for Bolt12Invoice { } tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef, 160..240, { - (160, paths: (Vec, WithoutLength, Iterable<'a, BlindedPathIter<'a>, BlindedPaymentPath>)), + (160, paths: (Vec, WithoutLength, Iterable<'a, BlindedPathIter<'a>, BlindedPath>)), (162, blindedpay: (Vec, WithoutLength, Iterable<'a, BlindedPayInfoIter<'a>, BlindedPayInfo>)), (164, created_at: (u64, HighZeroBytesDroppedBigSize)), (166, relative_expiry: (u32, HighZeroBytesDroppedBigSize)), @@ -1206,13 +1207,13 @@ tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef, 160..240, { }); pub(super) type BlindedPathIter<'a> = core::iter::Map< - core::slice::Iter<'a, (BlindedPayInfo, BlindedPaymentPath)>, - for<'r> fn(&'r (BlindedPayInfo, BlindedPaymentPath)) -> &'r BlindedPaymentPath, + core::slice::Iter<'a, BlindedPaymentPath>, + for<'r> fn(&'r BlindedPaymentPath) -> &'r BlindedPath, >; pub(super) type BlindedPayInfoIter<'a> = core::iter::Map< - core::slice::Iter<'a, (BlindedPayInfo, BlindedPaymentPath)>, - for<'r> fn(&'r (BlindedPayInfo, BlindedPaymentPath)) -> &'r BlindedPayInfo, + core::slice::Iter<'a, BlindedPaymentPath>, + for<'r> fn(&'r BlindedPaymentPath) -> &'r BlindedPayInfo, >; /// Information needed to route a payment across a [`BlindedPaymentPath`]. @@ -1387,8 +1388,8 @@ impl TryFrom for InvoiceContents { } pub(super) fn construct_payment_paths( - blinded_payinfos: Option>, blinded_paths: Option> -) -> Result, Bolt12SemanticError> { + blinded_payinfos: Option>, blinded_paths: Option> +) -> Result, Bolt12SemanticError> { match (blinded_payinfos, blinded_paths) { (_, None) => Err(Bolt12SemanticError::MissingPaths), (None, _) => Err(Bolt12SemanticError::InvalidPayInfo), @@ -1397,7 +1398,12 @@ pub(super) fn construct_payment_paths( Err(Bolt12SemanticError::InvalidPayInfo) }, (Some(blindedpay), Some(paths)) => { - Ok(blindedpay.into_iter().zip(paths.into_iter()).collect::>()) + Ok(blindedpay + .into_iter() + .zip(paths.into_iter()) + .map(|(payinfo, path)| BlindedPaymentPath::from_parts(path, payinfo)) + .collect::>() + ) }, } } @@ -1605,8 +1611,8 @@ mod tests { paths: None, }, InvoiceTlvStreamRef { - paths: Some(Iterable(payment_paths.iter().map(|(_, path)| path))), - blindedpay: Some(Iterable(payment_paths.iter().map(|(payinfo, _)| payinfo))), + paths: Some(Iterable(payment_paths.iter().map(|path| path.inner_blinded_path()))), + blindedpay: Some(Iterable(payment_paths.iter().map(|path| &path.payinfo))), created_at: Some(now.as_secs()), relative_expiry: None, payment_hash: Some(&payment_hash), @@ -1698,8 +1704,8 @@ mod tests { paths: None, }, InvoiceTlvStreamRef { - paths: Some(Iterable(payment_paths.iter().map(|(_, path)| path))), - blindedpay: Some(Iterable(payment_paths.iter().map(|(payinfo, _)| payinfo))), + paths: Some(Iterable(payment_paths.iter().map(|path| path.inner_blinded_path()))), + blindedpay: Some(Iterable(payment_paths.iter().map(|path| &path.payinfo))), created_at: Some(now.as_secs()), relative_expiry: None, payment_hash: Some(&payment_hash), @@ -2110,7 +2116,7 @@ mod tests { let empty_payment_paths = vec![]; let mut tlv_stream = invoice.as_tlv_stream(); - tlv_stream.3.paths = Some(Iterable(empty_payment_paths.iter().map(|(_, path)| path))); + tlv_stream.3.paths = Some(Iterable(empty_payment_paths.iter().map(|path| path.inner_blinded_path()))); match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), @@ -2120,7 +2126,7 @@ mod tests { let mut payment_paths = payment_paths(); payment_paths.pop(); let mut tlv_stream = invoice.as_tlv_stream(); - tlv_stream.3.blindedpay = Some(Iterable(payment_paths.iter().map(|(payinfo, _)| payinfo))); + tlv_stream.3.blindedpay = Some(Iterable(payment_paths.iter().map(|path| &path.payinfo))); match Bolt12Invoice::try_from(tlv_stream.to_bytes()) { Ok(_) => panic!("expected error"), diff --git a/lightning/src/offers/invoice_macros.rs b/lightning/src/offers/invoice_macros.rs index a06c0663a..3037ccfa8 100644 --- a/lightning/src/offers/invoice_macros.rs +++ b/lightning/src/offers/invoice_macros.rs @@ -107,7 +107,7 @@ macro_rules! invoice_accessors_common { ($self: ident, $contents: expr, $invoice /// /// This is not exported to bindings users as slices with non-reference types cannot be ABI /// matched in another language. - pub fn payment_paths(&$self) -> &[(BlindedPayInfo, BlindedPaymentPath)] { + pub fn payment_paths(&$self) -> &[BlindedPaymentPath] { $contents.payment_paths() } diff --git a/lightning/src/offers/invoice_request.rs b/lightning/src/offers/invoice_request.rs index a021a1a3a..fa3d9161b 100644 --- a/lightning/src/offers/invoice_request.rs +++ b/lightning/src/offers/invoice_request.rs @@ -69,7 +69,6 @@ use crate::ln::channelmanager::PaymentId; use crate::ln::features::InvoiceRequestFeatures; use crate::ln::inbound_payment::{ExpandedKey, IV_LEN}; use crate::ln::msgs::DecodeError; -use crate::offers::invoice::BlindedPayInfo; use crate::offers::merkle::{SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, self}; use crate::offers::nonce::Nonce; use crate::offers::offer::{Offer, OfferContents, OfferId, OfferTlvStream, OfferTlvStreamRef}; @@ -708,7 +707,7 @@ macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { ( /// [`Duration`]: core::time::Duration #[cfg(feature = "std")] pub fn respond_with( - &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash + &$self, payment_paths: Vec, payment_hash: PaymentHash ) -> Result<$builder, Bolt12SemanticError> { let created_at = std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) @@ -743,7 +742,7 @@ macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { ( /// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at /// [`OfferBuilder::deriving_signing_pubkey`]: crate::offers::offer::OfferBuilder::deriving_signing_pubkey pub fn respond_with_no_std( - &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec, payment_hash: PaymentHash, created_at: core::time::Duration ) -> Result<$builder, Bolt12SemanticError> { if $contents.invoice_request_features().requires_unknown_bits() { @@ -761,7 +760,7 @@ macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { ( #[cfg(test)] #[allow(dead_code)] pub(super) fn respond_with_no_std_using_signing_pubkey( - &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec, payment_hash: PaymentHash, created_at: core::time::Duration, signing_pubkey: PublicKey ) -> Result<$builder, Bolt12SemanticError> { debug_assert!($contents.contents.inner.offer.signing_pubkey().is_none()); @@ -881,7 +880,7 @@ macro_rules! invoice_request_respond_with_derived_signing_pubkey_methods { ( /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice #[cfg(feature = "std")] pub fn respond_using_derived_keys( - &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash + &$self, payment_paths: Vec, payment_hash: PaymentHash ) -> Result<$builder, Bolt12SemanticError> { let created_at = std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) @@ -898,7 +897,7 @@ macro_rules! invoice_request_respond_with_derived_signing_pubkey_methods { ( /// /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice pub fn respond_using_derived_keys_no_std( - &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec, payment_hash: PaymentHash, created_at: core::time::Duration ) -> Result<$builder, Bolt12SemanticError> { if $self.inner.invoice_request_features().requires_unknown_bits() { diff --git a/lightning/src/offers/refund.rs b/lightning/src/offers/refund.rs index 3dba3637d..c07055c5c 100644 --- a/lightning/src/offers/refund.rs +++ b/lightning/src/offers/refund.rs @@ -98,7 +98,6 @@ use crate::ln::channelmanager::PaymentId; use crate::ln::features::InvoiceRequestFeatures; use crate::ln::inbound_payment::{ExpandedKey, IV_LEN}; use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; -use crate::offers::invoice::BlindedPayInfo; use crate::offers::invoice_request::{InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef}; use crate::offers::nonce::Nonce; use crate::offers::offer::{OfferTlvStream, OfferTlvStreamRef}; @@ -533,7 +532,7 @@ macro_rules! respond_with_explicit_signing_pubkey_methods { ($self: ident, $buil /// [`Duration`]: core::time::Duration #[cfg(feature = "std")] pub fn respond_with( - &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec, payment_hash: PaymentHash, signing_pubkey: PublicKey, ) -> Result<$builder, Bolt12SemanticError> { let created_at = std::time::SystemTime::now() @@ -566,7 +565,7 @@ macro_rules! respond_with_explicit_signing_pubkey_methods { ($self: ident, $buil /// /// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at pub fn respond_with_no_std( - &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec, payment_hash: PaymentHash, signing_pubkey: PublicKey, created_at: Duration ) -> Result<$builder, Bolt12SemanticError> { if $self.features().requires_unknown_bits() { @@ -588,7 +587,7 @@ macro_rules! respond_with_derived_signing_pubkey_methods { ($self: ident, $build /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice #[cfg(feature = "std")] pub fn respond_using_derived_keys( - &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec, payment_hash: PaymentHash, expanded_key: &ExpandedKey, entropy_source: ES ) -> Result<$builder, Bolt12SemanticError> where @@ -612,7 +611,7 @@ macro_rules! respond_with_derived_signing_pubkey_methods { ($self: ident, $build /// /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice pub fn respond_using_derived_keys_no_std( - &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec, payment_hash: PaymentHash, created_at: core::time::Duration, expanded_key: &ExpandedKey, entropy_source: ES ) -> Result<$builder, Bolt12SemanticError> where diff --git a/lightning/src/offers/static_invoice.rs b/lightning/src/offers/static_invoice.rs index 63b32ccf3..33706f928 100644 --- a/lightning/src/offers/static_invoice.rs +++ b/lightning/src/offers/static_invoice.rs @@ -16,8 +16,8 @@ use crate::ln::features::{Bolt12InvoiceFeatures, OfferFeatures}; use crate::ln::inbound_payment::ExpandedKey; use crate::ln::msgs::DecodeError; use crate::offers::invoice::{ - check_invoice_signing_pubkey, construct_payment_paths, filter_fallbacks, BlindedPayInfo, - FallbackAddress, InvoiceTlvStream, InvoiceTlvStreamRef, + check_invoice_signing_pubkey, construct_payment_paths, filter_fallbacks, FallbackAddress, + InvoiceTlvStream, InvoiceTlvStreamRef, }; use crate::offers::invoice_macros::{invoice_accessors_common, invoice_builder_methods_common}; use crate::offers::merkle::{ @@ -71,7 +71,7 @@ pub struct StaticInvoice { #[derive(Clone, Debug)] struct InvoiceContents { offer: OfferContents, - payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, + payment_paths: Vec, created_at: Duration, relative_expiry: Option, fallbacks: Option>, @@ -97,7 +97,7 @@ impl<'a> StaticInvoiceBuilder<'a> { /// Unless [`StaticInvoiceBuilder::relative_expiry`] is set, the invoice will expire 24 hours /// after `created_at`. pub fn for_offer_using_derived_keys( - offer: &'a Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, + offer: &'a Offer, payment_paths: Vec, message_paths: Vec, created_at: Duration, expanded_key: &ExpandedKey, nonce: Nonce, secp_ctx: &Secp256k1, ) -> Result { @@ -326,7 +326,7 @@ impl InvoiceContents { } fn new( - offer: &Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, + offer: &Offer, payment_paths: Vec, message_paths: Vec, created_at: Duration, signing_pubkey: PublicKey, ) -> Self { Self { @@ -351,9 +351,9 @@ impl InvoiceContents { }; let invoice = InvoiceTlvStreamRef { - paths: Some(Iterable(self.payment_paths.iter().map(|(_, path)| path))), + paths: Some(Iterable(self.payment_paths.iter().map(|path| path.inner_blinded_path()))), message_paths: Some(self.message_paths.as_ref()), - blindedpay: Some(Iterable(self.payment_paths.iter().map(|(payinfo, _)| payinfo))), + blindedpay: Some(Iterable(self.payment_paths.iter().map(|path| &path.payinfo))), created_at: Some(self.created_at.as_secs()), relative_expiry: self.relative_expiry.map(|duration| duration.as_secs() as u32), fallbacks: self.fallbacks.as_ref(), @@ -407,7 +407,7 @@ impl InvoiceContents { self.offer.supported_quantity() } - fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPaymentPath)] { + fn payment_paths(&self) -> &[BlindedPaymentPath] { &self.payment_paths[..] } @@ -720,8 +720,10 @@ mod tests { node_id: Some(&offer_signing_pubkey), }, InvoiceTlvStreamRef { - paths: Some(Iterable(payment_paths.iter().map(|(_, path)| path))), - blindedpay: Some(Iterable(payment_paths.iter().map(|(payinfo, _)| payinfo))), + paths: Some(Iterable( + payment_paths.iter().map(|path| path.inner_blinded_path()) + )), + blindedpay: Some(Iterable(payment_paths.iter().map(|path| &path.payinfo))), created_at: Some(now.as_secs()), relative_expiry: None, payment_hash: None, diff --git a/lightning/src/offers/test_utils.rs b/lightning/src/offers/test_utils.rs index 588c167bf..d815338d7 100644 --- a/lightning/src/offers/test_utils.rs +++ b/lightning/src/offers/test_utils.rs @@ -67,44 +67,39 @@ pub(super) fn privkey(byte: u8) -> SecretKey { SecretKey::from_slice(&[byte; 32]).unwrap() } -pub(crate) fn payment_paths() -> Vec<(BlindedPayInfo, BlindedPaymentPath)> { - let paths = vec![ +pub(crate) fn payment_paths() -> Vec { + vec![ BlindedPaymentPath::from_raw( pubkey(40), pubkey(41), vec![ BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 43] }, BlindedHop { blinded_node_id: pubkey(44), encrypted_payload: vec![0; 44] }, - ] + ], + BlindedPayInfo { + fee_base_msat: 1, + fee_proportional_millionths: 1_000, + cltv_expiry_delta: 42, + htlc_minimum_msat: 100, + htlc_maximum_msat: 1_000_000_000_000, + features: BlindedHopFeatures::empty(), + }, ), BlindedPaymentPath::from_raw( pubkey(40), pubkey(41), vec![ BlindedHop { blinded_node_id: pubkey(45), encrypted_payload: vec![0; 45] }, BlindedHop { blinded_node_id: pubkey(46), encrypted_payload: vec![0; 46] }, - ] + ], + BlindedPayInfo { + fee_base_msat: 1, + fee_proportional_millionths: 1_000, + cltv_expiry_delta: 42, + htlc_minimum_msat: 100, + htlc_maximum_msat: 1_000_000_000_000, + features: BlindedHopFeatures::empty(), + }, ), - ]; - - let payinfo = vec![ - BlindedPayInfo { - fee_base_msat: 1, - fee_proportional_millionths: 1_000, - cltv_expiry_delta: 42, - htlc_minimum_msat: 100, - htlc_maximum_msat: 1_000_000_000_000, - features: BlindedHopFeatures::empty(), - }, - BlindedPayInfo { - fee_base_msat: 1, - fee_proportional_millionths: 1_000, - cltv_expiry_delta: 42, - htlc_minimum_msat: 100, - htlc_maximum_msat: 1_000_000_000_000, - features: BlindedHopFeatures::empty(), - }, - ]; - - payinfo.into_iter().zip(paths.into_iter()).collect() + ] } pub(crate) fn payment_hash() -> PaymentHash { diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 439838832..495ff30a9 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -20,7 +20,7 @@ use crate::ln::channelmanager::{PaymentId, MIN_FINAL_CLTV_EXPIRY_DELTA, Recipien use crate::ln::features::{BlindedHopFeatures, Bolt11InvoiceFeatures, Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures}; use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT}; use crate::ln::onion_utils; -use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice}; +use crate::offers::invoice::Bolt12Invoice; use crate::onion_message::messenger::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath}; use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId}; use crate::routing::scoring::{ChannelUsage, LockableScore, ScoreLookUp}; @@ -94,7 +94,7 @@ impl>, L: Deref, ES: Deref, S: Deref, SP: Size > ( &self, recipient: PublicKey, first_hops: Vec, tlvs: ReceiveTlvs, amount_msats: u64, secp_ctx: &Secp256k1 - ) -> Result, ()> { + ) -> Result, ()> { // Limit the number of blinded paths that are computed. const MAX_PAYMENT_PATHS: usize = 3; @@ -245,7 +245,7 @@ pub trait Router: MessageRouter { > ( &self, recipient: PublicKey, first_hops: Vec, tlvs: ReceiveTlvs, amount_msats: u64, secp_ctx: &Secp256k1 - ) -> Result, ()>; + ) -> Result, ()>; } /// [`ScoreLookUp`] implementation that factors in in-flight HTLC liquidity. @@ -759,10 +759,13 @@ pub struct PaymentParameters { impl Writeable for PaymentParameters { fn write(&self, writer: &mut W) -> Result<(), io::Error> { let mut clear_hints = &vec![]; - let mut blinded_hints = &vec![]; + let mut blinded_hints = None; match &self.payee { Payee::Clear { route_hints, .. } => clear_hints = route_hints, - Payee::Blinded { route_hints, .. } => blinded_hints = route_hints, + Payee::Blinded { route_hints, .. } => { + let hints_iter = route_hints.iter().map(|path| (&path.payinfo, path.inner_blinded_path())); + blinded_hints = Some(crate::util::ser::IterableOwned(hints_iter)); + } } write_tlv_fields!(writer, { (0, self.payee.node_id(), option), @@ -773,7 +776,7 @@ impl Writeable for PaymentParameters { (5, self.max_channel_saturation_power_of_half, required), (6, self.expiry_time, option), (7, self.previously_failed_channels, required_vec), - (8, *blinded_hints, optional_vec), + (8, blinded_hints, option), (9, self.payee.final_cltv_expiry_delta(), option), (11, self.previously_failed_blinded_path_idxs, required_vec), (13, self.max_path_length, required), @@ -802,7 +805,10 @@ impl ReadableArgs for PaymentParameters { let payee = if blinded_route_hints.len() != 0 { if clear_route_hints.len() != 0 || payee_pubkey.is_some() { return Err(DecodeError::InvalidValue) } Payee::Blinded { - route_hints: blinded_route_hints, + route_hints: blinded_route_hints + .into_iter() + .map(|(payinfo, path)| BlindedPaymentPath::from_parts(path, payinfo)) + .collect(), features: features.and_then(|f: Features| f.bolt12()), } } else { @@ -872,7 +878,7 @@ impl PaymentParameters { } /// Creates parameters for paying to a blinded payee from the provided blinded route hints. - pub fn blinded(blinded_route_hints: Vec<(BlindedPayInfo, BlindedPaymentPath)>) -> Self { + pub fn blinded(blinded_route_hints: Vec) -> Self { Self { payee: Payee::Blinded { route_hints: blinded_route_hints, features: None }, expiry_time: None, @@ -960,7 +966,7 @@ impl PaymentParameters { pub(crate) fn insert_previously_failed_blinded_path(&mut self, failed_blinded_tail: &BlindedTail) { let mut found_blinded_tail = false; - for (idx, (_, path)) in self.payee.blinded_route_hints().iter().enumerate() { + for (idx, path) in self.payee.blinded_route_hints().iter().enumerate() { if &failed_blinded_tail.hops == path.blinded_hops() && failed_blinded_tail.blinding_point == path.blinding_point() { @@ -981,7 +987,7 @@ pub enum Payee { Blinded { /// Aggregated routing info and blinded paths, for routing to the payee without knowing their /// node id. - route_hints: Vec<(BlindedPayInfo, BlindedPaymentPath)>, + route_hints: Vec, /// Features supported by the payee. /// /// May be set from the payee's invoice. May be `None` if the invoice does not contain any @@ -1037,14 +1043,14 @@ impl Payee { _ => None, } } - pub(crate) fn blinded_route_hints(&self) -> &[(BlindedPayInfo, BlindedPaymentPath)] { + pub(crate) fn blinded_route_hints(&self) -> &[BlindedPaymentPath] { match self { Self::Blinded { route_hints, .. } => &route_hints[..], Self::Clear { .. } => &[] } } - pub(crate) fn blinded_route_hints_mut(&mut self) -> &mut [(BlindedPayInfo, BlindedPaymentPath)] { + pub(crate) fn blinded_route_hints_mut(&mut self) -> &mut [BlindedPaymentPath] { match self { Self::Blinded { route_hints, .. } => &mut route_hints[..], Self::Clear { .. } => &mut [] @@ -1246,7 +1252,7 @@ pub struct BlindedPathCandidate<'a> { /// cryptographic material required to build an HTLC through the given path. /// /// This is not exported to bindings users as lifetimes are not expressible in most languages. - pub hint: &'a (BlindedPayInfo, BlindedPaymentPath), + pub hint: &'a BlindedPaymentPath, /// Index of the hint in the original list of blinded hints. /// /// This is used to cheaply uniquely identify this blinded path, even though we don't have @@ -1275,7 +1281,9 @@ pub struct OneHopBlindedPathCandidate<'a> { /// Note that the [`BlindedPayInfo`] is ignored here. /// /// This is not exported to bindings users as lifetimes are not expressible in most languages. - pub hint: &'a (BlindedPayInfo, BlindedPaymentPath), + /// + /// [`BlindedPayInfo`]: crate::offers::invoice::BlindedPayInfo + pub hint: &'a BlindedPaymentPath, /// Index of the hint in the original list of blinded hints. /// /// This is used to cheaply uniquely identify this blinded path, even though we don't have @@ -1325,6 +1333,8 @@ pub enum CandidateRouteHop<'a> { /// /// This primarily exists to track that we need to included a blinded path at the end of our /// [`Route`], even though it doesn't actually add an additional hop in the payment. + /// + /// [`BlindedPayInfo`]: crate::offers::invoice::BlindedPayInfo OneHopBlinded(OneHopBlindedPathCandidate<'a>), } @@ -1393,7 +1403,7 @@ impl<'a> CandidateRouteHop<'a> { CandidateRouteHop::FirstHop(_) => 0, CandidateRouteHop::PublicHop(hop) => hop.info.direction().cltv_expiry_delta as u32, CandidateRouteHop::PrivateHop(hop) => hop.hint.cltv_expiry_delta as u32, - CandidateRouteHop::Blinded(hop) => hop.hint.0.cltv_expiry_delta as u32, + CandidateRouteHop::Blinded(hop) => hop.hint.payinfo.cltv_expiry_delta as u32, CandidateRouteHop::OneHopBlinded(_) => 0, } } @@ -1405,7 +1415,7 @@ impl<'a> CandidateRouteHop<'a> { CandidateRouteHop::FirstHop(hop) => hop.details.next_outbound_htlc_minimum_msat, CandidateRouteHop::PublicHop(hop) => hop.info.direction().htlc_minimum_msat, CandidateRouteHop::PrivateHop(hop) => hop.hint.htlc_minimum_msat.unwrap_or(0), - CandidateRouteHop::Blinded(hop) => hop.hint.0.htlc_minimum_msat, + CandidateRouteHop::Blinded(hop) => hop.hint.payinfo.htlc_minimum_msat, CandidateRouteHop::OneHopBlinded { .. } => 0, } } @@ -1443,8 +1453,8 @@ impl<'a> CandidateRouteHop<'a> { CandidateRouteHop::PrivateHop(hop) => hop.hint.fees, CandidateRouteHop::Blinded(hop) => { RoutingFees { - base_msat: hop.hint.0.fee_base_msat, - proportional_millionths: hop.hint.0.fee_proportional_millionths + base_msat: hop.hint.payinfo.fee_base_msat, + proportional_millionths: hop.hint.payinfo.fee_proportional_millionths } }, CandidateRouteHop::OneHopBlinded(_) => @@ -1467,7 +1477,7 @@ impl<'a> CandidateRouteHop<'a> { CandidateRouteHop::PrivateHop(PrivateHopCandidate { hint: RouteHintHop { htlc_maximum_msat: None, .. }, .. }) => EffectiveCapacity::Infinite, CandidateRouteHop::Blinded(hop) => - EffectiveCapacity::HintMaxHTLC { amount_msat: hop.hint.0.htlc_maximum_msat }, + EffectiveCapacity::HintMaxHTLC { amount_msat: hop.hint.payinfo.htlc_maximum_msat }, CandidateRouteHop::OneHopBlinded(_) => EffectiveCapacity::Infinite, } } @@ -1486,7 +1496,7 @@ impl<'a> CandidateRouteHop<'a> { fn blinded_path(&self) -> Option<&'a BlindedPaymentPath> { match self { CandidateRouteHop::Blinded(BlindedPathCandidate { hint, .. }) | CandidateRouteHop::OneHopBlinded(OneHopBlindedPathCandidate { hint, .. }) => { - Some(&hint.1) + Some(&hint) }, _ => None, } @@ -1639,7 +1649,7 @@ fn calculate_blinded_path_intro_points<'a, L: Deref>( ) -> Result>, LightningError> where L::Target: Logger { let introduction_node_id_cache = payment_params.payee.blinded_route_hints().iter() - .map(|(_, path)| { + .map(|path| { match path.introduction_node() { IntroductionNode::NodeId(pubkey) => { // Note that this will only return `Some` if the `pubkey` is somehow known to @@ -1678,7 +1688,7 @@ where L::Target: Logger { if introduction_node_id_cache.iter().all(|info_opt| info_opt.map(|(a, _)| a) == Some(&our_node_id)) { return Err(LightningError{err: "Cannot generate a route to blinded paths if we are the introduction node to all of them".to_owned(), action: ErrorAction::IgnoreError}); } - for ((_, blinded_path), info_opt) in route_hints.iter().zip(introduction_node_id_cache.iter()) { + for (blinded_path, info_opt) in route_hints.iter().zip(introduction_node_id_cache.iter()) { if blinded_path.blinded_hops().len() == 0 { return Err(LightningError{err: "0-hop blinded path provided".to_owned(), action: ErrorAction::IgnoreError}); } @@ -1691,7 +1701,7 @@ where L::Target: Logger { } else if blinded_path.blinded_hops().len() == 1 && route_hints .iter().zip(introduction_node_id_cache.iter()) - .filter(|((_, p), _)| p.blinded_hops().len() == 1) + .filter(|(p, _)| p.blinded_hops().len() == 1) .any(|(_, iter_info_opt)| iter_info_opt.is_some() && iter_info_opt != info_opt) { return Err(LightningError{err: format!("1-hop blinded paths must all have matching introduction node ids"), action: ErrorAction::IgnoreError}); @@ -1974,7 +1984,7 @@ impl<'a> fmt::Display for LoggedCandidateHop<'a> { match self.0 { CandidateRouteHop::Blinded(BlindedPathCandidate { hint, .. }) | CandidateRouteHop::OneHopBlinded(OneHopBlindedPathCandidate { hint, .. }) => { "blinded route hint with introduction node ".fmt(f)?; - match hint.1.introduction_node() { + match hint.introduction_node() { IntroductionNode::NodeId(pubkey) => write!(f, "id {}", pubkey)?, IntroductionNode::DirectedShortChannelId(direction, scid) => { match direction { @@ -1988,7 +1998,7 @@ impl<'a> fmt::Display for LoggedCandidateHop<'a> { } } " and blinding point ".fmt(f)?; - hint.1.blinding_point().fmt(f) + hint.blinding_point().fmt(f) }, CandidateRouteHop::FirstHop(_) => { "first hop with SCID ".fmt(f)?; @@ -2821,7 +2831,7 @@ where L::Target: Logger { let source_node_opt = introduction_node_id_cache[hint_idx]; let (source_node_id, source_node_counter) = if let Some(v) = source_node_opt { v } else { continue }; if our_node_id == *source_node_id { continue } - let candidate = if hint.1.blinded_hops().len() == 1 { + let candidate = if hint.blinded_hops().len() == 1 { CandidateRouteHop::OneHopBlinded( OneHopBlindedPathCandidate { source_node_counter, source_node_id, hint, hint_idx } ) @@ -3620,22 +3630,24 @@ mod tests { } } - fn dummy_blinded_path(intro_node: PublicKey) -> BlindedPaymentPath { + fn dummy_blinded_path(intro_node: PublicKey, payinfo: BlindedPayInfo) -> BlindedPaymentPath { BlindedPaymentPath::from_raw( intro_node, ln_test_utils::pubkey(42), vec![ BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }, BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() } - ] + ], + payinfo ) } - fn dummy_one_hop_blinded_path(intro_node: PublicKey) -> BlindedPaymentPath { + fn dummy_one_hop_blinded_path(intro_node: PublicKey, payinfo: BlindedPayInfo) -> BlindedPaymentPath { BlindedPaymentPath::from_raw( intro_node, ln_test_utils::pubkey(42), vec![ BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }, - ] + ], + payinfo ) } @@ -5469,7 +5481,6 @@ mod tests { // MPP to a 1-hop blinded path for nodes[2] let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); - let blinded_path = dummy_one_hop_blinded_path(nodes[2]); let blinded_payinfo = BlindedPayInfo { // These fields are ignored for 1-hop blinded paths fee_base_msat: 0, fee_proportional_millionths: 0, @@ -5478,29 +5489,26 @@ mod tests { cltv_expiry_delta: 0, features: BlindedHopFeatures::empty(), }; - let one_hop_blinded_payment_params = PaymentParameters::blinded(vec![(blinded_payinfo.clone(), blinded_path.clone())]) + let blinded_path = dummy_one_hop_blinded_path(nodes[2], blinded_payinfo.clone()); + let one_hop_blinded_payment_params = PaymentParameters::blinded(vec![blinded_path.clone()]) .with_bolt12_features(bolt12_features.clone()).unwrap(); do_simple_mpp_route_test(one_hop_blinded_payment_params.clone()); // MPP to 3 2-hop blinded paths - let blinded_path_node_0 = dummy_blinded_path(nodes[0]); let mut node_0_payinfo = blinded_payinfo.clone(); node_0_payinfo.htlc_maximum_msat = 50_000; + let blinded_path_node_0 = dummy_blinded_path(nodes[0], node_0_payinfo); - let blinded_path_node_7 = dummy_blinded_path(nodes[7]); let mut node_7_payinfo = blinded_payinfo.clone(); node_7_payinfo.htlc_maximum_msat = 60_000; + let blinded_path_node_7 = dummy_blinded_path(nodes[7], node_7_payinfo); - let blinded_path_node_1 = dummy_blinded_path(nodes[1]); - let mut node_1_payinfo = blinded_payinfo.clone(); + let mut node_1_payinfo = blinded_payinfo; node_1_payinfo.htlc_maximum_msat = 180_000; + let blinded_path_node_1 = dummy_blinded_path(nodes[1], node_1_payinfo); let two_hop_blinded_payment_params = PaymentParameters::blinded( - vec![ - (node_0_payinfo, blinded_path_node_0), - (node_7_payinfo, blinded_path_node_7), - (node_1_payinfo, blinded_path_node_1) - ]) + vec![blinded_path_node_0, blinded_path_node_7, blinded_path_node_1]) .with_bolt12_features(bolt12_features).unwrap(); do_simple_mpp_route_test(two_hop_blinded_payment_params); } @@ -5682,8 +5690,8 @@ mod tests { assert_eq!( NodeId::from_pubkey(&path.hops.last().unwrap().pubkey), payment_params.payee.blinded_route_hints().iter() - .find(|(p, _)| p.htlc_maximum_msat == path.final_value_msat()) - .and_then(|(_, p)| p.public_introduction_node_id(&network_graph)) + .find(|p| p.payinfo.htlc_maximum_msat == path.final_value_msat()) + .and_then(|p| p.public_introduction_node_id(&network_graph)) .copied() .unwrap() ); @@ -7656,7 +7664,6 @@ mod tests { assert_eq!(route.get_total_amount(), amt_msat); // Make sure this works for blinded route hints. - let blinded_path = dummy_blinded_path(intermed_node_id); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 100, fee_proportional_millionths: 0, @@ -7665,11 +7672,11 @@ mod tests { cltv_expiry_delta: 10, features: BlindedHopFeatures::empty(), }; + let blinded_path = dummy_blinded_path(intermed_node_id, blinded_payinfo); let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); let payment_params = PaymentParameters::blinded(vec![ - (blinded_payinfo.clone(), blinded_path.clone()), - (blinded_payinfo.clone(), blinded_path.clone())]) - .with_bolt12_features(bolt12_features).unwrap(); + blinded_path.clone(), blinded_path.clone() + ]).with_bolt12_features(bolt12_features).unwrap(); let route_params = RouteParameters::from_payment_params_and_value( payment_params, amt_msat); let route = get_route(&our_node_id, &route_params, &network_graph.read_only(), @@ -7834,7 +7841,6 @@ mod tests { BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 + i as u8), encrypted_payload: Vec::new() }, ); } - let blinded_path = BlindedPaymentPath::from_raw(nodes[2], ln_test_utils::pubkey(42), blinded_hops); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 100, fee_proportional_millionths: 500, @@ -7843,8 +7849,9 @@ mod tests { cltv_expiry_delta: 15, features: BlindedHopFeatures::empty(), }; + let blinded_path = BlindedPaymentPath::from_raw(nodes[2], ln_test_utils::pubkey(42), blinded_hops, blinded_payinfo.clone()); - let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo.clone(), blinded_path.clone())]); + let payment_params = PaymentParameters::blinded(vec![blinded_path.clone()]); let route_params = RouteParameters::from_payment_params_and_value( payment_params, 1001); let route = get_route(&our_id, &route_params, &network_graph, None, Arc::clone(&logger), @@ -7891,11 +7898,10 @@ mod tests { features: BlindedHopFeatures::empty(), }; - let invalid_blinded_path_2 = dummy_one_hop_blinded_path(nodes[2]); - let invalid_blinded_path_3 = dummy_one_hop_blinded_path(nodes[3]); + let invalid_blinded_path_2 = dummy_one_hop_blinded_path(nodes[2], blinded_payinfo.clone()); + let invalid_blinded_path_3 = dummy_one_hop_blinded_path(nodes[3], blinded_payinfo.clone()); let payment_params = PaymentParameters::blinded(vec![ - (blinded_payinfo.clone(), invalid_blinded_path_2), - (blinded_payinfo.clone(), invalid_blinded_path_3)]); + invalid_blinded_path_2, invalid_blinded_path_3]); let route_params = RouteParameters::from_payment_params_and_value(payment_params, 1001); match get_route(&our_id, &route_params, &network_graph, None, Arc::clone(&logger), &scorer, &Default::default(), &random_seed_bytes) @@ -7906,8 +7912,8 @@ mod tests { _ => panic!("Expected error") } - let invalid_blinded_path = dummy_blinded_path(our_id); - let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo.clone(), invalid_blinded_path)]); + let invalid_blinded_path = dummy_blinded_path(our_id, blinded_payinfo.clone()); + let payment_params = PaymentParameters::blinded(vec![invalid_blinded_path]); let route_params = RouteParameters::from_payment_params_and_value(payment_params, 1001); match get_route(&our_id, &route_params, &network_graph, None, Arc::clone(&logger), &scorer, &Default::default(), &random_seed_bytes) @@ -7918,9 +7924,9 @@ mod tests { _ => panic!("Expected error") } - let mut invalid_blinded_path = dummy_one_hop_blinded_path(ln_test_utils::pubkey(46)); + let mut invalid_blinded_path = dummy_one_hop_blinded_path(ln_test_utils::pubkey(46), blinded_payinfo); invalid_blinded_path.clear_blinded_hops(); - let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo, invalid_blinded_path)]); + let payment_params = PaymentParameters::blinded(vec![invalid_blinded_path]); let route_params = RouteParameters::from_payment_params_and_value(payment_params, 1001); match get_route(&our_id, &route_params, &network_graph, None, Arc::clone(&logger), &scorer, &Default::default(), &random_seed_bytes) @@ -7945,7 +7951,6 @@ mod tests { let config = UserConfig::default(); let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); - let blinded_path_1 = dummy_blinded_path(nodes[2]); let blinded_payinfo_1 = BlindedPayInfo { fee_base_msat: 0, fee_proportional_millionths: 0, @@ -7954,20 +7959,19 @@ mod tests { cltv_expiry_delta: 0, features: BlindedHopFeatures::empty(), }; + let blinded_path_1 = dummy_blinded_path(nodes[2], blinded_payinfo_1.clone()); + let mut blinded_payinfo_2 = blinded_payinfo_1; + blinded_payinfo_2.htlc_maximum_msat = 70_000; let blinded_path_2 = BlindedPaymentPath::from_raw(nodes[2], ln_test_utils::pubkey(43), vec![ BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }, BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() } - ] + ], + blinded_payinfo_2 ); - let mut blinded_payinfo_2 = blinded_payinfo_1.clone(); - blinded_payinfo_2.htlc_maximum_msat = 70_000; - let blinded_hints = vec![ - (blinded_payinfo_1.clone(), blinded_path_1.clone()), - (blinded_payinfo_2.clone(), blinded_path_2.clone()), - ]; + let blinded_hints = vec![blinded_path_1.clone(), blinded_path_2.clone()]; let payment_params = PaymentParameters::blinded(blinded_hints.clone()) .with_bolt12_features(bolt12_features).unwrap(); @@ -7981,8 +7985,8 @@ mod tests { assert_eq!(path.hops.last().unwrap().pubkey, nodes[2]); if let Some(bt) = &path.blinded_tail { assert_eq!(bt.blinding_point, - blinded_hints.iter().find(|(p, _)| p.htlc_maximum_msat == path.final_value_msat()) - .map(|(_, bp)| bp.blinding_point()).unwrap()); + blinded_hints.iter().find(|p| p.payinfo.htlc_maximum_msat == path.final_value_msat()) + .map(|bp| bp.blinding_point()).unwrap()); } else { panic!(); } total_amount_paid_msat += path.final_value_msat(); } @@ -8040,7 +8044,6 @@ mod tests { let first_hops = vec![ get_channel_details(Some(1), nodes[1], InitFeatures::from_le_bytes(vec![0b11]), 10_000_000)]; - let blinded_path = dummy_blinded_path(nodes[1]); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 1000, fee_proportional_millionths: 0, @@ -8049,7 +8052,8 @@ mod tests { cltv_expiry_delta: 0, features: BlindedHopFeatures::empty(), }; - let blinded_hints = vec![(blinded_payinfo.clone(), blinded_path)]; + let blinded_path = dummy_blinded_path(nodes[1], blinded_payinfo.clone()); + let blinded_hints = vec![blinded_path]; let payment_params = PaymentParameters::blinded(blinded_hints.clone()); @@ -8101,7 +8105,6 @@ mod tests { get_channel_details(Some(1), nodes[1], channelmanager::provided_init_features(&config), 18446744073709551615)]; - let blinded_path = dummy_blinded_path(nodes[1]); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 5046_2720, fee_proportional_millionths: 0, @@ -8110,15 +8113,13 @@ mod tests { cltv_expiry_delta: 0, features: BlindedHopFeatures::empty(), }; - let mut blinded_hints = vec![ - (blinded_payinfo.clone(), blinded_path.clone()), - (blinded_payinfo.clone(), blinded_path.clone()), - ]; - blinded_hints[1].0.fee_base_msat = 419_4304; - blinded_hints[1].0.fee_proportional_millionths = 257; - blinded_hints[1].0.htlc_minimum_msat = 280_8908_6115_8400; - blinded_hints[1].0.htlc_maximum_msat = 2_8089_0861_1584_0000; - blinded_hints[1].0.cltv_expiry_delta = 0; + let blinded_path = dummy_blinded_path(nodes[1], blinded_payinfo.clone()); + let mut blinded_hints = vec![blinded_path.clone(), blinded_path.clone()]; + blinded_hints[1].payinfo.fee_base_msat = 419_4304; + blinded_hints[1].payinfo.fee_proportional_millionths = 257; + blinded_hints[1].payinfo.htlc_minimum_msat = 280_8908_6115_8400; + blinded_hints[1].payinfo.htlc_maximum_msat = 2_8089_0861_1584_0000; + blinded_hints[1].payinfo.cltv_expiry_delta = 0; let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); let payment_params = PaymentParameters::blinded(blinded_hints.clone()) @@ -8149,7 +8150,6 @@ mod tests { // Values are taken from the fuzz input that uncovered this panic. let amt_msat = 21_7020_5185_1423_0019; - let blinded_path = dummy_blinded_path(our_id); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 5052_9027, fee_proportional_millionths: 0, @@ -8158,11 +8158,9 @@ mod tests { cltv_expiry_delta: 0, features: BlindedHopFeatures::empty(), }; - let mut blinded_hints = vec![ - (blinded_payinfo.clone(), blinded_path.clone()), - (blinded_payinfo.clone(), blinded_path.clone()), - ]; - blinded_hints[1].1 = dummy_blinded_path(nodes[6]); + let blinded_path = dummy_blinded_path(our_id, blinded_payinfo.clone()); + let mut blinded_hints = vec![blinded_path.clone(), blinded_path.clone()]; + blinded_hints[1] = dummy_blinded_path(nodes[6], blinded_payinfo); let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); let payment_params = PaymentParameters::blinded(blinded_hints.clone()) @@ -8193,7 +8191,6 @@ mod tests { // Values are taken from the fuzz input that uncovered this panic. let amt_msat = 21_7020_5185_1423_0019; - let blinded_path = dummy_blinded_path(our_id); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 10_4425_1395, fee_proportional_millionths: 0, @@ -8202,16 +8199,15 @@ mod tests { cltv_expiry_delta: 0, features: BlindedHopFeatures::empty(), }; + let blinded_path = dummy_blinded_path(our_id, blinded_payinfo.clone()); let mut blinded_hints = vec![ - (blinded_payinfo.clone(), blinded_path.clone()), - (blinded_payinfo.clone(), blinded_path.clone()), - (blinded_payinfo.clone(), blinded_path.clone()), + blinded_path.clone(), blinded_path.clone(), blinded_path.clone(), ]; - blinded_hints[1].0.fee_base_msat = 5052_9027; - blinded_hints[1].0.htlc_minimum_msat = 21_7020_5185_1423_0019; - blinded_hints[1].0.htlc_maximum_msat = 1844_6744_0737_0955_1615; + blinded_hints[1].payinfo.fee_base_msat = 5052_9027; + blinded_hints[1].payinfo.htlc_minimum_msat = 21_7020_5185_1423_0019; + blinded_hints[1].payinfo.htlc_maximum_msat = 1844_6744_0737_0955_1615; - blinded_hints[2].1 = dummy_blinded_path(nodes[6]); + blinded_hints[2] = dummy_blinded_path(nodes[6], blinded_payinfo); let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); let payment_params = PaymentParameters::blinded(blinded_hints.clone()) @@ -8256,7 +8252,6 @@ mod tests { let base_fee = 1_6778_3453; let htlc_min = 2_5165_8240; let payment_params = if blinded_payee { - let blinded_path = dummy_blinded_path(nodes[0]); let blinded_payinfo = BlindedPayInfo { fee_base_msat: base_fee, fee_proportional_millionths: 0, @@ -8265,8 +8260,9 @@ mod tests { cltv_expiry_delta: 0, features: BlindedHopFeatures::empty(), }; + let blinded_path = dummy_blinded_path(nodes[0], blinded_payinfo); let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); - PaymentParameters::blinded(vec![(blinded_payinfo, blinded_path)]) + PaymentParameters::blinded(vec![blinded_path]) .with_bolt12_features(bolt12_features.clone()).unwrap() } else { let route_hint = RouteHint(vec![RouteHintHop { @@ -8328,17 +8324,17 @@ mod tests { let base_fees = [0, 425_9840, 0, 0]; let htlc_mins = [1_4392, 19_7401, 1027, 6_5535]; let payment_params = if blinded_payee { - let blinded_path = dummy_blinded_path(nodes[0]); let mut blinded_hints = Vec::new(); for (base_fee, htlc_min) in base_fees.iter().zip(htlc_mins.iter()) { - blinded_hints.push((BlindedPayInfo { + let blinded_payinfo = BlindedPayInfo { fee_base_msat: *base_fee, fee_proportional_millionths: 0, htlc_minimum_msat: *htlc_min, htlc_maximum_msat: htlc_min * 100, cltv_expiry_delta: 10, features: BlindedHopFeatures::empty(), - }, blinded_path.clone())); + }; + blinded_hints.push(dummy_blinded_path(nodes[0], blinded_payinfo)); } let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); PaymentParameters::blinded(blinded_hints.clone()) @@ -8415,14 +8411,14 @@ mod tests { let htlc_min = 2_5165_8240; let blinded_hints = vec![ - (BlindedPayInfo { + dummy_blinded_path(nodes[0], BlindedPayInfo { fee_base_msat: 1_6778_3453, fee_proportional_millionths: 0, htlc_minimum_msat: htlc_min, htlc_maximum_msat: htlc_min * 100, cltv_expiry_delta: 10, features: BlindedHopFeatures::empty(), - }, dummy_blinded_path(nodes[0])) + }) ]; let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); let payment_params = PaymentParameters::blinded(blinded_hints.clone()) @@ -8464,17 +8460,17 @@ mod tests { let htlc_mins = [49_0000, 1125_0000]; let payment_params = { - let blinded_path = dummy_blinded_path(nodes[0]); let mut blinded_hints = Vec::new(); for htlc_min in htlc_mins.iter() { - blinded_hints.push((BlindedPayInfo { + let payinfo = BlindedPayInfo { fee_base_msat: 0, fee_proportional_millionths: 0, htlc_minimum_msat: *htlc_min, htlc_maximum_msat: *htlc_min * 100, cltv_expiry_delta: 10, features: BlindedHopFeatures::empty(), - }, blinded_path.clone())); + }; + blinded_hints.push(dummy_blinded_path(nodes[0], payinfo)); } let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); PaymentParameters::blinded(blinded_hints.clone()) diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index de54a14f2..1c48463b8 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -805,6 +805,19 @@ impl<'a, I: Iterator + Clone, T: 'a + PartialEq> PartialEq for Ite } } +#[derive(Debug)] +pub(crate) struct IterableOwned + Clone, T>(pub I); + +impl + Clone, T: Writeable> Writeable for IterableOwned { + #[inline] + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + for ref v in self.0.clone() { + v.write(writer)?; + } + Ok(()) + } +} + macro_rules! impl_for_map { ($ty: ident, $keybound: ident, $constr: expr) => { impl Writeable for $ty diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 3f2226d74..45e8c081a 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -33,7 +33,7 @@ use crate::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; use crate::ln::{msgs, wire}; use crate::ln::msgs::LightningError; use crate::ln::script::ShutdownScript; -use crate::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice}; +use crate::offers::invoice::UnsignedBolt12Invoice; use crate::offers::invoice_request::UnsignedInvoiceRequest; use crate::onion_message::messenger::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath}; use crate::routing::gossip::{EffectiveCapacity, NetworkGraph, NodeId, RoutingFees}; @@ -119,7 +119,7 @@ pub struct TestRouter<'a> { >, pub network_graph: Arc>, pub next_routes: Mutex>)>>, - pub next_blinded_payment_paths: Mutex>, + pub next_blinded_payment_paths: Mutex>, pub scorer: &'a RwLock, } @@ -148,7 +148,7 @@ impl<'a> TestRouter<'a> { expected_routes.push_back((query, None)); } - pub fn expect_blinded_payment_paths(&self, mut paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>) { + pub fn expect_blinded_payment_paths(&self, mut paths: Vec) { let mut expected_paths = self.next_blinded_payment_paths.lock().unwrap(); core::mem::swap(&mut *expected_paths, &mut paths); } @@ -246,7 +246,7 @@ impl<'a> Router for TestRouter<'a> { >( &self, recipient: PublicKey, first_hops: Vec, tlvs: ReceiveTlvs, amount_msats: u64, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { let mut expected_paths = self.next_blinded_payment_paths.lock().unwrap(); if expected_paths.is_empty() { self.router.create_blinded_payment_paths( -- 2.39.5