diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 4322fccb16f..74bfcb2ed96 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -33,9 +33,8 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hashes::Hash as TraitImport; use bitcoin::WPubkeyHash; -use lightning::blinded_path::message::MessageContext; -use lightning::blinded_path::payment::ReceiveTlvs; -use lightning::blinded_path::BlindedPath; +use lightning::blinded_path::message::{BlindedMessagePath, MessageContext}; +use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs}; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; use lightning::chain::channelmonitor::{ChannelMonitor, MonitorEvent}; @@ -127,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!() } } @@ -142,7 +141,7 @@ impl MessageRouter for FuzzRouter { fn create_blinded_paths( &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, _secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { unreachable!() } } diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index fa0c2906294..974a1308bd2 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -30,9 +30,8 @@ use bitcoin::hashes::Hash as _; use bitcoin::hex::FromHex; use bitcoin::WPubkeyHash; -use lightning::blinded_path::message::MessageContext; -use lightning::blinded_path::payment::ReceiveTlvs; -use lightning::blinded_path::BlindedPath; +use lightning::blinded_path::message::{BlindedMessagePath, MessageContext}; +use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs}; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; use lightning::chain::chainmonitor; @@ -164,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!() } } @@ -179,7 +178,7 @@ impl MessageRouter for FuzzRouter { fn create_blinded_paths( &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, _secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { unreachable!() } } diff --git a/fuzz/src/invoice_request_deser.rs b/fuzz/src/invoice_request_deser.rs index d418cbe51d8..a5db1c4be99 100644 --- a/fuzz/src/invoice_request_deser.rs +++ b/fuzz/src/invoice_request_deser.rs @@ -11,10 +11,9 @@ use crate::utils::test_logger; use bitcoin::secp256k1::{self, Keypair, Parity, PublicKey, Secp256k1, SecretKey}; use core::convert::TryFrom; use lightning::blinded_path::payment::{ - Bolt12OfferContext, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, - ReceiveTlvs, + BlindedPaymentPath, Bolt12OfferContext, ForwardNode, ForwardTlvs, PaymentConstraints, + PaymentContext, PaymentRelay, ReceiveTlvs, }; -use lightning::blinded_path::BlindedPath; use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA; use lightning::ln::features::BlindedHopFeatures; use lightning::ln::types::PaymentSecret; @@ -118,7 +117,7 @@ fn build_response( node_id: pubkey(43), htlc_maximum_msat: 1_000_000_000_000, }]; - let payment_path = BlindedPath::new_for_payment( + let payment_path = BlindedPaymentPath::new( &intermediate_nodes, pubkey(42), payee_tlvs, diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 48f184af709..a37f23f4437 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -5,8 +5,8 @@ use bitcoin::secp256k1::ecdsa::RecoverableSignature; use bitcoin::secp256k1::schnorr; use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey}; -use lightning::blinded_path::message::{MessageContext, OffersContext}; -use lightning::blinded_path::{BlindedPath, EmptyNodeIdLookUp}; +use lightning::blinded_path::message::{BlindedMessagePath, MessageContext, OffersContext}; +use lightning::blinded_path::EmptyNodeIdLookUp; use lightning::ln::features::InitFeatures; use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler}; use lightning::ln::script::ShutdownScript; @@ -98,7 +98,7 @@ impl MessageRouter for TestMessageRouter { fn create_blinded_paths( &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, _secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { unreachable!() } } diff --git a/fuzz/src/refund_deser.rs b/fuzz/src/refund_deser.rs index 5a692280683..58dc68eed5c 100644 --- a/fuzz/src/refund_deser.rs +++ b/fuzz/src/refund_deser.rs @@ -11,10 +11,9 @@ use crate::utils::test_logger; use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1, SecretKey}; use core::convert::TryFrom; use lightning::blinded_path::payment::{ - Bolt12RefundContext, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, - PaymentRelay, ReceiveTlvs, + BlindedPaymentPath, Bolt12RefundContext, ForwardNode, ForwardTlvs, PaymentConstraints, + PaymentContext, PaymentRelay, ReceiveTlvs, }; -use lightning::blinded_path::BlindedPath; use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA; use lightning::ln::features::BlindedHopFeatures; use lightning::ln::types::PaymentSecret; @@ -96,7 +95,7 @@ fn build_response( node_id: pubkey(43), htlc_maximum_msat: 1_000_000_000_000, }]; - let payment_path = BlindedPath::new_for_payment( + let payment_path = BlindedPaymentPath::new( &intermediate_nodes, pubkey(42), payee_tlvs, diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs index 96046f25842..e578c2feda5 100644 --- a/fuzz/src/router.rs +++ b/fuzz/src/router.rs @@ -12,7 +12,8 @@ use bitcoin::constants::ChainHash; use bitcoin::script::Builder; use bitcoin::transaction::TxOut; -use lightning::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; +use lightning::blinded_path::payment::BlindedPaymentPath; +use lightning::blinded_path::BlindedHop; use lightning::chain::transaction::OutPoint; use lightning::ln::channel_state::{ChannelCounterparty, ChannelDetails, ChannelShutdownState}; use lightning::ln::channelmanager; @@ -380,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, BlindedPath)> = last_hops_unblinded + let last_hops: Vec<(BlindedPayInfo, BlindedPaymentPath)> = last_hops_unblinded .into_iter() .map(|hint| { let hop = &hint.0[0]; @@ -402,11 +403,7 @@ pub fn do_test(data: &[u8], out: Out) { } ( payinfo, - BlindedPath { - introduction_node: IntroductionNode::NodeId(hop.src_node_id), - blinding_point: dummy_pk, - blinded_hops, - }, + BlindedPaymentPath::from_raw(hop.src_node_id, dummy_pk, blinded_hops), ) }) .collect(); diff --git a/lightning/src/blinded_path/message.rs b/lightning/src/blinded_path/message.rs index 26019c0369d..93d36d621c9 100644 --- a/lightning/src/blinded_path/message.rs +++ b/lightning/src/blinded_path/message.rs @@ -7,9 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -//! Data structures and methods for constructing [`BlindedPath`]s to send a message over. -//! -//! [`BlindedPath`]: crate::blinded_path::BlindedPath +//! Data structures and methods for constructing [`BlindedMessagePath`]s to send a message over. use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; @@ -18,21 +16,204 @@ use crate::prelude::*; use bitcoin::hashes::hmac::Hmac; use bitcoin::hashes::sha256::Hash as Sha256; -use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NextMessageHop, NodeIdLookUp}; +use crate::blinded_path::{BlindedHop, BlindedPath, Direction, IntroductionNode, NodeIdLookUp}; use crate::blinded_path::utils; use crate::io; use crate::io::Cursor; use crate::ln::channelmanager::PaymentId; +use crate::ln::msgs::DecodeError; use crate::ln::{PaymentHash, onion_utils}; use crate::offers::nonce::Nonce; use crate::onion_message::packet::ControlTlvs; -use crate::sign::{NodeSigner, Recipient}; +use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph}; +use crate::sign::{EntropySource, NodeSigner, Recipient}; use crate::crypto::streams::ChaChaPolyReadAdapter; -use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Writeable, Writer}; +use crate::util::scid_utils; +use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Readable, Writeable, Writer}; use core::mem; use core::ops::Deref; +/// A blinded path to be used for sending or receiving a message, hiding the identity of the +/// recipient. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct BlindedMessagePath(pub(super) BlindedPath); + +impl Writeable for BlindedMessagePath { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.0.write(w) + } +} + +impl Readable for BlindedMessagePath { + fn read(r: &mut R) -> Result { + Ok(Self(BlindedPath::read(r)?)) + } +} + +impl BlindedMessagePath { + /// Create a one-hop blinded path for a message. + pub fn one_hop( + recipient_node_id: PublicKey, context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1 + ) -> Result where ES::Target: EntropySource { + Self::new(&[], recipient_node_id, context, entropy_source, secp_ctx) + } + + /// Create a path for an onion message, to be forwarded along `node_pks`. The last node + /// pubkey in `node_pks` will be the destination node. + /// + /// Errors if no hops are provided or if `node_pk`(s) are invalid. + // TODO: make all payloads the same size with padding + add dummy hops + pub fn new( + intermediate_nodes: &[ForwardNode], recipient_node_id: PublicKey, context: MessageContext, + entropy_source: ES, secp_ctx: &Secp256k1 + ) -> Result where ES::Target: EntropySource { + let introduction_node = IntroductionNode::NodeId( + intermediate_nodes.first().map_or(recipient_node_id, |n| n.node_id) + ); + let blinding_secret_bytes = entropy_source.get_secure_random_bytes(); + let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted"); + + Ok(Self(BlindedPath { + introduction_node, + blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret), + blinded_hops: blinded_hops( + secp_ctx, intermediate_nodes, recipient_node_id, + context, &blinding_secret, + ).map_err(|_| ())?, + })) + } + + /// Attempts to a use a compact representation for the [`IntroductionNode`] by using a directed + /// short channel id from a channel in `network_graph` leading to the introduction node. + /// + /// While this may result in a smaller encoding, there is a trade off in that the path may + /// become invalid if the channel is closed or hasn't been propagated via gossip. Therefore, + /// calling this may not be suitable for long-lived blinded paths. + pub fn use_compact_introduction_node(&mut self, network_graph: &ReadOnlyNetworkGraph) { + if let IntroductionNode::NodeId(pubkey) = &self.0.introduction_node { + let node_id = NodeId::from_pubkey(pubkey); + if let Some(node_info) = network_graph.node(&node_id) { + if let Some((scid, channel_info)) = node_info + .channels + .iter() + .filter_map(|scid| network_graph.channel(*scid).map(|info| (*scid, info))) + .min_by_key(|(scid, _)| scid_utils::block_from_scid(*scid)) + { + let direction = if node_id == channel_info.node_one { + Direction::NodeOne + } else { + debug_assert_eq!(node_id, channel_info.node_two); + Direction::NodeTwo + }; + self.0.introduction_node = + IntroductionNode::DirectedShortChannelId(direction, scid); + } + } + } + } + + /// Returns the introduction [`NodeId`] of the blinded path, if it is publicly reachable (i.e., + /// it is found in the network graph). + pub fn public_introduction_node_id<'a>( + &self, network_graph: &'a ReadOnlyNetworkGraph + ) -> Option<&'a NodeId> { + self.0.public_introduction_node_id(network_graph) + } + + /// The [`IntroductionNode`] of the blinded path. + pub fn introduction_node(&self) -> &IntroductionNode { + &self.0.introduction_node + } + + /// Used by the [`IntroductionNode`] to decrypt its [`encrypted_payload`] to forward the message. + /// + /// [`encrypted_payload`]: BlindedHop::encrypted_payload + pub fn blinding_point(&self) -> PublicKey { + self.0.blinding_point + } + + /// The [`BlindedHop`]s within the blinded path. + pub fn blinded_hops(&self) -> &[BlindedHop] { + &self.0.blinded_hops + } + + /// Advance the blinded onion message path by one hop, making the second hop into the new + /// introduction node. + /// + /// Will only modify `self` when returning `Ok`. + pub fn advance_path_by_one( + &mut self, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1 + ) -> Result<(), ()> + where + NS::Target: NodeSigner, + NL::Target: NodeIdLookUp, + T: secp256k1::Signing + secp256k1::Verification, + { + let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.0.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 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) { + Ok(ChaChaPolyReadAdapter { + readable: ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override }) + }) => { + let next_node_id = match next_hop { + NextMessageHop::NodeId(pubkey) => pubkey, + NextMessageHop::ShortChannelId(scid) => match node_id_lookup.next_node_id(scid) { + Some(pubkey) => pubkey, + None => return Err(()), + }, + }; + let mut new_blinding_point = match next_blinding_override { + Some(blinding_point) => blinding_point, + None => { + onion_utils::next_hop_pubkey(secp_ctx, self.0.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); + Ok(()) + }, + _ => Err(()) + } + } + + pub(crate) fn introduction_node_mut(&mut self) -> &mut IntroductionNode { + &mut self.0.introduction_node + } + + #[cfg(test)] + pub fn from_raw( + introduction_node_id: PublicKey, blinding_point: PublicKey, blinded_hops: Vec + ) -> Self { + Self(BlindedPath { + introduction_node: IntroductionNode::NodeId(introduction_node_id), + blinding_point, + blinded_hops, + }) + } + + #[cfg(test)] + pub fn clear_blinded_hops(&mut self) { + self.0.blinded_hops.clear() + } +} + +/// The next hop to forward an onion message along its path. +/// +/// Note that payment blinded paths always specify their next hop using an explicit node id. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub enum NextMessageHop { + /// The node id of the next hop. + NodeId(PublicKey), + /// The short channel id leading to the next hop. + ShortChannelId(u64), +} + /// An intermediate node, and possibly a short channel id leading to the next node. #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub struct ForwardNode { @@ -88,10 +269,10 @@ impl Writeable for ReceiveTlvs { } } -/// Additional data included by the recipient in a [`BlindedPath`]. +/// Additional data included by the recipient in a [`BlindedMessagePath`]. /// /// This data is encrypted by the recipient and will be given to the corresponding message handler -/// when handling a message sent over the [`BlindedPath`]. The recipient can use this data to +/// when handling a message sent over the [`BlindedMessagePath`]. The recipient can use this data to /// authenticate the message or for further processing if needed. #[derive(Clone, Debug)] pub enum MessageContext { @@ -110,7 +291,7 @@ pub enum MessageContext { /// [`OffersMessage`]: crate::onion_message::offers::OffersMessage #[derive(Clone, Debug, Eq, PartialEq)] pub enum OffersContext { - /// Context used by a [`BlindedPath`] within an [`Offer`]. + /// Context used by a [`BlindedMessagePath`] within an [`Offer`]. /// /// This variant is intended to be received when handling an [`InvoiceRequest`]. /// @@ -124,7 +305,7 @@ pub enum OffersContext { /// [`Offer`]: crate::offers::offer::Offer nonce: Nonce, }, - /// Context used by a [`BlindedPath`] within a [`Refund`] or as a reply path for an + /// Context used by a [`BlindedMessagePath`] within a [`Refund`] or as a reply path for an /// [`InvoiceRequest`]. /// /// This variant is intended to be received when handling a [`Bolt12Invoice`] or an @@ -155,7 +336,7 @@ pub enum OffersContext { /// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError hmac: Option>, }, - /// Context used by a [`BlindedPath`] as a reply path for a [`Bolt12Invoice`]. + /// Context used by a [`BlindedMessagePath`] as a reply path for a [`Bolt12Invoice`]. /// /// This variant is intended to be received when handling an [`InvoiceError`]. /// @@ -208,46 +389,3 @@ pub(super) fn blinded_hops( utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv) } -// Advance the blinded onion message path by one hop, so make the second hop into the new -// introduction node. -// -// Will only modify `path` when returning `Ok`. -pub(crate) fn advance_path_by_one( - path: &mut BlindedPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1 -) -> Result<(), ()> -where - NS::Target: NodeSigner, - NL::Target: NodeIdLookUp, - T: secp256k1::Signing + secp256k1::Verification, -{ - let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.blinding_point, None)?; - let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes()); - let encrypted_control_tlvs = &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) { - Ok(ChaChaPolyReadAdapter { - readable: ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override }) - }) => { - let next_node_id = match next_hop { - NextMessageHop::NodeId(pubkey) => pubkey, - NextMessageHop::ShortChannelId(scid) => match node_id_lookup.next_node_id(scid) { - Some(pubkey) => pubkey, - None => return Err(()), - }, - }; - let mut new_blinding_point = match next_blinding_override { - Some(blinding_point) => blinding_point, - None => { - onion_utils::next_hop_pubkey(secp_ctx, path.blinding_point, - control_tlvs_ss.as_ref()).map_err(|_| ())? - } - }; - mem::swap(&mut path.blinding_point, &mut new_blinding_point); - path.introduction_node = IntroductionNode::NodeId(next_node_id); - path.blinded_hops.remove(0); - Ok(()) - }, - _ => Err(()) - } -} diff --git a/lightning/src/blinded_path/mod.rs b/lightning/src/blinded_path/mod.rs index e34e64c7ac2..6a278b7fd28 100644 --- a/lightning/src/blinded_path/mod.rs +++ b/lightning/src/blinded_path/mod.rs @@ -13,35 +13,20 @@ pub mod payment; pub mod message; pub(crate) mod utils; -use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; -use message::MessageContext; +use bitcoin::secp256k1::PublicKey; use core::ops::Deref; use crate::ln::msgs::DecodeError; -use crate::offers::invoice::BlindedPayInfo; use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph}; -use crate::sign::EntropySource; use crate::util::ser::{Readable, Writeable, Writer}; -use crate::util::scid_utils; use crate::io; use crate::prelude::*; -/// The next hop to forward an onion message along its path. -/// -/// Note that payment blinded paths always specify their next hop using an explicit node id. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub enum NextMessageHop { - /// The node id of the next hop. - NodeId(PublicKey), - /// The short channel id leading to the next hop. - ShortChannelId(u64), -} - /// 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)] -pub struct BlindedPath { +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. @@ -57,7 +42,7 @@ pub struct BlindedPath { pub blinded_hops: Vec, } -/// The unblinded node in a [`BlindedPath`]. +/// The unblinded node in a blinded path. #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub enum IntroductionNode { /// The node id of the introduction node. @@ -67,8 +52,8 @@ pub enum IntroductionNode { DirectedShortChannelId(Direction, u64), } -/// The side of a channel that is the [`IntroductionNode`] in a [`BlindedPath`]. [BOLT 7] defines -/// which nodes is which in the [`ChannelAnnouncement`] message. +/// The side of a channel that is the [`IntroductionNode`] in a blinded path. [BOLT 7] defines which +/// nodes is which in the [`ChannelAnnouncement`] message. /// /// [BOLT 7]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-channel_announcement-message /// [`ChannelAnnouncement`]: crate::ln::msgs::ChannelAnnouncement @@ -113,96 +98,16 @@ impl Deref for EmptyNodeIdLookUp { /// and thus can be used to hide the identity of the recipient. #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct BlindedHop { - /// The blinded node id of this hop in a [`BlindedPath`]. + /// The blinded node id of this hop in a blinded path. pub blinded_node_id: PublicKey, - /// The encrypted payload intended for this hop in a [`BlindedPath`]. + /// The encrypted payload intended for this hop in a blinded path. // The node sending to this blinded path will later encode this payload into the onion packet for // this hop. pub encrypted_payload: Vec, } impl BlindedPath { - /// Create a one-hop blinded path for a message. - pub fn one_hop_for_message( - recipient_node_id: PublicKey, context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1 - ) -> Result where ES::Target: EntropySource { - Self::new_for_message(&[], recipient_node_id, context, entropy_source, secp_ctx) - } - - /// Create a blinded path for an onion message, to be forwarded along `node_pks`. The last node - /// pubkey in `node_pks` will be the destination node. - /// - /// Errors if no hops are provided or if `node_pk`(s) are invalid. - // TODO: make all payloads the same size with padding + add dummy hops - pub fn new_for_message( - intermediate_nodes: &[message::ForwardNode], recipient_node_id: PublicKey, - context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1 - ) -> Result where ES::Target: EntropySource { - let introduction_node = IntroductionNode::NodeId( - intermediate_nodes.first().map_or(recipient_node_id, |n| n.node_id) - ); - let blinding_secret_bytes = entropy_source.get_secure_random_bytes(); - let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted"); - - Ok(BlindedPath { - introduction_node, - blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret), - blinded_hops: message::blinded_hops( - secp_ctx, intermediate_nodes, recipient_node_id, - context, &blinding_secret, - ).map_err(|_| ())?, - }) - } - - /// Create a one-hop blinded path for a payment. - pub fn one_hop_for_payment( - payee_node_id: PublicKey, payee_tlvs: payment::ReceiveTlvs, min_final_cltv_expiry_delta: u16, - entropy_source: ES, secp_ctx: &Secp256k1 - ) -> Result<(BlindedPayInfo, Self), ()> 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(); - Self::new_for_payment( - &[], payee_node_id, payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta, - entropy_source, secp_ctx - ) - } - - /// Create a blinded path for a payment, to be forwarded along `intermediate_nodes`. - /// - /// Errors if: - /// * a provided node id is invalid - /// * [`BlindedPayInfo`] calculation results in an integer overflow - /// * any unknown features are required in the provided [`ForwardTlvs`] - /// - /// [`ForwardTlvs`]: crate::blinded_path::payment::ForwardTlvs - // TODO: make all payloads the same size with padding + add dummy hops - pub fn new_for_payment( - intermediate_nodes: &[payment::ForwardNode], payee_node_id: PublicKey, - payee_tlvs: payment::ReceiveTlvs, htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16, - entropy_source: ES, secp_ctx: &Secp256k1 - ) -> Result<(BlindedPayInfo, Self), ()> where ES::Target: EntropySource { - let introduction_node = IntroductionNode::NodeId( - intermediate_nodes.first().map_or(payee_node_id, |n| n.node_id) - ); - let blinding_secret_bytes = entropy_source.get_secure_random_bytes(); - let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted"); - - let blinded_payinfo = payment::compute_payinfo( - intermediate_nodes, &payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta - )?; - Ok((blinded_payinfo, BlindedPath { - introduction_node, - blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret), - blinded_hops: payment::blinded_hops( - secp_ctx, intermediate_nodes, payee_node_id, payee_tlvs, &blinding_secret - ).map_err(|_| ())?, - })) - } - - /// Returns the introduction [`NodeId`] of the blinded path, if it is publicly reachable (i.e., - /// it is found in the network graph). - pub fn public_introduction_node_id<'a>( + pub(super) fn public_introduction_node_id<'a>( &self, network_graph: &'a ReadOnlyNetworkGraph ) -> Option<&'a NodeId> { match &self.introduction_node { @@ -220,35 +125,6 @@ impl BlindedPath { }, } } - - /// Attempts to a use a compact representation for the [`IntroductionNode`] by using a directed - /// short channel id from a channel in `network_graph` leading to the introduction node. - /// - /// While this may result in a smaller encoding, there is a trade off in that the path may - /// become invalid if the channel is closed or hasn't been propagated via gossip. Therefore, - /// calling this may not be suitable for long-lived blinded paths. - pub fn use_compact_introduction_node(&mut self, network_graph: &ReadOnlyNetworkGraph) { - if let IntroductionNode::NodeId(pubkey) = &self.introduction_node { - let node_id = NodeId::from_pubkey(pubkey); - if let Some(node_info) = network_graph.node(&node_id) { - if let Some((scid, channel_info)) = node_info - .channels - .iter() - .filter_map(|scid| network_graph.channel(*scid).map(|info| (*scid, info))) - .min_by_key(|(scid, _)| scid_utils::block_from_scid(*scid)) - { - let direction = if node_id == channel_info.node_one { - Direction::NodeOne - } else { - debug_assert_eq!(node_id, channel_info.node_two); - Direction::NodeTwo - }; - self.introduction_node = - IntroductionNode::DirectedShortChannelId(direction, scid); - } - } - } - } } impl Writeable for BlindedPath { diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index 8c892e896c8..765e0b91f05 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -7,9 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -//! Data structures and methods for constructing [`BlindedPath`]s to send a payment over. -//! -//! [`BlindedPath`]: crate::blinded_path::BlindedPath +//! Data structures and methods for constructing [`BlindedPaymentPath`]s to send a payment over. use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; @@ -26,7 +24,8 @@ use crate::ln::onion_utils; use crate::offers::invoice::BlindedPayInfo; use crate::offers::invoice_request::InvoiceRequestFields; use crate::offers::offer::OfferId; -use crate::sign::{NodeSigner, Recipient}; +use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph}; +use crate::sign::{EntropySource, NodeSigner, Recipient}; use crate::util::ser::{FixedLengthReader, LengthReadableArgs, HighZeroBytesDroppedBigSize, Readable, Writeable, Writer}; use core::mem; @@ -35,6 +34,147 @@ use core::ops::Deref; #[allow(unused_imports)] 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)?)) + } +} + +impl BlindedPaymentPath { + /// Create a one-hop blinded path for a payment. + 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 { + // 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(); + Self::new( + &[], payee_node_id, payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta, + entropy_source, secp_ctx + ) + } + + /// Create a blinded path for a payment, to be forwarded along `intermediate_nodes`. + /// + /// Errors if: + /// * a provided node id is invalid + /// * [`BlindedPayInfo`] calculation results in an integer overflow + /// * any unknown features are required in the provided [`ForwardTlvs`] + // TODO: make all payloads the same size with padding + add dummy hops + pub fn new( + 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 { + let introduction_node = IntroductionNode::NodeId( + intermediate_nodes.first().map_or(payee_node_id, |n| n.node_id) + ); + let blinding_secret_bytes = entropy_source.get_secure_random_bytes(); + let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted"); + + 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(|_| ())?, + }))) + } + + /// Returns the introduction [`NodeId`] of the blinded path, if it is publicly reachable (i.e., + /// it is found in the network graph). + pub fn public_introduction_node_id<'a>( + &self, network_graph: &'a ReadOnlyNetworkGraph + ) -> Option<&'a NodeId> { + self.0.public_introduction_node_id(network_graph) + } + + /// The [`IntroductionNode`] of the blinded path. + pub fn introduction_node(&self) -> &IntroductionNode { + &self.0.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 + } + + /// The [`BlindedHop`]s within the blinded path. + pub fn blinded_hops(&self) -> &[BlindedHop] { + &self.0.blinded_hops + } + + /// Advance the blinded onion payment path by one hop, making the second hop into the new + /// introduction node. + /// + /// Will only modify `self` when returning `Ok`. + pub fn advance_path_by_one( + &mut self, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1 + ) -> Result<(), ()> + where + NS::Target: NodeSigner, + NL::Target: NodeIdLookUp, + T: secp256k1::Signing + secp256k1::Verification, + { + let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.0.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 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) { + Ok(ChaChaPolyReadAdapter { + readable: BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, .. }) + }) => { + let next_node_id = match node_id_lookup.next_node_id(short_channel_id) { + Some(node_id) => node_id, + None => return Err(()), + }; + let mut new_blinding_point = onion_utils::next_hop_pubkey( + secp_ctx, self.0.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); + Ok(()) + }, + _ => Err(()) + } + } + + #[cfg(any(test, fuzzing))] + pub fn from_raw( + introduction_node_id: PublicKey, blinding_point: PublicKey, blinded_hops: Vec + ) -> Self { + Self(BlindedPath { + introduction_node: IntroductionNode::NodeId(introduction_node_id), + blinding_point, + blinded_hops, + }) + } + + #[cfg(test)] + pub fn clear_blinded_hops(&mut self) { + self.0.blinded_hops.clear() + } +} + /// An intermediate node, its outbound channel, and relay parameters. #[derive(Clone, Debug)] pub struct ForwardNode { @@ -117,10 +257,9 @@ pub struct PaymentConstraints { pub htlc_minimum_msat: u64, } -/// The context of an inbound payment, which is included in a [`BlindedPath`] via [`ReceiveTlvs`] -/// and surfaced in [`PaymentPurpose`]. +/// The context of an inbound payment, which is included in a [`BlindedPaymentPath`] via +/// [`ReceiveTlvs`] and surfaced in [`PaymentPurpose`]. /// -/// [`BlindedPath`]: crate::blinded_path::BlindedPath /// [`PaymentPurpose`]: crate::events::PaymentPurpose #[derive(Clone, Debug, Eq, PartialEq)] pub enum PaymentContext { @@ -281,43 +420,6 @@ pub(super) fn blinded_hops( utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv) } -// Advance the blinded onion payment path by one hop, so make the second hop into the new -// introduction node. -// -// Will only modify `path` when returning `Ok`. -pub(crate) fn advance_path_by_one( - path: &mut BlindedPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1 -) -> Result<(), ()> -where - NS::Target: NodeSigner, - NL::Target: NodeIdLookUp, - T: secp256k1::Signing + secp256k1::Verification, -{ - let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.blinding_point, None)?; - let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes()); - let encrypted_control_tlvs = &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) { - Ok(ChaChaPolyReadAdapter { - readable: BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, .. }) - }) => { - let next_node_id = match node_id_lookup.next_node_id(short_channel_id) { - Some(node_id) => node_id, - None => return Err(()), - }; - let mut new_blinding_point = onion_utils::next_hop_pubkey( - secp_ctx, path.blinding_point, control_tlvs_ss.as_ref() - ).map_err(|_| ())?; - mem::swap(&mut path.blinding_point, &mut new_blinding_point); - path.introduction_node = IntroductionNode::NodeId(next_node_id); - path.blinded_hops.remove(0); - Ok(()) - }, - _ => Err(()) - } -} - /// `None` if underflow occurs. pub(crate) fn amt_to_forward_msat(inbound_amt_msat: u64, payment_relay: &PaymentRelay) -> Option { let inbound_amt = inbound_amt_msat as u128; diff --git a/lightning/src/blinded_path/utils.rs b/lightning/src/blinded_path/utils.rs index 7e43f314536..384281c7123 100644 --- a/lightning/src/blinded_path/utils.rs +++ b/lightning/src/blinded_path/utils.rs @@ -16,6 +16,7 @@ use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey, Scalar}; use bitcoin::secp256k1::ecdh::SharedSecret; use super::{BlindedHop, BlindedPath}; +use super::message::BlindedMessagePath; use crate::ln::msgs::DecodeError; use crate::ln::onion_utils; use crate::onion_message::messenger::Destination; @@ -97,7 +98,7 @@ where Destination::Node(pk) => { build_keys!(pk, false, None); }, - Destination::BlindedPath(BlindedPath { blinded_hops, .. }) => { + Destination::BlindedPath(BlindedMessagePath(BlindedPath { blinded_hops, .. })) => { for hop in blinded_hops { build_keys_in_loop!(hop.blinded_node_id, true, Some(hop.encrypted_payload)); } diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index 63f19ed222b..d756eff1bad 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -811,9 +811,9 @@ pub enum Event { payment_id: PaymentId, /// The invoice to pay. invoice: Bolt12Invoice, - /// The context of the [`BlindedPath`] used to send the invoice. + /// The context of the [`BlindedMessagePath`] used to send the invoice. /// - /// [`BlindedPath`]: crate::blinded_path::BlindedPath + /// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath context: Option, /// A responder for replying with an [`InvoiceError`] if needed. /// diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 9d246f1a741..b13b1e04d64 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -8,8 +8,7 @@ // licenses. use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; -use crate::blinded_path::BlindedPath; -use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, ReceiveTlvs}; +use crate::blinded_path::payment::{BlindedPaymentPath, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, ReceiveTlvs}; use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PaymentFailureReason}; use crate::ln::types::PaymentSecret; use crate::ln::channelmanager; @@ -31,7 +30,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, BlindedPath) { +) -> (BlindedPayInfo, 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); @@ -66,7 +65,7 @@ fn blinded_payment_path( payment_context: PaymentContext::unknown(), }; let mut secp_ctx = Secp256k1::new(); - BlindedPath::new_for_payment( + BlindedPaymentPath::new( &intermediate_nodes[..], *node_ids.last().unwrap(), payee_tlvs, intro_node_max_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_maximum_msat), TEST_FINAL_CLTV as u16, keys_manager, &secp_ctx @@ -112,8 +111,8 @@ fn do_one_hop_blinded_path(success: bool) { payment_context: PaymentContext::unknown(), }; let mut secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath::one_hop_for_payment( - nodes[1].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16, + let blinded_path = BlindedPaymentPath::new( + &[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, &chanmon_cfgs[1].keys_manager, &secp_ctx ).unwrap(); @@ -155,8 +154,8 @@ fn mpp_to_one_hop_blinded_path() { }, payment_context: PaymentContext::unknown(), }; - let blinded_path = BlindedPath::one_hop_for_payment( - nodes[3].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16, + let blinded_path = BlindedPaymentPath::new( + &[], nodes[3].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, &chanmon_cfgs[3].keys_manager, &secp_ctx ).unwrap(); @@ -1301,8 +1300,8 @@ fn custom_tlvs_to_blinded_path() { payment_context: PaymentContext::unknown(), }; let mut secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath::one_hop_for_payment( - nodes[1].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16, + let blinded_path = BlindedPaymentPath::new( + &[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, &chanmon_cfgs[1].keys_manager, &secp_ctx ).unwrap(); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index c6645956b18..641810f2f4e 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -32,9 +32,9 @@ use bitcoin::secp256k1::Secp256k1; use bitcoin::{secp256k1, Sequence}; use crate::blinded_path::message::{MessageContext, OffersContext}; -use crate::blinded_path::{BlindedPath, NodeIdLookUp}; -use crate::blinded_path::message::ForwardNode; -use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs}; +use crate::blinded_path::NodeIdLookUp; +use crate::blinded_path::message::{BlindedMessagePath, ForwardNode}; +use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs}; use crate::chain; use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock}; use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator}; @@ -2472,11 +2472,11 @@ const MAX_NO_CHANNEL_PEERS: usize = 250; /// short-lived, while anything with a greater expiration is considered long-lived. /// /// Using [`ChannelManager::create_offer_builder`] or [`ChannelManager::create_refund_builder`], -/// will included a [`BlindedPath`] created using: +/// will included a [`BlindedMessagePath`] created using: /// - [`MessageRouter::create_compact_blinded_paths`] when short-lived, and /// - [`MessageRouter::create_blinded_paths`] when long-lived. /// -/// Using compact [`BlindedPath`]s may provide better privacy as the [`MessageRouter`] could select +/// Using compact [`BlindedMessagePath`]s may provide better privacy as the [`MessageRouter`] could select /// more hops. However, since they use short channel ids instead of pubkeys, they are more likely to /// become invalid over time as channels are closed. Thus, they are only suitable for short-term use. pub const MAX_SHORT_LIVED_RELATIVE_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24); @@ -8789,7 +8789,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => { /// /// # Privacy /// - /// Uses [`MessageRouter`] to construct a [`BlindedPath`] for the offer based on the given + /// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the offer based on the given /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for /// privacy implications as well as those of the parameterized [`Router`], which implements /// [`MessageRouter`]. @@ -8856,7 +8856,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => { /// /// # Privacy /// - /// Uses [`MessageRouter`] to construct a [`BlindedPath`] for the refund based on the given + /// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for /// privacy implications as well as those of the parameterized [`Router`], which implements /// [`MessageRouter`]. @@ -8970,7 +8970,7 @@ where /// # Privacy /// /// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`] - /// to construct a [`BlindedPath`] for the reply path. For further privacy implications, see the + /// to construct a [`BlindedMessagePath`] for the reply path. For further privacy implications, see the /// docs of the parameterized [`Router`], which implements [`MessageRouter`]. /// /// # Limitations @@ -9073,8 +9073,8 @@ where /// message. /// /// The resulting invoice uses a [`PaymentHash`] recognized by the [`ChannelManager`] and a - /// [`BlindedPath`] containing the [`PaymentSecret`] needed to reconstruct the corresponding - /// [`PaymentPreimage`]. It is returned purely for informational purposes. + /// [`BlindedPaymentPath`] containing the [`PaymentSecret`] needed to reconstruct the + /// corresponding [`PaymentPreimage`]. It is returned purely for informational purposes. /// /// # Limitations /// @@ -9273,7 +9273,7 @@ where /// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. fn create_blinded_paths_using_absolute_expiry( &self, context: OffersContext, absolute_expiry: Option, - ) -> Result, ()> { + ) -> Result, ()> { let now = self.duration_since_epoch(); let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY); @@ -9301,7 +9301,7 @@ where /// [`MessageRouter::create_blinded_paths`]. /// /// Errors if the `MessageRouter` errors. - fn create_blinded_paths(&self, context: OffersContext) -> Result, ()> { + fn create_blinded_paths(&self, context: OffersContext) -> Result, ()> { let recipient = self.get_our_node_id(); let secp_ctx = &self.secp_ctx; @@ -9322,7 +9322,7 @@ where /// [`MessageRouter::create_compact_blinded_paths`]. /// /// Errors if the `MessageRouter` errors. - fn create_compact_blinded_paths(&self, context: OffersContext) -> Result, ()> { + fn create_compact_blinded_paths(&self, context: OffersContext) -> Result, ()> { let recipient = self.get_our_node_id(); let secp_ctx = &self.secp_ctx; @@ -9350,7 +9350,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 096bcf9633c..8e5edd4e91b 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -11,8 +11,8 @@ //! and/or blinded paths present. use bitcoin::secp256k1::{Secp256k1, PublicKey}; -use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; -use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, ReceiveTlvs}; +use crate::blinded_path::BlindedHop; +use crate::blinded_path::payment::{BlindedPaymentPath, PaymentConstraints, PaymentContext, ReceiveTlvs}; use crate::events::{Event, MessageSendEventsProvider}; use crate::ln::PaymentSecret; use crate::ln::blinded_payment_tests::get_blinded_route_parameters; @@ -167,8 +167,8 @@ fn one_hop_blinded_path_with_custom_tlv() { payment_context: PaymentContext::unknown(), }; let mut secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath::one_hop_for_payment( - nodes[2].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16, + let blinded_path = BlindedPaymentPath::new( + &[], nodes[2].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, &chanmon_cfgs[2].keys_manager, &secp_ctx ).unwrap(); let route_params = RouteParameters::from_payment_params_and_value( @@ -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.1.blinded_hops()[0].encrypted_payload, + intro_node_blinding_point: Some(blinded_path.1.blinding_point()), keysend_preimage: None, custom_tlvs: &Vec::new() }.serialized_length(); @@ -363,10 +363,9 @@ fn bolt12_invoice_too_large_blinded_paths() { htlc_maximum_msat: 42_000_000, features: BlindedHopFeatures::empty(), }, - BlindedPath { - introduction_node: IntroductionNode::NodeId(PublicKey::from_slice(&[2; 33]).unwrap()), - blinding_point: PublicKey::from_slice(&[2; 33]).unwrap(), - blinded_hops: vec![ + BlindedPaymentPath::from_raw( + PublicKey::from_slice(&[2; 33]).unwrap(), PublicKey::from_slice(&[2; 33]).unwrap(), + vec![ BlindedHop { blinded_node_id: PublicKey::from_slice(&[2; 33]).unwrap(), encrypted_payload: vec![42; 1300], @@ -375,8 +374,8 @@ fn bolt12_invoice_too_large_blinded_paths() { blinded_node_id: PublicKey::from_slice(&[2; 33]).unwrap(), encrypted_payload: vec![42; 1300], }, - ], - } + ] + ) )]); let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap(); diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index fd496b5f639..8edeefcf871 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -43,7 +43,8 @@ use bitcoin::network::Network; use bitcoin::secp256k1::{PublicKey, Secp256k1}; use core::time::Duration; -use crate::blinded_path::{BlindedPath, IntroductionNode}; +use crate::blinded_path::IntroductionNode; +use crate::blinded_path::message::BlindedMessagePath; use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentContext}; use crate::blinded_path::message::{MessageContext, OffersContext}; use crate::events::{Event, MessageSendEventsProvider, PaymentFailureReason, PaymentPurpose}; @@ -139,7 +140,7 @@ fn announce_node_address<'a, 'b, 'c>( } } -fn resolve_introduction_node<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, path: &BlindedPath) -> PublicKey { +fn resolve_introduction_node<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, path: &BlindedMessagePath) -> PublicKey { path.public_introduction_node_id(&node.network_graph.read_only()) .and_then(|node_id| node_id.as_pubkey().ok()) .unwrap() @@ -199,7 +200,7 @@ fn extract_offer_nonce<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessa fn extract_invoice_request<'a, 'b, 'c>( node: &Node<'a, 'b, 'c>, message: &OnionMessage -) -> (InvoiceRequest, BlindedPath) { +) -> (InvoiceRequest, BlindedMessagePath) { match node.onion_messenger.peel_onion_message(message) { Ok(PeeledOnion::Receive(message, _, reply_path)) => match message { ParsedOnionMessageContents::Offers(offers_message) => match offers_message { @@ -218,7 +219,7 @@ fn extract_invoice_request<'a, 'b, 'c>( } } -fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) -> (Bolt12Invoice, Option) { +fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) -> (Bolt12Invoice, Option) { match node.onion_messenger.peel_onion_message(message) { Ok(PeeledOnion::Receive(message, _, reply_path)) => match message { ParsedOnionMessageContents::Offers(offers_message) => match offers_message { @@ -401,7 +402,7 @@ fn creates_short_lived_offer() { for path in offer.paths() { let introduction_node_id = resolve_introduction_node(bob, &path); assert_eq!(introduction_node_id, alice_id); - assert!(matches!(path.introduction_node, IntroductionNode::DirectedShortChannelId(..))); + assert!(matches!(path.introduction_node(), &IntroductionNode::DirectedShortChannelId(..))); } } @@ -427,7 +428,7 @@ fn creates_long_lived_offer() { assert_eq!(offer.absolute_expiry(), Some(absolute_expiry)); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } let offer = alice.node @@ -436,7 +437,7 @@ fn creates_long_lived_offer() { assert_eq!(offer.absolute_expiry(), None); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } } @@ -465,7 +466,7 @@ fn creates_short_lived_refund() { for path in refund.paths() { let introduction_node_id = resolve_introduction_node(alice, &path); assert_eq!(introduction_node_id, bob_id); - assert!(matches!(path.introduction_node, IntroductionNode::DirectedShortChannelId(..))); + assert!(matches!(path.introduction_node(), &IntroductionNode::DirectedShortChannelId(..))); } } @@ -492,7 +493,7 @@ fn creates_long_lived_refund() { assert_eq!(refund.absolute_expiry(), Some(absolute_expiry)); assert!(!refund.paths().is_empty()); for path in refund.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } } @@ -542,7 +543,7 @@ fn creates_and_pays_for_offer_using_two_hop_blinded_path() { assert_ne!(offer.signing_pubkey(), Some(alice_id)); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } let payment_id = PaymentId([1; 32]); @@ -571,7 +572,7 @@ fn creates_and_pays_for_offer_using_two_hop_blinded_path() { }); assert_eq!(invoice_request.amount_msats(), None); assert_ne!(invoice_request.payer_id(), david_id); - assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(charlie_id)); + assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(charlie_id)); let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap(); charlie.onion_messenger.handle_onion_message(&alice_id, &onion_message); @@ -584,7 +585,7 @@ fn creates_and_pays_for_offer_using_two_hop_blinded_path() { assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); for (_, path) in invoice.payment_paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } route_bolt12_payment(david, &[charlie, bob, alice], &invoice); @@ -643,7 +644,7 @@ fn creates_and_pays_for_refund_using_two_hop_blinded_path() { assert_ne!(refund.payer_id(), david_id); assert!(!refund.paths().is_empty()); for path in refund.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(charlie_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(charlie_id)); } expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); @@ -665,7 +666,7 @@ fn creates_and_pays_for_refund_using_two_hop_blinded_path() { assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); for (_, path) in invoice.payment_paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } route_bolt12_payment(david, &[charlie, bob, alice], &invoice); @@ -699,7 +700,7 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() { assert_ne!(offer.signing_pubkey(), Some(alice_id)); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } let payment_id = PaymentId([1; 32]); @@ -720,7 +721,7 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() { }); assert_eq!(invoice_request.amount_msats(), None); assert_ne!(invoice_request.payer_id(), bob_id); - assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(bob_id)); let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap(); bob.onion_messenger.handle_onion_message(&alice_id, &onion_message); @@ -730,7 +731,7 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() { assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); for (_, path) in invoice.payment_paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } route_bolt12_payment(bob, &[alice], &invoice); @@ -768,7 +769,7 @@ fn creates_and_pays_for_refund_using_one_hop_blinded_path() { assert_ne!(refund.payer_id(), bob_id); assert!(!refund.paths().is_empty()); for path in refund.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id); @@ -785,7 +786,7 @@ fn creates_and_pays_for_refund_using_one_hop_blinded_path() { assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); for (_, path) in invoice.payment_paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } route_bolt12_payment(bob, &[alice], &invoice); @@ -943,7 +944,7 @@ fn send_invoice_requests_with_distinct_reply_path() { assert_ne!(offer.signing_pubkey(), Some(alice_id)); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } let payment_id = PaymentId([1; 32]); @@ -962,7 +963,7 @@ fn send_invoice_requests_with_distinct_reply_path() { alice.onion_messenger.handle_onion_message(&bob_id, &onion_message); let (_, reply_path) = extract_invoice_request(alice, &onion_message); - assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(charlie_id)); + assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(charlie_id)); // Send, extract and verify the second Invoice Request message let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap(); @@ -972,7 +973,7 @@ fn send_invoice_requests_with_distinct_reply_path() { alice.onion_messenger.handle_onion_message(&bob_id, &onion_message); let (_, reply_path) = extract_invoice_request(alice, &onion_message); - assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(nodes[6].node.get_our_node_id())); + assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(nodes[6].node.get_our_node_id())); } /// This test checks that when multiple potential introduction nodes are available for the payee, @@ -1027,7 +1028,7 @@ fn send_invoice_for_refund_with_distinct_reply_path() { .build().unwrap(); assert_ne!(refund.payer_id(), alice_id); for path in refund.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } expect_recent_payment!(alice, RecentPaymentDetails::AwaitingInvoice, payment_id); @@ -1043,7 +1044,7 @@ fn send_invoice_for_refund_with_distinct_reply_path() { let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap(); let (_, reply_path) = extract_invoice(alice, &onion_message); - assert_eq!(reply_path.unwrap().introduction_node, IntroductionNode::NodeId(charlie_id)); + assert_eq!(reply_path.unwrap().introduction_node(), &IntroductionNode::NodeId(charlie_id)); // Send, extract and verify the second Invoice Request message let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap(); @@ -1052,7 +1053,7 @@ fn send_invoice_for_refund_with_distinct_reply_path() { let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap(); let (_, reply_path) = extract_invoice(alice, &onion_message); - assert_eq!(reply_path.unwrap().introduction_node, IntroductionNode::NodeId(nodes[6].node.get_our_node_id())); + assert_eq!(reply_path.unwrap().introduction_node(), &IntroductionNode::NodeId(nodes[6].node.get_our_node_id())); } /// Checks that a deferred invoice can be paid asynchronously from an Event::InvoiceReceived. @@ -1109,7 +1110,7 @@ fn pays_bolt12_invoice_asynchronously() { assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); for (_, path) in invoice.payment_paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } assert!(bob.node.send_payment_for_bolt12_invoice(&invoice, context.as_ref()).is_ok()); @@ -1164,7 +1165,7 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() { assert_ne!(offer.signing_pubkey(), Some(alice_id)); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } let payment_id = PaymentId([1; 32]); @@ -1184,7 +1185,7 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() { }, }); assert_ne!(invoice_request.payer_id(), bob_id); - assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(alice_id)); + assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(alice_id)); let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap(); bob.onion_messenger.handle_onion_message(&alice_id, &onion_message); @@ -1193,7 +1194,7 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() { assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); for (_, path) in invoice.payment_paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } route_bolt12_payment(bob, &[alice], &invoice); @@ -1230,7 +1231,7 @@ fn creates_refund_with_blinded_path_using_unannounced_introduction_node() { assert_ne!(refund.payer_id(), bob_id); assert!(!refund.paths().is_empty()); for path in refund.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id)); } expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id); @@ -1243,7 +1244,7 @@ fn creates_refund_with_blinded_path_using_unannounced_introduction_node() { assert_ne!(invoice.signing_pubkey(), alice_id); assert!(!invoice.payment_paths().is_empty()); for (_, path) in invoice.payment_paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } } @@ -1294,7 +1295,7 @@ fn fails_authentication_when_handling_invoice_request() { assert_ne!(offer.signing_pubkey(), Some(alice_id)); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } let invalid_path = alice.node @@ -1303,7 +1304,7 @@ fn fails_authentication_when_handling_invoice_request() { .build().unwrap() .paths().first().unwrap() .clone(); - assert_eq!(invalid_path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(invalid_path.introduction_node(), &IntroductionNode::NodeId(bob_id)); // Send the invoice request directly to Alice instead of using a blinded path. let payment_id = PaymentId([1; 32]); @@ -1327,7 +1328,7 @@ fn fails_authentication_when_handling_invoice_request() { let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message); assert_eq!(invoice_request.amount_msats(), None); assert_ne!(invoice_request.payer_id(), david_id); - assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(charlie_id)); + assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(charlie_id)); assert_eq!(alice.onion_messenger.next_onion_message_for_peer(charlie_id), None); @@ -1360,7 +1361,7 @@ fn fails_authentication_when_handling_invoice_request() { let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message); assert_eq!(invoice_request.amount_msats(), None); assert_ne!(invoice_request.payer_id(), david_id); - assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(charlie_id)); + assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(charlie_id)); assert_eq!(alice.onion_messenger.next_onion_message_for_peer(charlie_id), None); } @@ -1411,7 +1412,7 @@ fn fails_authentication_when_handling_invoice_for_offer() { assert_ne!(offer.signing_pubkey(), Some(alice_id)); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id)); } // Initiate an invoice request, but abandon tracking it. @@ -1465,7 +1466,7 @@ fn fails_authentication_when_handling_invoice_for_offer() { let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message); assert_eq!(invoice_request.amount_msats(), None); assert_ne!(invoice_request.payer_id(), david_id); - assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(charlie_id)); + assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(charlie_id)); let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap(); charlie.onion_messenger.handle_onion_message(&alice_id, &onion_message); @@ -1522,7 +1523,7 @@ fn fails_authentication_when_handling_invoice_for_refund() { assert_ne!(refund.payer_id(), david_id); assert!(!refund.paths().is_empty()); for path in refund.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(charlie_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(charlie_id)); } expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); @@ -1559,7 +1560,7 @@ fn fails_authentication_when_handling_invoice_for_refund() { assert_ne!(refund.payer_id(), david_id); assert!(!refund.paths().is_empty()); for path in refund.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(charlie_id)); + assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(charlie_id)); } let expected_invoice = alice.node.request_refund_payment(&refund).unwrap(); diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index d6fe281d1d3..70a7c6bf8bb 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -340,8 +340,8 @@ pub(crate) fn set_max_path_length( .map(|(_, path)| path) .max_by_key(|path| path.serialized_length()) .map(|largest_path| BlindedTailHopIter { - hops: largest_path.blinded_hops.iter(), - blinding_point: largest_path.blinding_point, + hops: largest_path.blinded_hops().iter(), + blinding_point: largest_path.blinding_point(), final_value_msat: final_value_msat_with_overpay_buffer, excess_final_cltv_expiry_delta: 0, }); diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index c36f2c5c1a9..aff2367779b 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -14,7 +14,6 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{self, Secp256k1, SecretKey}; use crate::blinded_path::{IntroductionNode, NodeIdLookUp}; -use crate::blinded_path::payment::advance_path_by_one; use crate::events::{self, PaymentFailureReason}; use crate::ln::types::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::ln::channel_state::ChannelDetails; @@ -428,10 +427,10 @@ pub enum RetryableSendFailure { /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed DuplicatePayment, /// The [`RecipientOnionFields::payment_metadata`], [`RecipientOnionFields::custom_tlvs`], or - /// [`BlindedPath`]s provided are too large and caused us to exceed the maximum onion packet size - /// of 1300 bytes. + /// [`BlindedPaymentPath`]s provided are too large and caused us to exceed the maximum onion + /// packet size of 1300 bytes. /// - /// [`BlindedPath`]: crate::blinded_path::BlindedPath + /// [`BlindedPaymentPath`]: crate::blinded_path::payment::BlindedPaymentPath OnionPacketSizeExceeded, } @@ -835,17 +834,17 @@ 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() { - let introduction_node_id = match path.introduction_node { - IntroductionNode::NodeId(pubkey) => pubkey, + let introduction_node_id = match path.introduction_node() { + IntroductionNode::NodeId(pubkey) => *pubkey, IntroductionNode::DirectedShortChannelId(direction, scid) => { - match node_id_lookup.next_node_id(scid) { + match node_id_lookup.next_node_id(*scid) { Some(next_node_id) => *direction.select_pubkey(&our_node_id, &next_node_id), None => continue, } }, }; if introduction_node_id == our_node_id { - let _ = advance_path_by_one(path, node_signer, node_id_lookup, secp_ctx); + let _ = path.advance_path_by_one(node_signer, node_id_lookup, secp_ctx); } } } diff --git a/lightning/src/offers/invoice.rs b/lightning/src/offers/invoice.rs index 3fd2e73aa5b..1769a5d7001 100644 --- a/lightning/src/offers/invoice.rs +++ b/lightning/src/offers/invoice.rs @@ -14,7 +14,7 @@ //! then sends the invoice to the intended payer, who will then pay it. //! //! The payment recipient must include a [`PaymentHash`], so as to reveal the preimage upon payment -//! receipt, and one or more [`BlindedPath`]s for the payer to use when sending the payment. +//! receipt, and one or more [`BlindedPaymentPath`]s for the payer to use when sending the payment. //! //! ``` //! extern crate bitcoin; @@ -30,9 +30,9 @@ //! //! # use lightning::ln::types::PaymentHash; //! # use lightning::offers::invoice::{BlindedPayInfo, ExplicitSigningPubkey, InvoiceBuilder}; -//! # use lightning::blinded_path::BlindedPath; +//! # use lightning::blinded_path::payment::BlindedPaymentPath; //! # -//! # fn create_payment_paths() -> Vec<(BlindedPayInfo, BlindedPath)> { unimplemented!() } +//! # fn create_payment_paths() -> Vec<(BlindedPayInfo, BlindedPaymentPath)> { unimplemented!() } //! # fn create_payment_hash() -> PaymentHash { unimplemented!() } //! # //! # fn parse_invoice_request(bytes: Vec) -> Result<(), lightning::offers::parse::Bolt12ParseError> { @@ -110,7 +110,8 @@ use bitcoin::address::{Address, Payload}; 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; use crate::ln::channelmanager::PaymentId; use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures}; @@ -211,7 +212,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, BlindedPath)>, + invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration, payment_hash: PaymentHash, signing_pubkey: PublicKey ) -> Result { let amount_msats = Self::amount_msats(invoice_request)?; @@ -227,7 +228,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, BlindedPath)>, created_at: Duration, + refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration, payment_hash: PaymentHash, signing_pubkey: PublicKey ) -> Result { let amount_msats = refund.amount_msats(); @@ -269,7 +270,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, BlindedPath)>, + invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration, payment_hash: PaymentHash, keys: Keypair ) -> Result { let amount_msats = Self::amount_msats(invoice_request)?; @@ -286,7 +287,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, BlindedPath)>, created_at: Duration, + refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration, payment_hash: PaymentHash, keys: Keypair, ) -> Result { let amount_msats = refund.amount_msats(); @@ -355,7 +356,7 @@ macro_rules! invoice_builder_methods { ( #[cfg_attr(c_bindings, allow(dead_code))] fn fields( - payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration, + payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration, payment_hash: PaymentHash, amount_msats: u64, signing_pubkey: PublicKey ) -> InvoiceFields { InvoiceFields { @@ -602,7 +603,7 @@ enum InvoiceContents { /// Invoice-specific fields for an `invoice` message. #[derive(Clone, Debug, PartialEq)] struct InvoiceFields { - payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, + payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration, relative_expiry: Option, payment_hash: PaymentHash, @@ -698,7 +699,7 @@ macro_rules! invoice_accessors { ($self: ident, $contents: expr) => { /// From [`Offer::paths`] or [`Refund::paths`]. /// /// [`Offer::paths`]: crate::offers::offer::Offer::paths - pub fn message_paths(&$self) -> &[BlindedPath] { + pub fn message_paths(&$self) -> &[BlindedMessagePath] { $contents.message_paths() } @@ -797,7 +798,7 @@ impl Bolt12Invoice { } /// Verifies that the invoice was for a request or refund created using the given key by - /// checking a payment id and nonce included with the [`BlindedPath`] for which the invoice was + /// checking a payment id and nonce included with the [`BlindedMessagePath`] for which the invoice was /// sent through. pub fn verify_using_payer_data( &self, payment_id: PaymentId, nonce: Nonce, key: &ExpandedKey, secp_ctx: &Secp256k1 @@ -934,7 +935,7 @@ impl InvoiceContents { } } - fn message_paths(&self) -> &[BlindedPath] { + fn message_paths(&self) -> &[BlindedMessagePath] { match self { InvoiceContents::ForOffer { invoice_request, .. } => { invoice_request.inner.offer.paths() @@ -987,7 +988,7 @@ impl InvoiceContents { } } - fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPath)] { + fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPaymentPath)] { &self.fields().payment_paths[..] } @@ -1192,7 +1193,7 @@ impl TryFrom> for Bolt12Invoice { } tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef, 160..240, { - (160, paths: (Vec, WithoutLength, Iterable<'a, BlindedPathIter<'a>, BlindedPath>)), + (160, paths: (Vec, WithoutLength, Iterable<'a, BlindedPathIter<'a>, BlindedPaymentPath>)), (162, blindedpay: (Vec, WithoutLength, Iterable<'a, BlindedPayInfoIter<'a>, BlindedPayInfo>)), (164, created_at: (u64, HighZeroBytesDroppedBigSize)), (166, relative_expiry: (u32, HighZeroBytesDroppedBigSize)), @@ -1202,20 +1203,20 @@ tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef, 160..240, { (174, features: (Bolt12InvoiceFeatures, WithoutLength)), (176, node_id: PublicKey), // Only present in `StaticInvoice`s. - (238, message_paths: (Vec, WithoutLength)), + (238, message_paths: (Vec, WithoutLength)), }); pub(super) type BlindedPathIter<'a> = core::iter::Map< - core::slice::Iter<'a, (BlindedPayInfo, BlindedPath)>, - for<'r> fn(&'r (BlindedPayInfo, BlindedPath)) -> &'r BlindedPath, + core::slice::Iter<'a, (BlindedPayInfo, BlindedPaymentPath)>, + for<'r> fn(&'r (BlindedPayInfo, BlindedPaymentPath)) -> &'r BlindedPaymentPath, >; pub(super) type BlindedPayInfoIter<'a> = core::iter::Map< - core::slice::Iter<'a, (BlindedPayInfo, BlindedPath)>, - for<'r> fn(&'r (BlindedPayInfo, BlindedPath)) -> &'r BlindedPayInfo, + core::slice::Iter<'a, (BlindedPayInfo, BlindedPaymentPath)>, + for<'r> fn(&'r (BlindedPayInfo, BlindedPaymentPath)) -> &'r BlindedPayInfo, >; -/// Information needed to route a payment across a [`BlindedPath`]. +/// Information needed to route a payment across a [`BlindedPaymentPath`]. #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct BlindedPayInfo { /// Base fee charged (in millisatoshi) for the entire blinded path. @@ -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), @@ -1414,7 +1415,7 @@ pub(super) fn check_invoice_signing_pubkey( (None, Some(paths)) => { if !paths .iter() - .filter_map(|path| path.blinded_hops.last()) + .filter_map(|path| path.blinded_hops().last()) .any(|last_hop| invoice_signing_pubkey == &last_hop.blinded_node_id) { return Err(Bolt12SemanticError::InvalidSigningPubkey); @@ -1440,7 +1441,8 @@ mod tests { use core::time::Duration; - use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; + use crate::blinded_path::BlindedHop; + use crate::blinded_path::message::BlindedMessagePath; use crate::sign::KeyMaterial; use crate::ln::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures}; use crate::ln::inbound_payment::ExpandedKey; @@ -1789,14 +1791,13 @@ mod tests { let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + let blinded_path = BlindedMessagePath::from_raw( + pubkey(40), pubkey(41), + vec![ BlindedHop { blinded_node_id: pubkey(42), encrypted_payload: vec![0; 43] }, BlindedHop { blinded_node_id: node_id, encrypted_payload: vec![0; 44] }, - ], - }; + ] + ); #[cfg(c_bindings)] use crate::offers::offer::OfferWithDerivedMetadataBuilder as OfferBuilder; @@ -1865,14 +1866,13 @@ mod tests { let entropy = FixedEntropy {}; let secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + let blinded_path = BlindedMessagePath::from_raw( + pubkey(40), pubkey(41), + vec![ BlindedHop { blinded_node_id: pubkey(42), encrypted_payload: vec![0; 43] }, BlindedHop { blinded_node_id: node_id, encrypted_payload: vec![0; 44] }, - ], - }; + ] + ); let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap() .path(blinded_path) @@ -2369,22 +2369,20 @@ mod tests { #[test] fn parses_invoice_with_node_id_from_blinded_path() { let paths = vec![ - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + BlindedMessagePath::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] }, - ], - }, - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + ] + ), + BlindedMessagePath::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] }, - ], - }, + ] + ), ]; let blinded_node_id_sign = |message: &UnsignedBolt12Invoice| { @@ -2522,14 +2520,13 @@ mod tests { .build().unwrap() .sign(recipient_sign).unwrap(); - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + let blinded_path = BlindedMessagePath::from_raw( + pubkey(40), pubkey(41), + vec![ BlindedHop { blinded_node_id: pubkey(42), encrypted_payload: vec![0; 43] }, BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 44] }, - ], - }; + ] + ); let mut tlv_stream = invoice.as_tlv_stream(); let message_paths = vec![blinded_path]; diff --git a/lightning/src/offers/invoice_macros.rs b/lightning/src/offers/invoice_macros.rs index c603c352ce9..a06c0663a0f 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, BlindedPath)] { + pub fn payment_paths(&$self) -> &[(BlindedPayInfo, BlindedPaymentPath)] { $contents.payment_paths() } diff --git a/lightning/src/offers/invoice_request.rs b/lightning/src/offers/invoice_request.rs index 6ed9b2a1295..01083b7b74b 100644 --- a/lightning/src/offers/invoice_request.rs +++ b/lightning/src/offers/invoice_request.rs @@ -62,7 +62,8 @@ use bitcoin::network::Network; use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, self}; use bitcoin::secp256k1::schnorr::Signature; 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; use crate::ln::channelmanager::PaymentId; use crate::ln::features::InvoiceRequestFeatures; @@ -707,7 +708,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, BlindedPath)>, payment_hash: PaymentHash + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash ) -> Result<$builder, Bolt12SemanticError> { let created_at = std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) @@ -742,7 +743,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, BlindedPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, created_at: core::time::Duration ) -> Result<$builder, Bolt12SemanticError> { if $contents.invoice_request_features().requires_unknown_bits() { @@ -760,7 +761,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, BlindedPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, created_at: core::time::Duration, signing_pubkey: PublicKey ) -> Result<$builder, Bolt12SemanticError> { debug_assert!($contents.contents.inner.offer.signing_pubkey().is_none()); @@ -804,7 +805,7 @@ macro_rules! invoice_request_verify_method { ($self: ident, $self_type: ty) => { } /// Verifies that the request was for an offer created using the given key by checking a nonce - /// included with the [`BlindedPath`] for which the request was sent through. + /// included with the [`BlindedMessagePath`] for which the request was sent through. /// /// Returns the verified request which contains the derived keys needed to sign a /// [`Bolt12Invoice`] for the request if they could be extracted from the metadata. @@ -880,7 +881,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, BlindedPath)>, payment_hash: PaymentHash + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash ) -> Result<$builder, Bolt12SemanticError> { let created_at = std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) @@ -897,7 +898,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, BlindedPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, created_at: core::time::Duration ) -> Result<$builder, Bolt12SemanticError> { if $self.inner.invoice_request_features().requires_unknown_bits() { @@ -1057,7 +1058,7 @@ tlv_stream!(InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef, INVOICE_REQUEST (INVOICE_REQUEST_PAYER_ID_TYPE, payer_id: PublicKey), (89, payer_note: (String, WithoutLength)), // Only used for Refund since the onion message of an InvoiceRequest has a reply path. - (90, paths: (Vec, WithoutLength)), + (90, paths: (Vec, WithoutLength)), }); type FullInvoiceRequestTlvStream = diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index e314f712c2d..96cd4465c96 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -29,12 +29,12 @@ //! use lightning::offers::parse::Bolt12ParseError; //! use lightning::util::ser::{Readable, Writeable}; //! -//! # use lightning::blinded_path::BlindedPath; +//! # use lightning::blinded_path::message::BlindedMessagePath; //! # #[cfg(feature = "std")] //! # use std::time::SystemTime; //! # -//! # fn create_blinded_path() -> BlindedPath { unimplemented!() } -//! # fn create_another_blinded_path() -> BlindedPath { unimplemented!() } +//! # fn create_blinded_path() -> BlindedMessagePath { unimplemented!() } +//! # fn create_another_blinded_path() -> BlindedMessagePath { unimplemented!() } //! # //! # #[cfg(feature = "std")] //! # fn build() -> Result<(), Bolt12ParseError> { @@ -85,7 +85,7 @@ use core::num::NonZeroU64; use core::str::FromStr; use core::time::Duration; use crate::io; -use crate::blinded_path::BlindedPath; +use crate::blinded_path::message::BlindedMessagePath; use crate::ln::channelmanager::PaymentId; use crate::ln::features::OfferFeatures; use crate::ln::inbound_payment::{ExpandedKey, IV_LEN}; @@ -249,7 +249,7 @@ macro_rules! offer_derived_metadata_builder_methods { ($secp_context: ty) => { /// Also, sets the metadata when [`OfferBuilder::build`] is called such that it can be used by /// [`InvoiceRequest::verify_using_metadata`] to determine if the request was produced for the /// offer given an [`ExpandedKey`]. However, if [`OfferBuilder::path`] is called, then the - /// metadata will not be set and must be included in each [`BlindedPath`] instead. In this case, + /// metadata will not be set and must be included in each [`BlindedMessagePath`] instead. In this case, /// use [`InvoiceRequest::verify_using_recipient_data`]. /// /// [`InvoiceRequest::verify_using_metadata`]: crate::offers::invoice_request::InvoiceRequest::verify_using_metadata @@ -346,7 +346,7 @@ macro_rules! offer_builder_methods { ( /// /// Successive calls to this method will add another blinded path. Caller is responsible for not /// adding duplicate paths. - pub fn path($($self_mut)* $self: $self_type, path: BlindedPath) -> $return_type { + pub fn path($($self_mut)* $self: $self_type, path: BlindedMessagePath) -> $return_type { $self.offer.paths.get_or_insert_with(Vec::new).push(path); $return_value } @@ -540,7 +540,7 @@ for OfferBuilder<'a, DerivedMetadata, secp256k1::All> { /// Offers may be denominated in currency other than bitcoin but are ultimately paid using the /// latter. /// -/// Through the use of [`BlindedPath`]s, offers provide recipient privacy. +/// Through the use of [`BlindedMessagePath`]s, offers provide recipient privacy. /// /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice @@ -568,7 +568,7 @@ pub(super) struct OfferContents { features: OfferFeatures, absolute_expiry: Option, issuer: Option, - paths: Option>, + paths: Option>, supported_quantity: Quantity, signing_pubkey: Option, } @@ -622,7 +622,7 @@ macro_rules! offer_accessors { ($self: ident, $contents: expr) => { /// Paths to the recipient originating from publicly reachable nodes. Blinded paths provide /// recipient privacy by obfuscating its node id. - pub fn paths(&$self) -> &[$crate::blinded_path::BlindedPath] { + pub fn paths(&$self) -> &[$crate::blinded_path::message::BlindedMessagePath] { $contents.paths() } @@ -854,7 +854,7 @@ impl OfferContents { self.issuer.as_ref().map(|issuer| PrintableString(issuer.as_str())) } - pub fn paths(&self) -> &[BlindedPath] { + pub fn paths(&self) -> &[BlindedMessagePath] { self.paths.as_ref().map(|paths| paths.as_slice()).unwrap_or(&[]) } @@ -1074,7 +1074,7 @@ tlv_stream!(OfferTlvStream, OfferTlvStreamRef, OFFER_TYPES, { (10, description: (String, WithoutLength)), (12, features: (OfferFeatures, WithoutLength)), (14, absolute_expiry: (u64, HighZeroBytesDroppedBigSize)), - (16, paths: (Vec, WithoutLength)), + (16, paths: (Vec, WithoutLength)), (18, issuer: (String, WithoutLength)), (20, quantity_max: (u64, HighZeroBytesDroppedBigSize)), (OFFER_NODE_ID_TYPE, node_id: PublicKey), @@ -1177,7 +1177,8 @@ mod tests { use bitcoin::secp256k1::Secp256k1; use core::num::NonZeroU64; use core::time::Duration; - use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; + use crate::blinded_path::BlindedHop; + use crate::blinded_path::message::BlindedMessagePath; use crate::sign::KeyMaterial; use crate::ln::features::OfferFeatures; use crate::ln::inbound_payment::ExpandedKey; @@ -1360,14 +1361,13 @@ mod tests { let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + let blinded_path = BlindedMessagePath::from_raw( + pubkey(40), pubkey(41), + vec![ BlindedHop { blinded_node_id: pubkey(42), encrypted_payload: vec![0; 43] }, BlindedHop { blinded_node_id: node_id, encrypted_payload: vec![0; 44] }, - ], - }; + ] + ); #[cfg(c_bindings)] use super::OfferWithDerivedMetadataBuilder as OfferBuilder; @@ -1544,22 +1544,20 @@ mod tests { #[test] fn builds_offer_with_paths() { let paths = vec![ - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + BlindedMessagePath::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] }, - ], - }, - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + ] + ), + BlindedMessagePath::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] }, - ], - }, + ] + ), ]; let offer = OfferBuilder::new(pubkey(42)) @@ -1747,22 +1745,20 @@ mod tests { #[test] fn parses_offer_with_paths() { let offer = OfferBuilder::new(pubkey(42)) - .path(BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + .path(BlindedMessagePath::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] }, - ], - }) - .path(BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ - BlindedHop { blinded_node_id: pubkey(45), encrypted_payload: vec![0; 45] }, - BlindedHop { blinded_node_id: pubkey(46), encrypted_payload: vec![0; 46] }, - ], - }) + ] + )) + .path(BlindedMessagePath::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] }, + ] + )) .build() .unwrap(); if let Err(e) = offer.to_string().parse::() { @@ -1770,14 +1766,13 @@ mod tests { } let offer = OfferBuilder::new(pubkey(42)) - .path(BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ - BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 43] }, - BlindedHop { blinded_node_id: pubkey(44), encrypted_payload: vec![0; 44] }, - ], - }) + .path(BlindedMessagePath::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] }, + ] + )) .clear_signing_pubkey() .build() .unwrap(); diff --git a/lightning/src/offers/refund.rs b/lightning/src/offers/refund.rs index 10f56f0a14c..479fe6746af 100644 --- a/lightning/src/offers/refund.rs +++ b/lightning/src/offers/refund.rs @@ -34,12 +34,12 @@ //! use lightning::offers::refund::{Refund, RefundBuilder}; //! use lightning::util::ser::{Readable, Writeable}; //! -//! # use lightning::blinded_path::BlindedPath; +//! # use lightning::blinded_path::message::BlindedMessagePath; //! # #[cfg(feature = "std")] //! # use std::time::SystemTime; //! # -//! # fn create_blinded_path() -> BlindedPath { unimplemented!() } -//! # fn create_another_blinded_path() -> BlindedPath { unimplemented!() } +//! # fn create_blinded_path() -> BlindedMessagePath { unimplemented!() } +//! # fn create_another_blinded_path() -> BlindedMessagePath { unimplemented!() } //! # //! # #[cfg(feature = "std")] //! # fn build() -> Result<(), Bolt12ParseError> { @@ -91,7 +91,8 @@ use core::str::FromStr; use core::time::Duration; use crate::sign::EntropySource; 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; use crate::ln::channelmanager::PaymentId; use crate::ln::features::InvoiceRequestFeatures; @@ -193,7 +194,7 @@ macro_rules! refund_builder_methods { ( /// Also, sets the metadata when [`RefundBuilder::build`] is called such that it can be used by /// [`Bolt12Invoice::verify_using_metadata`] to determine if the invoice was produced for the /// refund given an [`ExpandedKey`]. However, if [`RefundBuilder::path`] is called, then the - /// metadata must be included in each [`BlindedPath`] instead. In this case, use + /// metadata must be included in each [`BlindedMessagePath`] instead. In this case, use /// [`Bolt12Invoice::verify_using_payer_data`]. /// /// The `payment_id` is encrypted in the metadata and should be unique. This ensures that only @@ -253,7 +254,7 @@ macro_rules! refund_builder_methods { ( /// /// Successive calls to this method will add another blinded path. Caller is responsible for not /// adding duplicate paths. - pub fn path($($self_mut)* $self: $self_type, path: BlindedPath) -> $return_type { + pub fn path($($self_mut)* $self: $self_type, path: BlindedMessagePath) -> $return_type { $self.refund.paths.get_or_insert_with(Vec::new).push(path); $return_value } @@ -436,7 +437,7 @@ pub(super) struct RefundContents { quantity: Option, payer_id: PublicKey, payer_note: Option, - paths: Option>, + paths: Option>, } impl Refund { @@ -472,7 +473,7 @@ impl Refund { /// Paths to the sender originating from publicly reachable nodes. Blinded paths provide sender /// privacy by obfuscating its node id. - pub fn paths(&self) -> &[BlindedPath] { + pub fn paths(&self) -> &[BlindedMessagePath] { self.contents.paths() } @@ -532,7 +533,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, BlindedPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, signing_pubkey: PublicKey, ) -> Result<$builder, Bolt12SemanticError> { let created_at = std::time::SystemTime::now() @@ -565,7 +566,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, BlindedPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, signing_pubkey: PublicKey, created_at: Duration ) -> Result<$builder, Bolt12SemanticError> { if $self.features().requires_unknown_bits() { @@ -587,7 +588,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, BlindedPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, expanded_key: &ExpandedKey, entropy_source: ES ) -> Result<$builder, Bolt12SemanticError> where @@ -611,7 +612,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, BlindedPath)>, payment_hash: PaymentHash, + &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash, created_at: core::time::Duration, expanded_key: &ExpandedKey, entropy_source: ES ) -> Result<$builder, Bolt12SemanticError> where @@ -693,7 +694,7 @@ impl RefundContents { self.issuer.as_ref().map(|issuer| PrintableString(issuer.as_str())) } - pub fn paths(&self) -> &[BlindedPath] { + pub fn paths(&self) -> &[BlindedMessagePath] { self.paths.as_ref().map(|paths| paths.as_slice()).unwrap_or(&[]) } @@ -937,7 +938,8 @@ mod tests { use core::time::Duration; - use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; + use crate::blinded_path::BlindedHop; + use crate::blinded_path::message::BlindedMessagePath; use crate::sign::KeyMaterial; use crate::ln::channelmanager::PaymentId; use crate::ln::features::{InvoiceRequestFeatures, OfferFeatures}; @@ -1096,14 +1098,13 @@ mod tests { let secp_ctx = Secp256k1::new(); let payment_id = PaymentId([1; 32]); - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + let blinded_path = BlindedMessagePath::from_raw( + pubkey(40), pubkey(41), + vec![ BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 43] }, BlindedHop { blinded_node_id: node_id, encrypted_payload: vec![0; 44] }, - ], - }; + ] + ); let refund = RefundBuilder ::deriving_payer_id(node_id, &expanded_key, nonce, &secp_ctx, 1000, payment_id) @@ -1189,22 +1190,20 @@ mod tests { #[test] fn builds_refund_with_paths() { let paths = vec![ - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + BlindedMessagePath::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] }, - ], - }, - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + ] + ), + BlindedMessagePath::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] }, - ], - }, + ] + ), ]; let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap() @@ -1406,22 +1405,20 @@ mod tests { fn parses_refund_with_optional_fields() { let past_expiry = Duration::from_secs(0); let paths = vec![ - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + BlindedMessagePath::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] }, - ], - }, - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + ] + ), + BlindedMessagePath::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] }, - ], - }, + ] + ), ]; let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap() diff --git a/lightning/src/offers/static_invoice.rs b/lightning/src/offers/static_invoice.rs index c91496e17a1..413cfff2950 100644 --- a/lightning/src/offers/static_invoice.rs +++ b/lightning/src/offers/static_invoice.rs @@ -9,7 +9,8 @@ //! Data structures and encoding for static BOLT 12 invoices. -use crate::blinded_path::BlindedPath; +use crate::blinded_path::message::BlindedMessagePath; +use crate::blinded_path::payment::BlindedPaymentPath; use crate::io; use crate::ln::features::{Bolt12InvoiceFeatures, OfferFeatures}; use crate::ln::inbound_payment::ExpandedKey; @@ -70,13 +71,13 @@ pub struct StaticInvoice { #[derive(Clone, Debug)] struct InvoiceContents { offer: OfferContents, - payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, + payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration, relative_expiry: Option, fallbacks: Option>, features: Bolt12InvoiceFeatures, signing_pubkey: PublicKey, - message_paths: Vec, + message_paths: Vec, } /// Builds a [`StaticInvoice`] from an [`Offer`]. @@ -96,8 +97,8 @@ 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, BlindedPath)>, - message_paths: Vec, created_at: Duration, expanded_key: &ExpandedKey, + offer: &'a Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, + message_paths: Vec, created_at: Duration, expanded_key: &ExpandedKey, nonce: Nonce, secp_ctx: &Secp256k1, ) -> Result { if offer.chains().len() > 1 { @@ -223,13 +224,13 @@ macro_rules! invoice_accessors { ($self: ident, $contents: expr) => { /// publicly reachable nodes. Taken from [`Offer::paths`]. /// /// [`Offer::paths`]: crate::offers::offer::Offer::paths - pub fn offer_message_paths(&$self) -> &[BlindedPath] { + pub fn offer_message_paths(&$self) -> &[BlindedMessagePath] { $contents.offer_message_paths() } /// Paths to the recipient for indicating that a held HTLC is available to claim when they next /// come online. - pub fn message_paths(&$self) -> &[BlindedPath] { + pub fn message_paths(&$self) -> &[BlindedMessagePath] { $contents.message_paths() } @@ -325,8 +326,8 @@ impl InvoiceContents { } fn new( - offer: &Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, - message_paths: Vec, created_at: Duration, signing_pubkey: PublicKey, + offer: &Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, + message_paths: Vec, created_at: Duration, signing_pubkey: PublicKey, ) -> Self { Self { offer: offer.contents.clone(), @@ -394,11 +395,11 @@ impl InvoiceContents { self.offer.issuer() } - fn offer_message_paths(&self) -> &[BlindedPath] { + fn offer_message_paths(&self) -> &[BlindedMessagePath] { self.offer.paths() } - fn message_paths(&self) -> &[BlindedPath] { + fn message_paths(&self) -> &[BlindedMessagePath] { &self.message_paths[..] } @@ -406,7 +407,7 @@ impl InvoiceContents { self.offer.supported_quantity() } - fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPath)] { + fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPaymentPath)] { &self.payment_paths[..] } @@ -559,7 +560,8 @@ impl TryFrom for InvoiceContents { #[cfg(test)] mod tests { - use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; + use crate::blinded_path::message::BlindedMessagePath; + use crate::blinded_path::BlindedHop; use crate::ln::features::{Bolt12InvoiceFeatures, OfferFeatures}; use crate::ln::inbound_payment::ExpandedKey; use crate::ln::msgs::DecodeError; @@ -632,15 +634,15 @@ mod tests { .unwrap() } - fn blinded_path() -> BlindedPath { - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + fn blinded_path() -> BlindedMessagePath { + BlindedMessagePath::from_raw( + pubkey(40), + pubkey(41), + vec![ BlindedHop { blinded_node_id: pubkey(42), encrypted_payload: vec![0; 43] }, BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 44] }, ], - } + ) } #[test] diff --git a/lightning/src/offers/test_utils.rs b/lightning/src/offers/test_utils.rs index 0c35ee28598..588c167bf5f 100644 --- a/lightning/src/offers/test_utils.rs +++ b/lightning/src/offers/test_utils.rs @@ -13,7 +13,8 @@ use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey}; use bitcoin::secp256k1::schnorr::Signature; use core::time::Duration; -use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; +use crate::blinded_path::BlindedHop; +use crate::blinded_path::payment::BlindedPaymentPath; use crate::sign::EntropySource; use crate::ln::types::PaymentHash; use crate::ln::features::BlindedHopFeatures; @@ -66,24 +67,22 @@ pub(super) fn privkey(byte: u8) -> SecretKey { SecretKey::from_slice(&[byte; 32]).unwrap() } -pub(crate) fn payment_paths() -> Vec<(BlindedPayInfo, BlindedPath)> { +pub(crate) fn payment_paths() -> Vec<(BlindedPayInfo, BlindedPaymentPath)> { let paths = vec![ - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: 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] }, - ], - }, - BlindedPath { - introduction_node: IntroductionNode::NodeId(pubkey(40)), - blinding_point: pubkey(41), - blinded_hops: vec![ + ] + ), + 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] }, - ], - }, + ] + ), ]; let payinfo = vec![ diff --git a/lightning/src/onion_message/async_payments.rs b/lightning/src/onion_message/async_payments.rs index d0200101ff7..4a080101915 100644 --- a/lightning/src/onion_message/async_payments.rs +++ b/lightning/src/onion_message/async_payments.rs @@ -55,7 +55,7 @@ pub trait AsyncPaymentsMessageHandler { ) -> Vec<( AsyncPaymentsMessage, crate::onion_message::messenger::Destination, - Option, + Option, )> { vec![] } diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 7df69b82348..508e7982b40 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -9,8 +9,8 @@ //! Onion message testing and test utilities live here. -use crate::blinded_path::{BlindedPath, EmptyNodeIdLookUp}; -use crate::blinded_path::message::{ForwardNode, MessageContext, OffersContext}; +use crate::blinded_path::EmptyNodeIdLookUp; +use crate::blinded_path::message::{BlindedMessagePath, ForwardNode, MessageContext, OffersContext}; use crate::events::{Event, EventsProvider}; use crate::ln::features::{ChannelFeatures, InitFeatures}; use crate::ln::msgs::{self, DecodeError, OnionMessageHandler}; @@ -373,7 +373,7 @@ fn one_blinded_hop() { let secp_ctx = Secp256k1::new(); let context = MessageContext::Custom(Vec::new()); - let blinded_path = BlindedPath::new_for_message(&[], nodes[1].node_id, context, &*nodes[1].entropy_source, &secp_ctx).unwrap(); + let blinded_path = BlindedMessagePath::new(&[], nodes[1].node_id, context, &*nodes[1].entropy_source, &secp_ctx).unwrap(); let destination = Destination::BlindedPath(blinded_path); nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); nodes[1].custom_message_handler.expect_message(TestCustomMessage::Pong); @@ -388,7 +388,7 @@ fn two_unblinded_two_blinded() { let secp_ctx = Secp256k1::new(); let intermediate_nodes = [ForwardNode { node_id: nodes[3].node_id, short_channel_id: None }]; let context = MessageContext::Custom(Vec::new()); - let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[4].node_id, context, &*nodes[4].entropy_source, &secp_ctx).unwrap(); + let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[4].node_id, context, &*nodes[4].entropy_source, &secp_ctx).unwrap(); let path = OnionMessagePath { intermediate_nodes: vec![nodes[1].node_id, nodes[2].node_id], destination: Destination::BlindedPath(blinded_path), @@ -411,7 +411,7 @@ fn three_blinded_hops() { ForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, ]; let context = MessageContext::Custom(Vec::new()); - let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[3].node_id, context, &*nodes[3].entropy_source, &secp_ctx).unwrap(); + let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[3].node_id, context, &*nodes[3].entropy_source, &secp_ctx).unwrap(); let destination = Destination::BlindedPath(blinded_path); nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); @@ -434,7 +434,7 @@ fn async_response_over_one_blinded_hop() { // 3. Simulate the creation of a Blinded Reply path provided by Bob. let secp_ctx = Secp256k1::new(); let context = MessageContext::Custom(Vec::new()); - let reply_path = BlindedPath::new_for_message(&[], nodes[1].node_id, context, &*nodes[1].entropy_source, &secp_ctx).unwrap(); + let reply_path = BlindedMessagePath::new(&[], nodes[1].node_id, context, &*nodes[1].entropy_source, &secp_ctx).unwrap(); // 4. Create a responder using the reply path for Alice. let responder = Some(Responder::new(reply_path)); @@ -470,7 +470,7 @@ fn async_response_with_reply_path_succeeds() { // Alice receives a message from Bob with an added reply_path for responding back. let message = TestCustomMessage::Ping; let context = MessageContext::Custom(Vec::new()); - let reply_path = BlindedPath::new_for_message(&[], bob.node_id, context, &*bob.entropy_source, &secp_ctx).unwrap(); + let reply_path = BlindedMessagePath::new(&[], bob.node_id, context, &*bob.entropy_source, &secp_ctx).unwrap(); // Alice asynchronously responds to Bob, expecting a response back from him. let responder = Responder::new(reply_path); @@ -507,7 +507,7 @@ fn async_response_with_reply_path_fails() { // Alice receives a message from Bob with an added reply_path for responding back. let message = TestCustomMessage::Ping; let context = MessageContext::Custom(Vec::new()); - let reply_path = BlindedPath::new_for_message(&[], bob.node_id, context, &*bob.entropy_source, &secp_ctx).unwrap(); + let reply_path = BlindedMessagePath::new(&[], bob.node_id, context, &*bob.entropy_source, &secp_ctx).unwrap(); // Alice tries to asynchronously respond to Bob, but fails because the nodes are unannounced and // disconnected. Thus, a reply path could no be created for the response. @@ -552,7 +552,7 @@ fn we_are_intro_node() { ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, ]; let context = MessageContext::Custom(Vec::new()); - let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx).unwrap(); + let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx).unwrap(); let destination = Destination::BlindedPath(blinded_path); nodes[0].messenger.send_onion_message(test_msg.clone(), destination, None).unwrap(); @@ -562,7 +562,7 @@ fn we_are_intro_node() { // Try with a two-hop blinded path where we are the introduction node. let intermediate_nodes = [ForwardNode { node_id: nodes[0].node_id, short_channel_id: None }]; let context = MessageContext::Custom(Vec::new()); - let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[1].node_id, context, &*nodes[1].entropy_source, &secp_ctx).unwrap(); + let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[1].node_id, context, &*nodes[1].entropy_source, &secp_ctx).unwrap(); let destination = Destination::BlindedPath(blinded_path); nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); nodes[1].custom_message_handler.expect_message(TestCustomMessage::Pong); @@ -579,8 +579,8 @@ fn invalid_blinded_path_error() { let secp_ctx = Secp256k1::new(); let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; let context = MessageContext::Custom(Vec::new()); - let mut blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx).unwrap(); - blinded_path.blinded_hops.clear(); + let mut blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx).unwrap(); + blinded_path.clear_blinded_hops(); let destination = Destination::BlindedPath(blinded_path); let err = nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap_err(); assert_eq!(err, SendError::TooFewBlindedHops); @@ -603,7 +603,7 @@ fn reply_path() { ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, ]; let context = MessageContext::Custom(Vec::new()); - let reply_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[0].node_id, context, &*nodes[0].entropy_source, &secp_ctx).unwrap(); + let reply_path = BlindedMessagePath::new(&intermediate_nodes, nodes[0].node_id, context, &*nodes[0].entropy_source, &secp_ctx).unwrap(); nodes[0].messenger.send_onion_message_using_path(path, test_msg.clone(), Some(reply_path)).unwrap(); nodes[3].custom_message_handler.expect_message(TestCustomMessage::Ping); pass_along_path(&nodes); @@ -618,14 +618,14 @@ fn reply_path() { ForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, ]; let context = MessageContext::Custom(Vec::new()); - let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[3].node_id, context, &*nodes[3].entropy_source, &secp_ctx).unwrap(); + let blinded_path = BlindedMessagePath::new(&intermediate_nodes, nodes[3].node_id, context, &*nodes[3].entropy_source, &secp_ctx).unwrap(); let destination = Destination::BlindedPath(blinded_path); let intermediate_nodes = [ ForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, ]; let context = MessageContext::Custom(Vec::new()); - let reply_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[0].node_id, context, &*nodes[0].entropy_source, &secp_ctx).unwrap(); + let reply_path = BlindedMessagePath::new(&intermediate_nodes, nodes[0].node_id, context, &*nodes[0].entropy_source, &secp_ctx).unwrap(); nodes[0].messenger.send_onion_message(test_msg, destination, Some(reply_path)).unwrap(); nodes[3].custom_message_handler.expect_message(TestCustomMessage::Ping); @@ -707,7 +707,7 @@ fn requests_peer_connection_for_buffered_messages() { let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; let context = MessageContext::Custom(Vec::new()); - let blinded_path = BlindedPath::new_for_message( + let blinded_path = BlindedMessagePath::new( &intermediate_nodes, nodes[2].node_id, context, &*nodes[0].entropy_source, &secp_ctx ).unwrap(); let destination = Destination::BlindedPath(blinded_path); @@ -746,7 +746,7 @@ fn drops_buffered_messages_waiting_for_peer_connection() { let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; let context = MessageContext::Custom(Vec::new()); - let blinded_path = BlindedPath::new_for_message( + let blinded_path = BlindedMessagePath::new( &intermediate_nodes, nodes[2].node_id, context, &*nodes[0].entropy_source, &secp_ctx ).unwrap(); let destination = Destination::BlindedPath(blinded_path); @@ -797,7 +797,7 @@ fn intercept_offline_peer_oms() { let secp_ctx = Secp256k1::new(); let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; let context = MessageContext::Custom(Vec::new()); - let blinded_path = BlindedPath::new_for_message( + let blinded_path = BlindedMessagePath::new( &intermediate_nodes, nodes[2].node_id, context, &*nodes[2].entropy_source, &secp_ctx ).unwrap(); let destination = Destination::BlindedPath(blinded_path); diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 24615e537c7..a5c81bb364e 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -15,8 +15,8 @@ use bitcoin::hashes::hmac::{Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey}; -use crate::blinded_path::{BlindedPath, IntroductionNode, NextMessageHop, NodeIdLookUp}; -use crate::blinded_path::message::{advance_path_by_one, ForwardNode, ForwardTlvs, MessageContext, ReceiveTlvs}; +use crate::blinded_path::{IntroductionNode, NodeIdLookUp}; +use crate::blinded_path::message::{BlindedMessagePath, ForwardNode, ForwardTlvs, MessageContext, NextMessageHop, ReceiveTlvs}; use crate::blinded_path::utils; use crate::events::{Event, EventHandler, EventsProvider, ReplayEvent}; use crate::sign::{EntropySource, NodeSigner, Recipient}; @@ -147,8 +147,8 @@ for OnionMessenger where /// # use bitcoin::hashes::_export::_core::time::Duration; /// # use bitcoin::hex::FromHex; /// # use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey, self}; -/// # use lightning::blinded_path::{BlindedPath, EmptyNodeIdLookUp}; -/// # use lightning::blinded_path::message::{ForwardNode, MessageContext}; +/// # use lightning::blinded_path::EmptyNodeIdLookUp; +/// # use lightning::blinded_path::message::{BlindedMessagePath, ForwardNode, MessageContext}; /// # use lightning::sign::{EntropySource, KeysManager}; /// # use lightning::ln::peer_handler::IgnoringMessageHandler; /// # use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath, OnionMessenger}; @@ -176,7 +176,7 @@ for OnionMessenger where /// # } /// # fn create_blinded_paths( /// # &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, _secp_ctx: &Secp256k1 -/// # ) -> Result, ()> { +/// # ) -> Result, ()> { /// # unreachable!() /// # } /// # } @@ -229,7 +229,7 @@ for OnionMessenger where /// ForwardNode { node_id: hop_node_id4, short_channel_id: None }, /// ]; /// let context = MessageContext::Custom(Vec::new()); -/// let blinded_path = BlindedPath::new_for_message(&hops, your_node_id, context, &keys_manager, &secp_ctx).unwrap(); +/// let blinded_path = BlindedMessagePath::new(&hops, your_node_id, context, &keys_manager, &secp_ctx).unwrap(); /// /// // Send a custom onion message to a blinded path. /// let destination = Destination::BlindedPath(blinded_path); @@ -347,7 +347,7 @@ impl OnionMessageRecipient { #[derive(Clone, Debug, Eq, PartialEq)] pub struct Responder { /// The path along which a response can be sent. - reply_path: BlindedPath, + reply_path: BlindedMessagePath, } impl_writeable_tlv_based!(Responder, { @@ -356,7 +356,7 @@ impl_writeable_tlv_based!(Responder, { impl Responder { /// Creates a new [`Responder`] instance with the provided reply path. - pub(super) fn new(reply_path: BlindedPath) -> Self { + pub(super) fn new(reply_path: BlindedMessagePath) -> Self { Responder { reply_path, } @@ -386,7 +386,7 @@ impl Responder { /// This struct contains the information needed to reply to a received message. pub struct OnionMessageResponse { message: T, - reply_path: BlindedPath, + reply_path: BlindedMessagePath, } /// `ResponseInstruction` represents instructions for responding to received messages. @@ -414,7 +414,7 @@ pub struct PendingOnionMessage { pub destination: Destination, /// A reply path to include in the [`OnionMessage`] for a response. - pub reply_path: Option, + pub reply_path: Option, } #[cfg(c_bindings)] @@ -422,10 +422,10 @@ pub struct PendingOnionMessage { /// /// These are obtained when released from [`OnionMessenger`]'s handlers after which they are /// enqueued for sending. -pub type PendingOnionMessage = (T, Destination, Option); +pub type PendingOnionMessage = (T, Destination, Option); pub(crate) fn new_pending_onion_message( - contents: T, destination: Destination, reply_path: Option + contents: T, destination: Destination, reply_path: Option ) -> PendingOnionMessage { #[cfg(not(c_bindings))] return PendingOnionMessage { contents, destination, reply_path }; @@ -440,16 +440,16 @@ pub trait MessageRouter { &self, sender: PublicKey, peers: Vec, destination: Destination ) -> Result; - /// Creates [`BlindedPath`]s to the `recipient` node. The nodes in `peers` are assumed to be - /// direct peers with the `recipient`. + /// Creates [`BlindedMessagePath`]s to the `recipient` node. The nodes in `peers` are assumed to + /// be direct peers with the `recipient`. fn create_blinded_paths< T: secp256k1::Signing + secp256k1::Verification >( &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, - ) -> Result, ()>; + ) -> Result, ()>; - /// Creates compact [`BlindedPath`]s to the `recipient` node. The nodes in `peers` are assumed - /// to be direct peers with the `recipient`. + /// Creates compact [`BlindedMessagePath`]s to the `recipient` node. The nodes in `peers` are + /// assumed to be direct peers with the `recipient`. /// /// Compact blinded paths use short channel ids instead of pubkeys for a smaller serialization, /// which is beneficial when a QR code is used to transport the data. The SCID is passed using a @@ -457,7 +457,7 @@ pub trait MessageRouter { /// /// Implementations using additional intermediate nodes are responsible for using a /// [`ForwardNode`] with `Some` short channel id, if possible. Similarly, implementations should - /// call [`BlindedPath::use_compact_introduction_node`]. + /// call [`BlindedMessagePath::use_compact_introduction_node`]. /// /// The provided implementation simply delegates to [`MessageRouter::create_blinded_paths`], /// ignoring the short channel ids. @@ -466,7 +466,7 @@ pub trait MessageRouter { >( &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { let peers = peers .into_iter() .map(|ForwardNode { node_id, short_channel_id: _ }| node_id) @@ -479,10 +479,10 @@ pub trait MessageRouter { /// /// # Privacy /// -/// Creating [`BlindedPath`]s may affect privacy since, if a suitable path cannot be found, it will -/// create a one-hop path using the recipient as the introduction node if it is a announced node. -/// Otherwise, there is no way to find a path to the introduction node in order to send a message, -/// and thus an `Err` is returned. +/// Creating [`BlindedMessagePath`]s may affect privacy since, if a suitable path cannot be found, +/// it will create a one-hop path using the recipient as the introduction node if it is a announced +/// node. Otherwise, there is no way to find a path to the introduction node in order to send a +/// message, and thus an `Err` is returned. pub struct DefaultMessageRouter>, L: Deref, ES: Deref> where L::Target: Logger, @@ -508,7 +508,7 @@ where >( network_graph: &G, recipient: PublicKey, context: MessageContext, peers: I, entropy_source: &ES, secp_ctx: &Secp256k1, compact_paths: bool, - ) -> Result, ()> { + ) -> Result, ()> { // Limit the number of blinded paths that are computed. const MAX_PATHS: usize = 3; @@ -546,7 +546,7 @@ where let paths = peer_info.into_iter() .map(|(peer, _, _)| { - BlindedPath::new_for_message(&[peer], recipient, context.clone(), &**entropy_source, secp_ctx) + BlindedMessagePath::new(&[peer], recipient, context.clone(), &**entropy_source, secp_ctx) }) .take(MAX_PATHS) .collect::, _>>(); @@ -555,7 +555,7 @@ where Ok(paths) if !paths.is_empty() => Ok(paths), _ => { if is_recipient_announced { - BlindedPath::one_hop_for_message(recipient, context, &**entropy_source, secp_ctx) + BlindedMessagePath::new(&[], recipient, context, &**entropy_source, secp_ctx) .map(|path| vec![path]) } else { Err(()) @@ -610,7 +610,7 @@ where >( network_graph: &G, recipient: PublicKey, context: MessageContext, peers: Vec, entropy_source: &ES, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { let peers = peers .into_iter() .map(|node_id| ForwardNode { node_id, short_channel_id: None }); @@ -622,7 +622,7 @@ where >( network_graph: &G, recipient: PublicKey, context: MessageContext, peers: Vec, entropy_source: &ES, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { Self::create_blinded_paths_from_iter(network_graph, recipient, context, peers.into_iter(), entropy_source, secp_ctx, true) } } @@ -642,7 +642,7 @@ where T: secp256k1::Signing + secp256k1::Verification >( &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { Self::create_blinded_paths(&self.network_graph, recipient, context, peers, &self.entropy_source, secp_ctx) } @@ -650,7 +650,7 @@ where T: secp256k1::Signing + secp256k1::Verification >( &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { Self::create_compact_blinded_paths(&self.network_graph, recipient, context, peers, &self.entropy_source, secp_ctx) } @@ -688,7 +688,7 @@ pub enum Destination { /// We're sending this onion message to a node. Node(PublicKey), /// We're sending this onion message to a blinded path. - BlindedPath(BlindedPath), + BlindedPath(BlindedMessagePath), } impl Destination { @@ -697,12 +697,12 @@ impl Destination { /// provided [`ReadOnlyNetworkGraph`]. pub fn resolve(&mut self, network_graph: &ReadOnlyNetworkGraph) { if let Destination::BlindedPath(path) = self { - if let IntroductionNode::DirectedShortChannelId(..) = path.introduction_node { + if let IntroductionNode::DirectedShortChannelId(..) = path.introduction_node() { if let Some(pubkey) = path .public_introduction_node_id(network_graph) .and_then(|node_id| node_id.as_pubkey().ok()) { - path.introduction_node = IntroductionNode::NodeId(pubkey); + *path.introduction_node_mut() = IntroductionNode::NodeId(pubkey); } } } @@ -711,15 +711,15 @@ impl Destination { pub(super) fn num_hops(&self) -> usize { match self { Destination::Node(_) => 1, - Destination::BlindedPath(BlindedPath { blinded_hops, .. }) => blinded_hops.len(), + Destination::BlindedPath(path) => path.blinded_hops().len(), } } fn first_node(&self) -> Option { match self { Destination::Node(node_id) => Some(*node_id), - Destination::BlindedPath(BlindedPath { introduction_node, .. }) => { - match introduction_node { + Destination::BlindedPath(path) => { + match path.introduction_node() { IntroductionNode::NodeId(pubkey) => Some(*pubkey), IntroductionNode::DirectedShortChannelId(..) => None, } @@ -751,8 +751,8 @@ pub enum SendError { /// Because implementations such as Eclair will drop onion messages where the message packet /// exceeds 32834 bytes, we refuse to send messages where the packet exceeds this size. TooBigPacket, - /// The provided [`Destination`] was an invalid [`BlindedPath`] due to not having any blinded - /// hops. + /// The provided [`Destination`] was an invalid [`BlindedMessagePath`] due to not having any + /// blinded hops. TooFewBlindedHops, /// The first hop is not a peer and doesn't have a known [`SocketAddress`]. InvalidFirstHop(PublicKey), @@ -817,7 +817,7 @@ pub trait CustomOnionMessageHandler { /// Typically, this is used for messages initiating a message flow rather than in response to /// another message. The latter should use the return value of [`Self::handle_custom_message`]. #[cfg(c_bindings)] - fn release_pending_custom_messages(&self) -> Vec<(Self::CustomMessage, Destination, Option)>; + fn release_pending_custom_messages(&self) -> Vec<(Self::CustomMessage, Destination, Option)>; } /// A processed incoming onion message, containing either a Forward (another onion message) @@ -827,7 +827,7 @@ pub enum PeeledOnion { /// Forwarded onion, with the next node id and a new onion Forward(NextMessageHop, OnionMessage), /// Received onion message, with decrypted contents, context, and reply path - Receive(ParsedOnionMessageContents, Option, Option) + Receive(ParsedOnionMessageContents, Option, Option) } @@ -842,7 +842,7 @@ pub fn create_onion_message_resolving_destination< >( entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL, network_graph: &ReadOnlyNetworkGraph, secp_ctx: &Secp256k1, - mut path: OnionMessagePath, contents: T, reply_path: Option, + mut path: OnionMessagePath, contents: T, reply_path: Option, ) -> Result<(PublicKey, OnionMessage, Option>), SendError> where ES::Target: EntropySource, @@ -869,7 +869,7 @@ where pub fn create_onion_message( entropy_source: &ES, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1, path: OnionMessagePath, contents: T, - reply_path: Option, + reply_path: Option, ) -> Result<(PublicKey, OnionMessage, Option>), SendError> where ES::Target: EntropySource, @@ -877,8 +877,8 @@ where NL::Target: NodeIdLookUp, { let OnionMessagePath { intermediate_nodes, mut destination, first_node_addresses } = path; - if let Destination::BlindedPath(BlindedPath { ref blinded_hops, .. }) = destination { - if blinded_hops.is_empty() { + if let Destination::BlindedPath(ref path) = destination { + if path.blinded_hops().is_empty() { return Err(SendError::TooFewBlindedHops); } } @@ -891,17 +891,17 @@ where if let Destination::BlindedPath(ref mut blinded_path) = destination { let our_node_id = node_signer.get_node_id(Recipient::Node) .map_err(|()| SendError::GetNodeIdFailed)?; - let introduction_node_id = match blinded_path.introduction_node { - IntroductionNode::NodeId(pubkey) => pubkey, + let introduction_node_id = match blinded_path.introduction_node() { + IntroductionNode::NodeId(pubkey) => *pubkey, IntroductionNode::DirectedShortChannelId(direction, scid) => { - match node_id_lookup.next_node_id(scid) { + match node_id_lookup.next_node_id(*scid) { Some(next_node_id) => *direction.select_pubkey(&our_node_id, &next_node_id), None => return Err(SendError::UnresolvedIntroductionNode), } }, }; if introduction_node_id == our_node_id { - advance_path_by_one(blinded_path, node_signer, node_id_lookup, &secp_ctx) + blinded_path.advance_path_by_one(node_signer, node_id_lookup, &secp_ctx) .map_err(|()| SendError::BlindedPathAdvanceFailed)?; } } @@ -914,9 +914,9 @@ where } else { match &destination { Destination::Node(pk) => (*pk, PublicKey::from_secret_key(&secp_ctx, &blinding_secret)), - Destination::BlindedPath(BlindedPath { introduction_node, blinding_point, .. }) => { - match introduction_node { - IntroductionNode::NodeId(pubkey) => (*pubkey, *blinding_point), + Destination::BlindedPath(path) => { + match path.introduction_node() { + IntroductionNode::NodeId(pubkey) => (*pubkey, path.blinding_point()), IntroductionNode::DirectedShortChannelId(..) => { return Err(SendError::UnresolvedIntroductionNode); }, @@ -1160,7 +1160,7 @@ where /// /// See [`OnionMessenger`] for example usage. pub fn send_onion_message( - &self, contents: T, destination: Destination, reply_path: Option + &self, contents: T, destination: Destination, reply_path: Option ) -> Result { self.find_path_and_enqueue_onion_message( contents, destination, reply_path, format_args!("") @@ -1168,7 +1168,7 @@ where } fn find_path_and_enqueue_onion_message( - &self, contents: T, destination: Destination, reply_path: Option, + &self, contents: T, destination: Destination, reply_path: Option, log_suffix: fmt::Arguments ) -> Result { let mut logger = WithContext::from(&self.logger, None, None, None); @@ -1219,7 +1219,7 @@ where .map_err(|_| SendError::PathNotFound) } - fn create_blinded_path(&self, context: MessageContext) -> Result { + fn create_blinded_path(&self, context: MessageContext) -> Result { let recipient = self.node_signer .get_node_id(Recipient::Node) .map_err(|_| SendError::GetNodeIdFailed)?; @@ -1238,7 +1238,7 @@ where } fn enqueue_onion_message( - &self, path: OnionMessagePath, contents: T, reply_path: Option, + &self, path: OnionMessagePath, contents: T, reply_path: Option, log_suffix: fmt::Arguments ) -> Result { log_trace!(self.logger, "Constructing onion message {}: {:?}", log_suffix, contents); @@ -1297,7 +1297,7 @@ where #[cfg(any(test, feature = "_test_utils"))] pub fn send_onion_message_using_path( - &self, path: OnionMessagePath, contents: T, reply_path: Option + &self, path: OnionMessagePath, contents: T, reply_path: Option ) -> Result { self.enqueue_onion_message(path, contents, reply_path, format_args!("")) } @@ -1785,7 +1785,7 @@ pub type SimpleRefOnionMessenger< /// `unblinded_path` to the given `destination`. fn packet_payloads_and_keys( secp_ctx: &Secp256k1, unblinded_path: &[PublicKey], destination: Destination, message: T, - mut reply_path: Option, session_priv: &SecretKey + mut reply_path: Option, session_priv: &SecretKey ) -> Result<(Vec<(Payload, [u8; 32])>, Vec), SendError> { let num_hops = unblinded_path.len() + destination.num_hops(); let mut payloads = Vec::with_capacity(num_hops); @@ -1793,14 +1793,14 @@ fn packet_payloads_and_keys (None, 0), - Destination::BlindedPath(BlindedPath { introduction_node, blinding_point, blinded_hops }) => { - let introduction_node_id = match introduction_node { + Destination::BlindedPath(path) => { + let introduction_node_id = match path.introduction_node() { IntroductionNode::NodeId(pubkey) => pubkey, IntroductionNode::DirectedShortChannelId(..) => { return Err(SendError::UnresolvedIntroductionNode); }, }; - (Some((*introduction_node_id, *blinding_point)), blinded_hops.len()) + (Some((*introduction_node_id, path.blinding_point())), path.blinded_hops().len()) }, }; let num_unblinded_hops = num_hops - num_blinded_hops; diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index 1693c5a9911..8cdf098a3e5 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -18,7 +18,7 @@ //! information on its usage. //! //! [offers]: -//! [blinded paths]: crate::blinded_path::BlindedPath +//! [blinded paths]: crate::blinded_path::message::BlindedMessagePath //! [`OnionMessenger`]: self::messenger::OnionMessenger pub mod async_payments; diff --git a/lightning/src/onion_message/offers.rs b/lightning/src/onion_message/offers.rs index 6884ca77e06..86268c6217e 100644 --- a/lightning/src/onion_message/offers.rs +++ b/lightning/src/onion_message/offers.rs @@ -61,7 +61,7 @@ pub trait OffersMessageHandler { /// Typically, this is used for messages initiating a payment flow rather than in response to /// another message. The latter should use the return value of [`Self::handle_message`]. #[cfg(c_bindings)] - fn release_pending_messages(&self) -> Vec<(OffersMessage, crate::onion_message::messenger::Destination, Option)> { vec![] } + fn release_pending_messages(&self) -> Vec<(OffersMessage, crate::onion_message::messenger::Destination, Option)> { vec![] } } /// Possible BOLT 12 Offers messages sent and received via an [`OnionMessage`]. diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index 49b3f6642ab..553d7021674 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -12,8 +12,7 @@ use bitcoin::secp256k1::PublicKey; use bitcoin::secp256k1::ecdh::SharedSecret; -use crate::blinded_path::{BlindedPath, NextMessageHop}; -use crate::blinded_path::message::{ForwardTlvs, ReceiveTlvs}; +use crate::blinded_path::message::{BlindedMessagePath, ForwardTlvs, NextMessageHop, ReceiveTlvs}; use crate::blinded_path::utils::Padding; use crate::ln::msgs::DecodeError; use crate::ln::onion_utils; @@ -118,7 +117,7 @@ pub(super) enum Payload { /// This payload is for the final hop. Receive { control_tlvs: ReceiveControlTlvs, - reply_path: Option, + reply_path: Option, message: T, } } @@ -246,7 +245,7 @@ for Payload::CustomM let v: BigSize = Readable::read(r)?; let mut rd = FixedLengthReader::new(r, v.0); - let mut reply_path: Option = None; + let mut reply_path: Option = None; let mut read_adapter: Option> = None; let rho = onion_utils::gen_rho_from_shared_secret(&encrypted_tlvs_ss.secret_bytes()); let mut message_type: Option = None; diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index bf894f0ebb6..2d7450b91c5 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -11,9 +11,9 @@ use bitcoin::secp256k1::{PublicKey, Secp256k1, self}; -use crate::blinded_path::{BlindedHop, BlindedPath, Direction, IntroductionNode}; -use crate::blinded_path::message::{self, MessageContext}; -use crate::blinded_path::payment::{ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs, self}; +use crate::blinded_path::{BlindedHop, Direction, IntroductionNode}; +use crate::blinded_path::message::{self, BlindedMessagePath, MessageContext}; +use crate::blinded_path::payment::{BlindedPaymentPath, ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs, self}; use crate::ln::{PaymentHash, PaymentPreimage}; use crate::ln::channel_state::ChannelDetails; use crate::ln::channelmanager::{PaymentId, MIN_FINAL_CLTV_EXPIRY_DELTA, RecipientOnionFields}; @@ -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; @@ -158,7 +158,7 @@ impl>, L: Deref, ES: Deref, S: Deref, SP: Size }) }) .map(|forward_node| { - BlindedPath::new_for_payment( + BlindedPaymentPath::new( &[forward_node], recipient, tlvs.clone(), u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, &*self.entropy_source, secp_ctx ) @@ -170,8 +170,9 @@ impl>, L: Deref, ES: Deref, S: Deref, SP: Size Ok(paths) if !paths.is_empty() => Ok(paths), _ => { if network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient)) { - BlindedPath::one_hop_for_payment( - recipient, tlvs, MIN_FINAL_CLTV_EXPIRY_DELTA, &*self.entropy_source, secp_ctx + BlindedPaymentPath::new( + &[], recipient, tlvs, u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, &*self.entropy_source, + secp_ctx ).map(|path| vec![path]) } else { Err(()) @@ -196,7 +197,7 @@ impl< G: Deref>, L: Deref, ES: Deref, S: Deref, SP: Siz T: secp256k1::Signing + secp256k1::Verification > ( &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { DefaultMessageRouter::create_blinded_paths(&self.network_graph, recipient, context, peers, &self.entropy_source, secp_ctx) } @@ -204,7 +205,7 @@ impl< G: Deref>, L: Deref, ES: Deref, S: Deref, SP: Siz T: secp256k1::Signing + secp256k1::Verification > ( &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { DefaultMessageRouter::create_compact_blinded_paths(&self.network_graph, recipient, context, peers, &self.entropy_source, secp_ctx) } } @@ -235,7 +236,7 @@ pub trait Router: MessageRouter { self.find_route(payer, route_params, first_hops, inflight_htlcs) } - /// Creates [`BlindedPath`]s for payment to the `recipient` node. The channels in `first_hops` + /// Creates [`BlindedPaymentPath`]s for payment to the `recipient` node. The channels in `first_hops` /// are assumed to be with the `recipient`'s peers. The payment secret and any constraints are /// given in `tlvs`. fn create_blinded_payment_paths< @@ -243,7 +244,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. @@ -382,17 +383,15 @@ pub struct RouteHop { pub channel_features: ChannelFeatures, /// The fee taken on this hop (for paying for the use of the *next* channel in the path). /// If this is the last hop in [`Path::hops`]: - /// * if we're sending to a [`BlindedPath`], this is the fee paid for use of the entire blinded path + /// * if we're sending to a [`BlindedPaymentPath`], this is the fee paid for use of the entire + /// blinded path /// * otherwise, this is the full value of this [`Path`]'s part of the payment - /// - /// [`BlindedPath`]: crate::blinded_path::BlindedPath pub fee_msat: u64, /// The CLTV delta added for this hop. /// If this is the last hop in [`Path::hops`]: - /// * if we're sending to a [`BlindedPath`], this is the CLTV delta for the entire blinded path + /// * if we're sending to a [`BlindedPaymentPath`], this is the CLTV delta for the entire blinded + /// path /// * otherwise, this is the CLTV delta expected at the destination - /// - /// [`BlindedPath`]: crate::blinded_path::BlindedPath pub cltv_expiry_delta: u32, /// Indicates whether this hop is possibly announced in the public network graph. /// @@ -421,13 +420,9 @@ impl_writeable_tlv_based!(RouteHop, { /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct BlindedTail { - /// The hops of the [`BlindedPath`] provided by the recipient. - /// - /// [`BlindedPath`]: crate::blinded_path::BlindedPath + /// The hops of the [`BlindedPaymentPath`] provided by the recipient. pub hops: Vec, - /// The blinding point of the [`BlindedPath`] provided by the recipient. - /// - /// [`BlindedPath`]: crate::blinded_path::BlindedPath + /// The blinding point of the [`BlindedPaymentPath`] provided by the recipient. pub blinding_point: PublicKey, /// Excess CLTV delta added to the recipient's CLTV expiry to deter intermediate nodes from /// inferring the destination. May be 0. @@ -876,7 +871,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, BlindedPath)>) -> Self { + pub fn blinded(blinded_route_hints: Vec<(BlindedPayInfo, BlindedPaymentPath)>) -> Self { Self { payee: Payee::Blinded { route_hints: blinded_route_hints, features: None }, expiry_time: None, @@ -965,8 +960,8 @@ 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() { - if failed_blinded_tail.hops == path.blinded_hops && - failed_blinded_tail.blinding_point == path.blinding_point + if &failed_blinded_tail.hops == path.blinded_hops() && + failed_blinded_tail.blinding_point == path.blinding_point() { self.previously_failed_blinded_path_idxs.push(idx as u64); found_blinded_tail = true; @@ -985,7 +980,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, BlindedPath)>, + route_hints: Vec<(BlindedPayInfo, BlindedPaymentPath)>, /// Features supported by the payee. /// /// May be set from the payee's invoice. May be `None` if the invoice does not contain any @@ -1041,14 +1036,14 @@ impl Payee { _ => None, } } - pub(crate) fn blinded_route_hints(&self) -> &[(BlindedPayInfo, BlindedPath)] { + pub(crate) fn blinded_route_hints(&self) -> &[(BlindedPayInfo, BlindedPaymentPath)] { match self { Self::Blinded { route_hints, .. } => &route_hints[..], Self::Clear { .. } => &[] } } - pub(crate) fn blinded_route_hints_mut(&mut self) -> &mut [(BlindedPayInfo, BlindedPath)] { + pub(crate) fn blinded_route_hints_mut(&mut self) -> &mut [(BlindedPayInfo, BlindedPaymentPath)] { match self { Self::Blinded { route_hints, .. } => &mut route_hints[..], Self::Clear { .. } => &mut [] @@ -1250,7 +1245,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, BlindedPath), + pub hint: &'a (BlindedPayInfo, 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 @@ -1279,7 +1274,7 @@ 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, BlindedPath), + pub hint: &'a (BlindedPayInfo, 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 @@ -1487,7 +1482,7 @@ impl<'a> CandidateRouteHop<'a> { _ => CandidateHopId::Clear((self.short_channel_id().unwrap(), self.source() < self.target().unwrap())), } } - fn blinded_path(&self) -> Option<&'a BlindedPath> { + fn blinded_path(&self) -> Option<&'a BlindedPaymentPath> { match self { CandidateRouteHop::Blinded(BlindedPathCandidate { hint, .. }) | CandidateRouteHop::OneHopBlinded(OneHopBlindedPathCandidate { hint, .. }) => { Some(&hint.1) @@ -1644,7 +1639,7 @@ fn calculate_blinded_path_intro_points<'a, L: Deref>( where L::Target: Logger { let introduction_node_id_cache = payment_params.payee.blinded_route_hints().iter() .map(|(_, path)| { - match &path.introduction_node { + match path.introduction_node() { IntroductionNode::NodeId(pubkey) => { // Note that this will only return `Some` if the `pubkey` is somehow known to // us (i.e. a channel counterparty or in the network graph). @@ -1683,7 +1678,7 @@ where L::Target: Logger { 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()) { - if blinded_path.blinded_hops.len() == 0 { + if blinded_path.blinded_hops().len() == 0 { return Err(LightningError{err: "0-hop blinded path provided".to_owned(), action: ErrorAction::IgnoreError}); } let introduction_node_id = match info_opt { @@ -1692,10 +1687,10 @@ where L::Target: Logger { }; if *introduction_node_id == our_node_id { log_info!(logger, "Got blinded path with ourselves as the introduction node, ignoring"); - } else if blinded_path.blinded_hops.len() == 1 && + } 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}); @@ -1978,7 +1973,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.1.introduction_node() { IntroductionNode::NodeId(pubkey) => write!(f, "id {}", pubkey)?, IntroductionNode::DirectedShortChannelId(direction, scid) => { match direction { @@ -1992,7 +1987,7 @@ impl<'a> fmt::Display for LoggedCandidateHop<'a> { } } " and blinding point ".fmt(f)?; - hint.1.blinding_point.fmt(f) + hint.1.blinding_point().fmt(f) }, CandidateRouteHop::FirstHop(_) => { "first hop with SCID ".fmt(f)?; @@ -2825,7 +2820,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.1.blinded_hops().len() == 1 { CandidateRouteHop::OneHopBlinded( OneHopBlindedPathCandidate { source_node_counter, source_node_id, hint, hint_idx } ) @@ -3348,8 +3343,8 @@ where L::Target: Logger { if let Some(blinded_path) = h.candidate.blinded_path() { final_cltv_delta = h.candidate.cltv_expiry_delta(); Some(BlindedTail { - hops: blinded_path.blinded_hops.clone(), - blinding_point: blinded_path.blinding_point, + hops: blinded_path.blinded_hops().to_vec(), + blinding_point: blinded_path.blinding_point(), excess_final_cltv_expiry_delta: 0, final_value_msat: h.fee_msat, }) @@ -3546,7 +3541,8 @@ fn build_route_from_hops_internal( #[cfg(test)] mod tests { - use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; + use crate::blinded_path::BlindedHop; + use crate::blinded_path::payment::BlindedPaymentPath; use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, EffectiveCapacity}; use crate::routing::utxo::UtxoResult; use crate::routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features, @@ -3623,6 +3619,25 @@ mod tests { } } + fn dummy_blinded_path(intro_node: PublicKey) -> 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() } + ] + ) + } + + fn dummy_one_hop_blinded_path(intro_node: PublicKey) -> 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() }, + ] + ) + } + #[test] fn simple_route_test() { let (secp_ctx, network_graph, _, _, logger) = build_graph(); @@ -5453,11 +5468,7 @@ mod tests { // MPP to a 1-hop blinded path for nodes[2] let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(nodes[2]), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: vec![BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }], - }; + 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, @@ -5471,19 +5482,15 @@ mod tests { do_simple_mpp_route_test(one_hop_blinded_payment_params.clone()); // MPP to 3 2-hop blinded paths - let mut blinded_path_node_0 = blinded_path.clone(); - blinded_path_node_0.introduction_node = IntroductionNode::NodeId(nodes[0]); - blinded_path_node_0.blinded_hops.push(blinded_path.blinded_hops[0].clone()); + 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 mut blinded_path_node_7 = blinded_path_node_0.clone(); - blinded_path_node_7.introduction_node = IntroductionNode::NodeId(nodes[7]); + 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 mut blinded_path_node_1 = blinded_path_node_0.clone(); - blinded_path_node_1.introduction_node = IntroductionNode::NodeId(nodes[1]); + let blinded_path_node_1 = dummy_blinded_path(nodes[1]); let mut node_1_payinfo = blinded_payinfo.clone(); node_1_payinfo.htlc_maximum_msat = 180_000; @@ -7648,14 +7655,7 @@ mod tests { assert_eq!(route.get_total_amount(), amt_msat); // Make sure this works for blinded route hints. - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(intermed_node_id), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: vec![ - BlindedHop { blinded_node_id: ln_test_utils::pubkey(42), encrypted_payload: vec![] }, - BlindedHop { blinded_node_id: ln_test_utils::pubkey(43), encrypted_payload: vec![] }, - ], - }; + let blinded_path = dummy_blinded_path(intermed_node_id); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 100, fee_proportional_millionths: 0, @@ -7682,22 +7682,6 @@ mod tests { #[test] fn blinded_route_ser() { - let blinded_path_1 = BlindedPath { - introduction_node: IntroductionNode::NodeId(ln_test_utils::pubkey(42)), - blinding_point: ln_test_utils::pubkey(43), - blinded_hops: vec![ - BlindedHop { blinded_node_id: ln_test_utils::pubkey(44), encrypted_payload: Vec::new() }, - BlindedHop { blinded_node_id: ln_test_utils::pubkey(45), encrypted_payload: Vec::new() } - ], - }; - let blinded_path_2 = BlindedPath { - introduction_node: IntroductionNode::NodeId(ln_test_utils::pubkey(46)), - blinding_point: ln_test_utils::pubkey(47), - blinded_hops: vec![ - BlindedHop { blinded_node_id: ln_test_utils::pubkey(48), encrypted_payload: Vec::new() }, - BlindedHop { blinded_node_id: ln_test_utils::pubkey(49), encrypted_payload: Vec::new() } - ], - }; // (De)serialize a Route with 1 blinded path out of two total paths. let mut route = Route { paths: vec![Path { hops: vec![RouteHop { @@ -7710,8 +7694,11 @@ mod tests { maybe_announced_channel: true, }], blinded_tail: Some(BlindedTail { - hops: blinded_path_1.blinded_hops, - blinding_point: blinded_path_1.blinding_point, + hops: vec![ + BlindedHop { blinded_node_id: ln_test_utils::pubkey(44), encrypted_payload: Vec::new() }, + BlindedHop { blinded_node_id: ln_test_utils::pubkey(45), encrypted_payload: Vec::new() } + ], + blinding_point: ln_test_utils::pubkey(43), excess_final_cltv_expiry_delta: 40, final_value_msat: 100, })}, Path { @@ -7733,8 +7720,11 @@ mod tests { // (De)serialize a Route with two paths, each containing a blinded tail. route.paths[1].blinded_tail = Some(BlindedTail { - hops: blinded_path_2.blinded_hops, - blinding_point: blinded_path_2.blinding_point, + hops: vec![ + BlindedHop { blinded_node_id: ln_test_utils::pubkey(48), encrypted_payload: Vec::new() }, + BlindedHop { blinded_node_id: ln_test_utils::pubkey(49), encrypted_payload: Vec::new() } + ], + blinding_point: ln_test_utils::pubkey(47), excess_final_cltv_expiry_delta: 41, final_value_msat: 101, }); @@ -7749,11 +7739,6 @@ mod tests { // Ensure we'll score the channel that's inbound to a blinded path's introduction node, and // account for the blinded tail's final amount_msat. let mut inflight_htlcs = InFlightHtlcs::new(); - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(ln_test_utils::pubkey(43)), - blinding_point: ln_test_utils::pubkey(48), - blinded_hops: vec![BlindedHop { blinded_node_id: ln_test_utils::pubkey(49), encrypted_payload: Vec::new() }], - }; let path = Path { hops: vec![RouteHop { pubkey: ln_test_utils::pubkey(42), @@ -7774,8 +7759,8 @@ mod tests { maybe_announced_channel: false, }], blinded_tail: Some(BlindedTail { - hops: blinded_path.blinded_hops, - blinding_point: blinded_path.blinding_point, + hops: vec![BlindedHop { blinded_node_id: ln_test_utils::pubkey(49), encrypted_payload: Vec::new() }], + blinding_point: ln_test_utils::pubkey(48), excess_final_cltv_expiry_delta: 0, final_value_msat: 200, }), @@ -7788,14 +7773,6 @@ mod tests { #[test] fn blinded_path_cltv_shadow_offset() { // Make sure we add a shadow offset when sending to blinded paths. - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(ln_test_utils::pubkey(43)), - blinding_point: ln_test_utils::pubkey(44), - blinded_hops: vec![ - BlindedHop { blinded_node_id: ln_test_utils::pubkey(45), encrypted_payload: Vec::new() }, - BlindedHop { blinded_node_id: ln_test_utils::pubkey(46), encrypted_payload: Vec::new() } - ], - }; let mut route = Route { paths: vec![Path { hops: vec![RouteHop { pubkey: ln_test_utils::pubkey(42), @@ -7817,8 +7794,11 @@ mod tests { } ], blinded_tail: Some(BlindedTail { - hops: blinded_path.blinded_hops, - blinding_point: blinded_path.blinding_point, + hops: vec![ + BlindedHop { blinded_node_id: ln_test_utils::pubkey(45), encrypted_payload: Vec::new() }, + BlindedHop { blinded_node_id: ln_test_utils::pubkey(46), encrypted_payload: Vec::new() } + ], + blinding_point: ln_test_utils::pubkey(44), excess_final_cltv_expiry_delta: 0, final_value_msat: 200, }), @@ -7847,16 +7827,13 @@ mod tests { let scorer = ln_test_utils::TestScorer::new(); let random_seed_bytes = [42; 32]; - let mut blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(nodes[2]), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: Vec::with_capacity(num_blinded_hops), - }; + let mut blinded_hops = Vec::new(); for i in 0..num_blinded_hops { - blinded_path.blinded_hops.push( + blinded_hops.push( 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, @@ -7875,7 +7852,7 @@ mod tests { assert_eq!(route.paths[0].hops.len(), 2); let tail = route.paths[0].blinded_tail.as_ref().unwrap(); - assert_eq!(tail.hops, blinded_path.blinded_hops); + assert_eq!(&tail.hops, blinded_path.blinded_hops()); assert_eq!(tail.excess_final_cltv_expiry_delta, 0); assert_eq!(tail.final_value_msat, 1001); @@ -7904,13 +7881,6 @@ mod tests { let scorer = ln_test_utils::TestScorer::new(); let random_seed_bytes = [42; 32]; - let mut invalid_blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(nodes[2]), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: vec![ - BlindedHop { blinded_node_id: ln_test_utils::pubkey(43), encrypted_payload: vec![0; 43] }, - ], - }; let blinded_payinfo = BlindedPayInfo { fee_base_msat: 100, fee_proportional_millionths: 500, @@ -7920,11 +7890,11 @@ mod tests { features: BlindedHopFeatures::empty(), }; - let mut invalid_blinded_path_2 = invalid_blinded_path.clone(); - invalid_blinded_path_2.introduction_node = IntroductionNode::NodeId(nodes[3]); + 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 payment_params = PaymentParameters::blinded(vec![ - (blinded_payinfo.clone(), invalid_blinded_path.clone()), - (blinded_payinfo.clone(), invalid_blinded_path_2)]); + (blinded_payinfo.clone(), invalid_blinded_path_2), + (blinded_payinfo.clone(), 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) @@ -7935,8 +7905,8 @@ mod tests { _ => panic!("Expected error") } - invalid_blinded_path.introduction_node = IntroductionNode::NodeId(our_id); - let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo.clone(), invalid_blinded_path.clone())]); + let invalid_blinded_path = dummy_blinded_path(our_id); + let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo.clone(), 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) @@ -7947,8 +7917,8 @@ mod tests { _ => panic!("Expected error") } - invalid_blinded_path.introduction_node = IntroductionNode::NodeId(ln_test_utils::pubkey(46)); - invalid_blinded_path.blinded_hops.clear(); + let mut invalid_blinded_path = dummy_one_hop_blinded_path(ln_test_utils::pubkey(46)); + invalid_blinded_path.clear_blinded_hops(); let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo, 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, @@ -7974,14 +7944,7 @@ mod tests { let config = UserConfig::default(); let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); - let blinded_path_1 = BlindedPath { - introduction_node: IntroductionNode::NodeId(nodes[2]), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: 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() } - ], - }; + let blinded_path_1 = dummy_blinded_path(nodes[2]); let blinded_payinfo_1 = BlindedPayInfo { fee_base_msat: 0, fee_proportional_millionths: 0, @@ -7991,8 +7954,12 @@ mod tests { features: BlindedHopFeatures::empty(), }; - let mut blinded_path_2 = blinded_path_1.clone(); - blinded_path_2.blinding_point = ln_test_utils::pubkey(43); + 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() } + ] + ); let mut blinded_payinfo_2 = blinded_payinfo_1.clone(); blinded_payinfo_2.htlc_maximum_msat = 70_000; @@ -8014,7 +7981,7 @@ mod tests { 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()); + .map(|(_, bp)| bp.blinding_point()).unwrap()); } else { panic!(); } total_amount_paid_msat += path.final_value_msat(); } @@ -8072,14 +8039,7 @@ 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 = BlindedPath { - introduction_node: IntroductionNode::NodeId(nodes[1]), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: 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() } - ], - }; + let blinded_path = dummy_blinded_path(nodes[1]); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 1000, fee_proportional_millionths: 0, @@ -8140,14 +8100,7 @@ mod tests { get_channel_details(Some(1), nodes[1], channelmanager::provided_init_features(&config), 18446744073709551615)]; - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(nodes[1]), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: 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() } - ], - }; + let blinded_path = dummy_blinded_path(nodes[1]); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 5046_2720, fee_proportional_millionths: 0, @@ -8195,14 +8148,7 @@ mod tests { // Values are taken from the fuzz input that uncovered this panic. let amt_msat = 21_7020_5185_1423_0019; - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(our_id), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: 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() } - ], - }; + let blinded_path = dummy_blinded_path(our_id); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 5052_9027, fee_proportional_millionths: 0, @@ -8215,7 +8161,7 @@ mod tests { (blinded_payinfo.clone(), blinded_path.clone()), (blinded_payinfo.clone(), blinded_path.clone()), ]; - blinded_hints[1].1.introduction_node = IntroductionNode::NodeId(nodes[6]); + blinded_hints[1].1 = dummy_blinded_path(nodes[6]); let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); let payment_params = PaymentParameters::blinded(blinded_hints.clone()) @@ -8246,14 +8192,7 @@ mod tests { // Values are taken from the fuzz input that uncovered this panic. let amt_msat = 21_7020_5185_1423_0019; - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(our_id), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: 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() } - ], - }; + let blinded_path = dummy_blinded_path(our_id); let blinded_payinfo = BlindedPayInfo { fee_base_msat: 10_4425_1395, fee_proportional_millionths: 0, @@ -8271,7 +8210,7 @@ mod tests { 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[2].1.introduction_node = IntroductionNode::NodeId(nodes[6]); + blinded_hints[2].1 = dummy_blinded_path(nodes[6]); let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); let payment_params = PaymentParameters::blinded(blinded_hints.clone()) @@ -8316,14 +8255,7 @@ mod tests { let base_fee = 1_6778_3453; let htlc_min = 2_5165_8240; let payment_params = if blinded_payee { - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(nodes[0]), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: 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() } - ], - }; + let blinded_path = dummy_blinded_path(nodes[0]); let blinded_payinfo = BlindedPayInfo { fee_base_msat: base_fee, fee_proportional_millionths: 0, @@ -8395,14 +8327,7 @@ 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 = BlindedPath { - introduction_node: IntroductionNode::NodeId(nodes[0]), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: 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() } - ], - }; + 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 { @@ -8496,14 +8421,7 @@ mod tests { htlc_maximum_msat: htlc_min * 100, cltv_expiry_delta: 10, features: BlindedHopFeatures::empty(), - }, BlindedPath { - introduction_node: IntroductionNode::NodeId(nodes[0]), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: 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() } - ], - }) + }, dummy_blinded_path(nodes[0])) ]; let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config); let payment_params = PaymentParameters::blinded(blinded_hints.clone()) @@ -8545,14 +8463,7 @@ mod tests { let htlc_mins = [49_0000, 1125_0000]; let payment_params = { - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(nodes[0]), - blinding_point: ln_test_utils::pubkey(42), - blinded_hops: 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() } - ], - }; + 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 { diff --git a/lightning/src/routing/scoring.rs b/lightning/src/routing/scoring.rs index a04a1850489..7945a5b80b3 100644 --- a/lightning/src/routing/scoring.rs +++ b/lightning/src/routing/scoring.rs @@ -2152,7 +2152,7 @@ impl Readable for ChannelLiquidity { #[cfg(test)] mod tests { use super::{ChannelLiquidity, HistoricalBucketRangeTracker, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters, ProbabilisticScorer}; - use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; + use crate::blinded_path::BlindedHop; use crate::util::config::UserConfig; use crate::ln::channelmanager; @@ -3567,16 +3567,9 @@ mod tests { let mut path = payment_path_for_amount(768); let recipient_hop = path.hops.pop().unwrap(); - let blinded_path = BlindedPath { - introduction_node: IntroductionNode::NodeId(path.hops.last().as_ref().unwrap().pubkey), - blinding_point: test_utils::pubkey(42), - blinded_hops: vec![ - BlindedHop { blinded_node_id: test_utils::pubkey(44), encrypted_payload: Vec::new() } - ], - }; path.blinded_tail = Some(BlindedTail { - hops: blinded_path.blinded_hops, - blinding_point: blinded_path.blinding_point, + hops: vec![BlindedHop { blinded_node_id: test_utils::pubkey(44), encrypted_payload: Vec::new() }], + blinding_point: test_utils::pubkey(42), excess_final_cltv_expiry_delta: recipient_hop.cltv_expiry_delta, final_value_msat: recipient_hop.fee_msat, }); diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index f5256064edf..ef8a7c70f4b 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -8,9 +8,8 @@ // licenses. use crate::blinded_path::message::MessageContext; -use crate::blinded_path::BlindedPath; -use crate::blinded_path::message::ForwardNode; -use crate::blinded_path::payment::ReceiveTlvs; +use crate::blinded_path::message::{BlindedMessagePath, ForwardNode}; +use crate::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs}; use crate::chain; use crate::chain::WatchedOutput; use crate::chain::chaininterface; @@ -120,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, } @@ -149,7 +148,7 @@ impl<'a> TestRouter<'a> { expected_routes.push_back((query, None)); } - pub fn expect_blinded_payment_paths(&self, mut paths: Vec<(BlindedPayInfo, BlindedPath)>) { + pub fn expect_blinded_payment_paths(&self, mut paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>) { let mut expected_paths = self.next_blinded_payment_paths.lock().unwrap(); core::mem::swap(&mut *expected_paths, &mut paths); } @@ -247,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( @@ -271,7 +270,7 @@ impl<'a> MessageRouter for TestRouter<'a> { >( &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { self.router.create_blinded_paths(recipient, context, peers, secp_ctx) } @@ -280,7 +279,7 @@ impl<'a> MessageRouter for TestRouter<'a> { >( &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { self.router.create_compact_blinded_paths(recipient, context, peers, secp_ctx) } } @@ -316,14 +315,14 @@ impl<'a> MessageRouter for TestMessageRouter<'a> { fn create_blinded_paths( &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { self.inner.create_blinded_paths(recipient, context, peers, secp_ctx) } fn create_compact_blinded_paths( &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, - ) -> Result, ()> { + ) -> Result, ()> { self.inner.create_compact_blinded_paths(recipient, context, peers, secp_ctx) } }