From d792afb08cdc20a30786728c3bfe816dd3b59e47 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 9 Apr 2024 16:14:29 -0500 Subject: [PATCH 1/6] Support NextHop::ShortChannelId in BlindedPath When sending an onion message to a blinded path, the short channel id between hops isn't need in each hop's encrypted_payload since it is not a payment. However, using the short channel id instead of the node id gives a more compact representation. Update BlindedPath::new_for_message to allow for this. --- fuzz/src/invoice_request_deser.rs | 15 +++++- fuzz/src/refund_deser.rs | 15 +++++- lightning/src/blinded_path/message.rs | 34 ++++++++++--- lightning/src/blinded_path/mod.rs | 16 +++--- .../src/onion_message/functional_tests.rs | 51 ++++++++++++++----- lightning/src/onion_message/messenger.rs | 18 +++++-- 6 files changed, 116 insertions(+), 33 deletions(-) diff --git a/fuzz/src/invoice_request_deser.rs b/fuzz/src/invoice_request_deser.rs index 414ce1cdd1c..1aad5bfd897 100644 --- a/fuzz/src/invoice_request_deser.rs +++ b/fuzz/src/invoice_request_deser.rs @@ -11,6 +11,7 @@ use bitcoin::secp256k1::{KeyPair, Parity, PublicKey, Secp256k1, SecretKey, self} use crate::utils::test_logger; use core::convert::TryFrom; use lightning::blinded_path::BlindedPath; +use lightning::blinded_path::message::ForwardNode; use lightning::sign::EntropySource; use lightning::ln::PaymentHash; use lightning::ln::features::BlindedHopFeatures; @@ -73,9 +74,19 @@ fn build_response( invoice_request: &InvoiceRequest, secp_ctx: &Secp256k1 ) -> Result { let entropy_source = Randomness {}; + let intermediate_nodes = [ + [ + ForwardNode { node_id: pubkey(43), short_channel_id: None }, + ForwardNode { node_id: pubkey(44), short_channel_id: None }, + ], + [ + ForwardNode { node_id: pubkey(45), short_channel_id: None }, + ForwardNode { node_id: pubkey(46), short_channel_id: None }, + ], + ]; let paths = vec![ - BlindedPath::new_for_message(&[pubkey(43), pubkey(44), pubkey(42)], &entropy_source, secp_ctx).unwrap(), - BlindedPath::new_for_message(&[pubkey(45), pubkey(46), pubkey(42)], &entropy_source, secp_ctx).unwrap(), + BlindedPath::new_for_message(&intermediate_nodes[0], pubkey(42), &entropy_source, secp_ctx).unwrap(), + BlindedPath::new_for_message(&intermediate_nodes[1], pubkey(42), &entropy_source, secp_ctx).unwrap(), ]; let payinfo = vec![ diff --git a/fuzz/src/refund_deser.rs b/fuzz/src/refund_deser.rs index 14b136ec35b..660ad5e2c1d 100644 --- a/fuzz/src/refund_deser.rs +++ b/fuzz/src/refund_deser.rs @@ -11,6 +11,7 @@ use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey, self}; use crate::utils::test_logger; use core::convert::TryFrom; use lightning::blinded_path::BlindedPath; +use lightning::blinded_path::message::ForwardNode; use lightning::sign::EntropySource; use lightning::ln::PaymentHash; use lightning::ln::features::BlindedHopFeatures; @@ -62,9 +63,19 @@ fn build_response( refund: &Refund, signing_pubkey: PublicKey, secp_ctx: &Secp256k1 ) -> Result { let entropy_source = Randomness {}; + let intermediate_nodes = [ + [ + ForwardNode { node_id: pubkey(43), short_channel_id: None }, + ForwardNode { node_id: pubkey(44), short_channel_id: None }, + ], + [ + ForwardNode { node_id: pubkey(45), short_channel_id: None }, + ForwardNode { node_id: pubkey(46), short_channel_id: None }, + ], + ]; let paths = vec![ - BlindedPath::new_for_message(&[pubkey(43), pubkey(44), pubkey(42)], &entropy_source, secp_ctx).unwrap(), - BlindedPath::new_for_message(&[pubkey(45), pubkey(46), pubkey(42)], &entropy_source, secp_ctx).unwrap(), + BlindedPath::new_for_message(&intermediate_nodes[0], pubkey(42), &entropy_source, secp_ctx).unwrap(), + BlindedPath::new_for_message(&intermediate_nodes[1], pubkey(42), &entropy_source, secp_ctx).unwrap(), ]; let payinfo = vec![ diff --git a/lightning/src/blinded_path/message.rs b/lightning/src/blinded_path/message.rs index 9a282a5f87d..1a0f63d4600 100644 --- a/lightning/src/blinded_path/message.rs +++ b/lightning/src/blinded_path/message.rs @@ -1,3 +1,7 @@ +//! Data structures and methods for constructing [`BlindedPath`]s to send a message over. +//! +//! [`BlindedPath`]: crate::blinded_path::BlindedPath + use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; #[allow(unused_imports)] @@ -16,6 +20,17 @@ use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Writeable, Writer} use core::mem; use core::ops::Deref; +/// An intermediate node, and possibly a short channel id leading to the next node. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct ForwardNode { + /// This node's pubkey. + pub node_id: PublicKey, + /// The channel between `node_id` and the next hop. If set, the constructed [`BlindedHop`]'s + /// `encrypted_payload` will use this instead of the next [`ForwardNode::node_id`] for a more + /// compact representation. + pub short_channel_id: Option, +} + /// TLVs to encode in an intermediate onion message packet's hop data. When provided in a blinded /// route, they are encoded into [`BlindedHop::encrypted_payload`]. pub(crate) struct ForwardTlvs { @@ -60,17 +75,24 @@ impl Writeable for ReceiveTlvs { } } -/// Construct blinded onion message hops for the given `unblinded_path`. +/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`. pub(super) fn blinded_hops( - secp_ctx: &Secp256k1, unblinded_path: &[PublicKey], session_priv: &SecretKey + secp_ctx: &Secp256k1, intermediate_nodes: &[ForwardNode], recipient_node_id: PublicKey, + session_priv: &SecretKey ) -> Result, secp256k1::Error> { - let blinded_tlvs = unblinded_path.iter() + let pks = intermediate_nodes.iter().map(|node| &node.node_id) + .chain(core::iter::once(&recipient_node_id)); + let tlvs = pks.clone() .skip(1) // The first node's TLVs contains the next node's pubkey - .map(|pk| ForwardTlvs { next_hop: NextMessageHop::NodeId(*pk), next_blinding_override: None }) - .map(|tlvs| ControlTlvs::Forward(tlvs)) + .zip(intermediate_nodes.iter().map(|node| node.short_channel_id)) + .map(|(pubkey, scid)| match scid { + Some(scid) => NextMessageHop::ShortChannelId(scid), + None => NextMessageHop::NodeId(*pubkey), + }) + .map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None })) .chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { path_id: None }))); - utils::construct_blinded_hops(secp_ctx, unblinded_path.iter(), blinded_tlvs, session_priv) + 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 diff --git a/lightning/src/blinded_path/mod.rs b/lightning/src/blinded_path/mod.rs index 7f4cfe2e300..5abf53ec166 100644 --- a/lightning/src/blinded_path/mod.rs +++ b/lightning/src/blinded_path/mod.rs @@ -10,7 +10,7 @@ //! Creating blinded paths and related utilities live here. pub mod payment; -pub(crate) mod message; +pub mod message; pub(crate) mod utils; use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; @@ -124,7 +124,7 @@ impl BlindedPath { pub fn one_hop_for_message( recipient_node_id: PublicKey, entropy_source: ES, secp_ctx: &Secp256k1 ) -> Result where ES::Target: EntropySource { - Self::new_for_message(&[recipient_node_id], entropy_source, secp_ctx) + Self::new_for_message(&[], recipient_node_id, entropy_source, secp_ctx) } /// Create a blinded path for an onion message, to be forwarded along `node_pks`. The last node @@ -133,17 +133,21 @@ impl BlindedPath { /// 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( - node_pks: &[PublicKey], entropy_source: ES, secp_ctx: &Secp256k1 + intermediate_nodes: &[message::ForwardNode], recipient_node_id: PublicKey, + entropy_source: ES, secp_ctx: &Secp256k1 ) -> Result where ES::Target: EntropySource { - if node_pks.is_empty() { return Err(()) } + 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"); - let introduction_node = IntroductionNode::NodeId(node_pks[0]); Ok(BlindedPath { introduction_node, blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret), - blinded_hops: message::blinded_hops(secp_ctx, node_pks, &blinding_secret).map_err(|_| ())?, + blinded_hops: message::blinded_hops( + secp_ctx, intermediate_nodes, recipient_node_id, &blinding_secret, + ).map_err(|_| ())?, }) } diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 764a2bdcbdc..029038a9fe7 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -10,6 +10,7 @@ //! Onion message testing and test utilities live here. use crate::blinded_path::{BlindedPath, EmptyNodeIdLookUp}; +use crate::blinded_path::message::ForwardNode; use crate::events::{Event, EventsProvider}; use crate::ln::features::{ChannelFeatures, InitFeatures}; use crate::ln::msgs::{self, DecodeError, OnionMessageHandler}; @@ -327,7 +328,7 @@ fn one_blinded_hop() { let test_msg = TestCustomMessage::Response; let secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath::new_for_message(&[nodes[1].node_id], &*nodes[1].entropy_source, &secp_ctx).unwrap(); + let blinded_path = BlindedPath::new_for_message(&[], nodes[1].node_id, &*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::Response); @@ -340,7 +341,8 @@ fn two_unblinded_two_blinded() { let test_msg = TestCustomMessage::Response; let secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath::new_for_message(&[nodes[3].node_id, nodes[4].node_id], &*nodes[4].entropy_source, &secp_ctx).unwrap(); + let intermediate_nodes = [ForwardNode { node_id: nodes[3].node_id, short_channel_id: None }]; + let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[4].node_id, &*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), @@ -358,7 +360,11 @@ fn three_blinded_hops() { let test_msg = TestCustomMessage::Response; let secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath::new_for_message(&[nodes[1].node_id, nodes[2].node_id, nodes[3].node_id], &*nodes[3].entropy_source, &secp_ctx).unwrap(); + let intermediate_nodes = [ + ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, + ForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, + ]; + let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[3].node_id, &*nodes[3].entropy_source, &secp_ctx).unwrap(); let destination = Destination::BlindedPath(blinded_path); nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); @@ -391,7 +397,11 @@ fn we_are_intro_node() { let test_msg = TestCustomMessage::Response; let secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath::new_for_message(&[nodes[0].node_id, nodes[1].node_id, nodes[2].node_id], &*nodes[2].entropy_source, &secp_ctx).unwrap(); + let intermediate_nodes = [ + ForwardNode { node_id: nodes[0].node_id, short_channel_id: None }, + ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, + ]; + let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[2].node_id, &*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(); @@ -399,7 +409,8 @@ fn we_are_intro_node() { pass_along_path(&nodes); // Try with a two-hop blinded path where we are the introduction node. - let blinded_path = BlindedPath::new_for_message(&[nodes[0].node_id, nodes[1].node_id], &*nodes[1].entropy_source, &secp_ctx).unwrap(); + let intermediate_nodes = [ForwardNode { node_id: nodes[0].node_id, short_channel_id: None }]; + let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[1].node_id, &*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::Response); @@ -414,7 +425,8 @@ fn invalid_blinded_path_error() { let test_msg = TestCustomMessage::Response; let secp_ctx = Secp256k1::new(); - let mut blinded_path = BlindedPath::new_for_message(&[nodes[1].node_id, nodes[2].node_id], &*nodes[2].entropy_source, &secp_ctx).unwrap(); + let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; + let mut blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[2].node_id, &*nodes[2].entropy_source, &secp_ctx).unwrap(); blinded_path.blinded_hops.clear(); let destination = Destination::BlindedPath(blinded_path); let err = nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap_err(); @@ -433,7 +445,11 @@ fn reply_path() { destination: Destination::Node(nodes[3].node_id), first_node_addresses: None, }; - let reply_path = BlindedPath::new_for_message(&[nodes[2].node_id, nodes[1].node_id, nodes[0].node_id], &*nodes[0].entropy_source, &secp_ctx).unwrap(); + 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 reply_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[0].node_id, &*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::Request); pass_along_path(&nodes); @@ -443,9 +459,17 @@ fn reply_path() { pass_along_path(&nodes); // Destination::BlindedPath - let blinded_path = BlindedPath::new_for_message(&[nodes[1].node_id, nodes[2].node_id, nodes[3].node_id], &*nodes[3].entropy_source, &secp_ctx).unwrap(); + let intermediate_nodes = [ + ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, + ForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, + ]; + let blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[3].node_id, &*nodes[3].entropy_source, &secp_ctx).unwrap(); let destination = Destination::BlindedPath(blinded_path); - let reply_path = BlindedPath::new_for_message(&[nodes[2].node_id, nodes[1].node_id, nodes[0].node_id], &*nodes[0].entropy_source, &secp_ctx).unwrap(); + 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 reply_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[0].node_id, &*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::Request); @@ -525,8 +549,9 @@ fn requests_peer_connection_for_buffered_messages() { let secp_ctx = Secp256k1::new(); add_channel_to_graph(&nodes[0], &nodes[1], &secp_ctx, 42); + let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; let blinded_path = BlindedPath::new_for_message( - &[nodes[1].node_id, nodes[2].node_id], &*nodes[0].entropy_source, &secp_ctx + &intermediate_nodes, nodes[2].node_id, &*nodes[0].entropy_source, &secp_ctx ).unwrap(); let destination = Destination::BlindedPath(blinded_path); @@ -562,8 +587,9 @@ fn drops_buffered_messages_waiting_for_peer_connection() { let secp_ctx = Secp256k1::new(); add_channel_to_graph(&nodes[0], &nodes[1], &secp_ctx, 42); + let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; let blinded_path = BlindedPath::new_for_message( - &[nodes[1].node_id, nodes[2].node_id], &*nodes[0].entropy_source, &secp_ctx + &intermediate_nodes, nodes[2].node_id, &*nodes[0].entropy_source, &secp_ctx ).unwrap(); let destination = Destination::BlindedPath(blinded_path); @@ -611,8 +637,9 @@ fn intercept_offline_peer_oms() { let message = TestCustomMessage::Response; let secp_ctx = Secp256k1::new(); + let intermediate_nodes = [ForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; let blinded_path = BlindedPath::new_for_message( - &[nodes[1].node_id, nodes[2].node_id], &*nodes[2].entropy_source, &secp_ctx + &intermediate_nodes, nodes[2].node_id, &*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 b10bd185100..9fd6fd95f95 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -16,7 +16,7 @@ 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, ForwardTlvs, ReceiveTlvs}; +use crate::blinded_path::message::{advance_path_by_one, ForwardNode, ForwardTlvs, ReceiveTlvs}; use crate::blinded_path::utils; use crate::events::{Event, EventHandler, EventsProvider}; use crate::sign::{EntropySource, NodeSigner, Recipient}; @@ -71,6 +71,7 @@ pub(super) const MAX_TIMER_TICKS: usize = 2; /// # use bitcoin::hashes::hex::FromHex; /// # use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey, self}; /// # use lightning::blinded_path::{BlindedPath, EmptyNodeIdLookUp}; +/// # use lightning::blinded_path::message::ForwardNode; /// # use lightning::sign::{EntropySource, KeysManager}; /// # use lightning::ln::peer_handler::IgnoringMessageHandler; /// # use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath, OnionMessenger}; @@ -145,8 +146,11 @@ pub(super) const MAX_TIMER_TICKS: usize = 2; /// /// // Create a blinded path to yourself, for someone to send an onion message to. /// # let your_node_id = hop_node_id1; -/// let hops = [hop_node_id3, hop_node_id4, your_node_id]; -/// let blinded_path = BlindedPath::new_for_message(&hops, &keys_manager, &secp_ctx).unwrap(); +/// let hops = [ +/// ForwardNode { node_id: hop_node_id3, short_channel_id: None }, +/// ForwardNode { node_id: hop_node_id4, short_channel_id: None }, +/// ]; +/// let blinded_path = BlindedPath::new_for_message(&hops, your_node_id, &keys_manager, &secp_ctx).unwrap(); /// /// // Send a custom onion message to a blinded path. /// let destination = Destination::BlindedPath(blinded_path); @@ -435,8 +439,12 @@ where }); let paths = peer_info.into_iter() - .map(|(pubkey, _, _)| vec![pubkey, recipient]) - .map(|node_pks| BlindedPath::new_for_message(&node_pks, &*self.entropy_source, secp_ctx)) + .map(|(node_id, _, _)| vec![ForwardNode { node_id, short_channel_id: None }]) + .map(|intermediate_nodes| { + BlindedPath::new_for_message( + &intermediate_nodes, recipient, &*self.entropy_source, secp_ctx + ) + }) .take(MAX_PATHS) .collect::, _>>(); From e553a71b6f82c5cc61a0f12084444384058e9bc3 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 9 May 2024 17:31:37 -0500 Subject: [PATCH 2/6] Pass ForwardNode when creating BlindedPath Instead of passing Vec to MessageRouter::crate_blinded_path, pass Vec. This way callers can include a short_channel_id for a more compact BlindedPath encoding. --- fuzz/src/chanmon_consistency.rs | 3 ++- fuzz/src/full_stack.rs | 3 ++- fuzz/src/onion_message.rs | 3 ++- lightning/src/ln/channel.rs | 2 +- lightning/src/ln/channelmanager.rs | 13 +++++++++++-- lightning/src/onion_message/messenger.rs | 21 +++++++++------------ lightning/src/routing/router.rs | 7 ++++--- lightning/src/util/test_utils.rs | 5 +++-- 8 files changed, 34 insertions(+), 23 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index b3cf867d6e3..5004580231e 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -31,6 +31,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hash_types::{BlockHash, WPubkeyHash}; use lightning::blinded_path::BlindedPath; +use lightning::blinded_path::message::ForwardNode; use lightning::blinded_path::payment::ReceiveTlvs; use lightning::chain; use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, chainmonitor, channelmonitor, Confirm, Watch}; @@ -119,7 +120,7 @@ impl MessageRouter for FuzzRouter { } fn create_blinded_paths( - &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() } diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index d07def30ff9..adb997ab22c 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -28,6 +28,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash}; use lightning::blinded_path::BlindedPath; +use lightning::blinded_path::message::ForwardNode; use lightning::blinded_path::payment::ReceiveTlvs; use lightning::chain; use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen}; @@ -157,7 +158,7 @@ impl MessageRouter for FuzzRouter { } fn create_blinded_paths( - &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() } diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 19ba4cb6aac..4e563e28a46 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -7,6 +7,7 @@ use bitcoin::secp256k1::ecdsa::RecoverableSignature; use bitcoin::secp256k1::schnorr; use lightning::blinded_path::{BlindedPath, EmptyNodeIdLookUp}; +use lightning::blinded_path::message::ForwardNode; use lightning::ln::features::InitFeatures; use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler}; use lightning::ln::script::ShutdownScript; @@ -88,7 +89,7 @@ impl MessageRouter for TestMessageRouter { } fn create_blinded_paths( - &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() } diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 5fbdb595b77..f6b7630bf9c 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -1403,7 +1403,7 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { /// Either the height at which this channel was created or the height at which it was last /// serialized if it was serialized by versions prior to 0.0.103. /// We use this to close if funding is never broadcasted. - channel_creation_height: u32, + pub(super) channel_creation_height: u32, counterparty_dust_limit_satoshis: u64, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index f2b3bf15d39..a382b38ba6d 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -32,6 +32,7 @@ use bitcoin::secp256k1::Secp256k1; use bitcoin::{secp256k1, Sequence}; use crate::blinded_path::{BlindedPath, NodeIdLookUp}; +use crate::blinded_path::message::ForwardNode; use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs}; use crate::chain; use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock}; @@ -8996,8 +8997,16 @@ where let peers = self.per_peer_state.read().unwrap() .iter() - .filter(|(_, peer)| peer.lock().unwrap().latest_features.supports_onion_messages()) - .map(|(node_id, _)| *node_id) + .map(|(node_id, peer_state)| (node_id, peer_state.lock().unwrap())) + .filter(|(_, peer)| peer.latest_features.supports_onion_messages()) + .map(|(node_id, peer)| ForwardNode { + node_id: *node_id, + short_channel_id: peer.channel_by_id + .iter() + .filter(|(_, channel)| channel.context().is_usable()) + .min_by_key(|(_, channel)| channel.context().channel_creation_height) + .and_then(|(_, channel)| channel.context().get_short_channel_id()), + }) .collect::>(); self.router diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 9fd6fd95f95..5493b267ed9 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -98,7 +98,7 @@ pub(super) const MAX_TIMER_TICKS: usize = 2; /// # }) /// # } /// # fn create_blinded_paths( -/// # &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1 +/// # &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1 /// # ) -> Result, ()> { /// # unreachable!() /// # } @@ -341,7 +341,7 @@ pub trait MessageRouter { fn create_blinded_paths< T: secp256k1::Signing + secp256k1::Verification >( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()>; } @@ -408,7 +408,7 @@ where fn create_blinded_paths< T: secp256k1::Signing + secp256k1::Verification >( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { // Limit the number of blinded paths that are computed. const MAX_PATHS: usize = 3; @@ -421,13 +421,13 @@ where let is_recipient_announced = network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient)); - let mut peer_info = peers.iter() + let mut peer_info = peers.into_iter() // Limit to peers with announced channels - .filter_map(|pubkey| + .filter_map(|peer| network_graph - .node(&NodeId::from_pubkey(pubkey)) + .node(&NodeId::from_pubkey(&peer.node_id)) .filter(|info| info.channels.len() >= MIN_PEER_CHANNELS) - .map(|info| (*pubkey, info.is_tor_only(), info.channels.len())) + .map(|info| (peer, info.is_tor_only(), info.channels.len())) ) // Exclude Tor-only nodes when the recipient is announced. .filter(|(_, is_tor_only, _)| !(*is_tor_only && is_recipient_announced)) @@ -439,11 +439,8 @@ where }); let paths = peer_info.into_iter() - .map(|(node_id, _, _)| vec![ForwardNode { node_id, short_channel_id: None }]) - .map(|intermediate_nodes| { - BlindedPath::new_for_message( - &intermediate_nodes, recipient, &*self.entropy_source, secp_ctx - ) + .map(|(peer, _, _)| { + BlindedPath::new_for_message(&[peer], recipient, &*self.entropy_source, secp_ctx) }) .take(MAX_PATHS) .collect::, _>>(); diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 95c03c4431e..b4b238e820b 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -12,7 +12,8 @@ use bitcoin::secp256k1::{PublicKey, Secp256k1, self}; use crate::blinded_path::{BlindedHop, BlindedPath, Direction, IntroductionNode}; -use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs}; +use crate::blinded_path::message; +use crate::blinded_path::payment::{ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs, self}; use crate::ln::{PaymentHash, PaymentPreimage}; use crate::ln::channelmanager::{ChannelDetails, PaymentId, MIN_FINAL_CLTV_EXPIRY_DELTA, RecipientOnionFields}; use crate::ln::features::{BlindedHopFeatures, Bolt11InvoiceFeatures, Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures}; @@ -122,7 +123,7 @@ impl> + Clone, L: Deref, ES: Deref, S: Deref, max_cltv_expiry: tlvs.payment_constraints.max_cltv_expiry + cltv_expiry_delta, htlc_minimum_msat: details.inbound_htlc_minimum_msat.unwrap_or(0), }; - Some(ForwardNode { + Some(payment::ForwardNode { tlvs: ForwardTlvs { short_channel_id, payment_relay, @@ -171,7 +172,7 @@ impl< G: Deref> + Clone, L: Deref, ES: Deref, S: Deref, fn create_blinded_paths< T: secp256k1::Signing + secp256k1::Verification > ( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { self.message_router.create_blinded_paths(recipient, peers, secp_ctx) } diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 9ff5d76ef8d..92d43193e30 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -8,6 +8,7 @@ // licenses. use crate::blinded_path::BlindedPath; +use crate::blinded_path::message::ForwardNode; use crate::blinded_path::payment::ReceiveTlvs; use crate::chain; use crate::chain::WatchedOutput; @@ -246,7 +247,7 @@ impl<'a> MessageRouter for TestRouter<'a> { fn create_blinded_paths< T: secp256k1::Signing + secp256k1::Verification >( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { self.router.create_blinded_paths(recipient, peers, secp_ctx) } @@ -281,7 +282,7 @@ impl<'a> MessageRouter for TestMessageRouter<'a> { } fn create_blinded_paths( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { self.inner.create_blinded_paths(recipient, peers, secp_ctx) } From 4956ade170f112881f3454dacc95f90b64e6aad3 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 10 Apr 2024 16:07:58 -0500 Subject: [PATCH 3/6] Unwrap reply_path in extract_invoice_request --- lightning/src/ln/offers_tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 6ae87e6001d..6484f5259f6 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -178,11 +178,11 @@ fn claim_bolt12_payment<'a, 'b, 'c>( fn extract_invoice_request<'a, 'b, 'c>( node: &Node<'a, 'b, 'c>, message: &OnionMessage -) -> (InvoiceRequest, Option) { +) -> (InvoiceRequest, BlindedPath) { match node.onion_messenger.peel_onion_message(message) { Ok(PeeledOnion::Receive(message, _, reply_path)) => match message { ParsedOnionMessageContents::Offers(offers_message) => match offers_message { - OffersMessage::InvoiceRequest(invoice_request) => (invoice_request, reply_path), + OffersMessage::InvoiceRequest(invoice_request) => (invoice_request, reply_path.unwrap()), OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), OffersMessage::InvoiceError(error) => panic!("Unexpected invoice_error: {:?}", error), }, @@ -417,7 +417,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.unwrap().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); @@ -566,7 +566,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.unwrap().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); From 0a6886ee38cfd906f984d7b8f444cb8621fce4fd Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 10 Apr 2024 16:04:19 -0500 Subject: [PATCH 4/6] Compact a BlindedPath's introduction node Add a method to BlindedPath that given a network graph will compact the IntroductionNode as the DirectedShortChannelId variant. Call this method from DefaultMessageRouter so that Offer paths use the compact representation (along with reply paths). This leaves payment paths in Bolt12Invoice using the NodeId variant, as the compact representation isn't as useful there. --- lightning/src/blinded_path/mod.rs | 30 +++++++++++++++++ lightning/src/ln/offers_tests.rs | 42 ++++++++++++++++++------ lightning/src/onion_message/messenger.rs | 7 +++- 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/lightning/src/blinded_path/mod.rs b/lightning/src/blinded_path/mod.rs index 5abf53ec166..2d3d085bddf 100644 --- a/lightning/src/blinded_path/mod.rs +++ b/lightning/src/blinded_path/mod.rs @@ -21,6 +21,7 @@ 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::*; @@ -217,6 +218,35 @@ 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/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 6484f5259f6..016afd32a09 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -41,6 +41,7 @@ //! blinded paths are used. use bitcoin::network::constants::Network; +use bitcoin::secp256k1::PublicKey; use core::time::Duration; use crate::blinded_path::{BlindedPath, IntroductionNode}; use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentContext}; @@ -133,6 +134,12 @@ fn announce_node_address<'a, 'b, 'c>( } } +fn resolve_introduction_node<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, path: &BlindedPath) -> PublicKey { + path.public_introduction_node_id(&node.network_graph.read_only()) + .and_then(|node_id| node_id.as_pubkey().ok()) + .unwrap() +} + fn route_bolt12_payment<'a, 'b, 'c>( node: &Node<'a, 'b, 'c>, path: &[&Node<'a, 'b, 'c>], invoice: &Bolt12Invoice ) { @@ -273,8 +280,9 @@ fn prefers_non_tor_nodes_in_blinded_paths() { assert_ne!(offer.signing_pubkey(), Some(bob_id)); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_ne!(path.introduction_node, IntroductionNode::NodeId(bob_id)); - assert_ne!(path.introduction_node, IntroductionNode::NodeId(charlie_id)); + let introduction_node_id = resolve_introduction_node(david, &path); + assert_ne!(introduction_node_id, bob_id); + assert_ne!(introduction_node_id, charlie_id); } // Use a one-hop blinded path when Bob is announced and all his peers are Tor-only. @@ -288,7 +296,8 @@ fn prefers_non_tor_nodes_in_blinded_paths() { assert_ne!(offer.signing_pubkey(), Some(bob_id)); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id)); + let introduction_node_id = resolve_introduction_node(david, &path); + assert_eq!(introduction_node_id, bob_id); } } @@ -338,7 +347,8 @@ fn prefers_more_connected_nodes_in_blinded_paths() { assert_ne!(offer.signing_pubkey(), Some(bob_id)); assert!(!offer.paths().is_empty()); for path in offer.paths() { - assert_eq!(path.introduction_node, IntroductionNode::NodeId(nodes[4].node.get_our_node_id())); + let introduction_node_id = resolve_introduction_node(david, &path); + assert_eq!(introduction_node_id, nodes[4].node.get_our_node_id()); } } @@ -388,7 +398,9 @@ 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)); + let introduction_node_id = resolve_introduction_node(david, &path); + assert_eq!(introduction_node_id, bob_id); + assert!(matches!(path.introduction_node, IntroductionNode::DirectedShortChannelId(..))); } let payment_id = PaymentId([1; 32]); @@ -415,9 +427,11 @@ fn creates_and_pays_for_offer_using_two_hop_blinded_path() { payer_note_truncated: None, }, }); + let introduction_node_id = resolve_introduction_node(alice, &reply_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!(introduction_node_id, charlie_id); + assert!(matches!(reply_path.introduction_node, IntroductionNode::DirectedShortChannelId(..))); let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap(); charlie.onion_messenger.handle_onion_message(&alice_id, &onion_message); @@ -489,7 +503,9 @@ 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)); + let introduction_node_id = resolve_introduction_node(alice, &path); + assert_eq!(introduction_node_id, charlie_id); + assert!(matches!(path.introduction_node, IntroductionNode::DirectedShortChannelId(..))); } expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id); @@ -545,7 +561,9 @@ 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)); + let introduction_node_id = resolve_introduction_node(bob, &path); + assert_eq!(introduction_node_id, alice_id); + assert!(matches!(path.introduction_node, IntroductionNode::DirectedShortChannelId(..))); } let payment_id = PaymentId([1; 32]); @@ -564,9 +582,11 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() { payer_note_truncated: None, }, }); + let introduction_node_id = resolve_introduction_node(alice, &reply_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!(introduction_node_id, bob_id); + assert!(matches!(reply_path.introduction_node, IntroductionNode::DirectedShortChannelId(..))); let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap(); bob.onion_messenger.handle_onion_message(&alice_id, &onion_message); @@ -614,7 +634,9 @@ 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)); + let introduction_node_id = resolve_introduction_node(alice, &path); + assert_eq!(introduction_node_id, bob_id); + assert!(matches!(path.introduction_node, IntroductionNode::DirectedShortChannelId(..))); } expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id); diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 5493b267ed9..fc3eead1e4f 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -445,7 +445,7 @@ where .take(MAX_PATHS) .collect::, _>>(); - match paths { + let mut paths = match paths { Ok(paths) if !paths.is_empty() => Ok(paths), _ => { if is_recipient_announced { @@ -455,7 +455,12 @@ where Err(()) } }, + }?; + for path in &mut paths { + path.use_compact_introduction_node(&network_graph); } + + Ok(paths) } } From e8354b212b27a07d62a69b8de4cbcec02f20decd Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Mon, 22 Apr 2024 14:52:15 -0500 Subject: [PATCH 5/6] Compact introduction node test vector --- lightning/src/offers/offer.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index 5a824b9162f..b10a87866a2 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -1860,6 +1860,9 @@ mod bolt12_tests { // with blinded path via Bob (0x424242...), blinding 020202... "lno1pgx9getnwss8vetrw3hhyucs5ypjgef743p5fzqq9nqxh0ah7y87rzv3ud0eleps9kl2d5348hq2k8qzqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgqpqqqqqqqqqqqqqqqqqqqqqqqqqqqzqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqqzq3zyg3zyg3zyg3vggzamrjghtt05kvkvpcp0a79gmy3nt6jsn98ad2xs8de6sl9qmgvcvs", + // ... and with sciddir introduction node + "lno1pgx9getnwss8vetrw3hhyucs3yqqqqqqqqqqqqp2qgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqqyqqqqqqqqqqqqqqqqqqqqqqqqqqqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqqgzyg3zyg3zyg3z93pqthvwfzadd7jejes8q9lhc4rvjxd022zv5l44g6qah82ru5rdpnpj", + // ... and with second blinded path via Carol (0x434343...), blinding 020202... "lno1pgx9getnwss8vetrw3hhyucsl5q5yqeyv5l2cs6y3qqzesrth7mlzrlp3xg7xhulusczm04x6g6nms9trspqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqqsqqqqqqqqqqqqqqqqqqqqqqqqqqpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsqpqg3zyg3zyg3zygz0uc7h32x9s0aecdhxlk075kn046aafpuuyw8f5j652t3vha2yqrsyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsqzqqqqqqqqqqqqqqqqqqqqqqqqqqqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqqyzyg3zyg3zyg3zzcss9mk8y3wkklfvevcrszlmu23kfrxh49px20665dqwmn4p72pksese", From e4661fe4c4b9d1d25eeb71dedfc65071d7ca1eb8 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 23 May 2024 15:52:32 -0500 Subject: [PATCH 6/6] Add missing copyright statement --- lightning/src/blinded_path/message.rs | 9 +++++++++ lightning/src/blinded_path/payment.rs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/lightning/src/blinded_path/message.rs b/lightning/src/blinded_path/message.rs index 1a0f63d4600..1f3f5a1fa38 100644 --- a/lightning/src/blinded_path/message.rs +++ b/lightning/src/blinded_path/message.rs @@ -1,3 +1,12 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// 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 diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index dfe89e0ebc6..5e44c792d33 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -1,3 +1,12 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// 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