From 42c096c491bad1659c3cfdc04f87dc396220a131 Mon Sep 17 00:00:00 2001 From: shaavan Date: Sat, 15 Jun 2024 19:22:56 +0530 Subject: [PATCH] Allow create_blinded_paths functions to accept MessageContext as input field - Enabled `create_blinded_paths` to accept `MessageContext` TLVs as an input field. - `MessageContext` is intended to be sent along with the `reply_path` to the counterparty. - Added `MessageContext` in the `create_blinded_paths` flow, optionally appending it within the `reply_path`. - Updated tests to verify the new feature. --- fuzz/src/chanmon_consistency.rs | 4 +- fuzz/src/full_stack.rs | 4 +- fuzz/src/invoice_request_deser.rs | 22 ++++++-- fuzz/src/onion_message.rs | 3 +- fuzz/src/refund_deser.rs | 22 ++++++-- lightning/src/blinded_path/message.rs | 5 +- lightning/src/blinded_path/mod.rs | 10 ++-- lightning/src/ln/channelmanager.rs | 27 +++++----- .../src/ln/max_payment_path_len_tests.rs | 11 +++- lightning/src/ln/offers_tests.rs | 8 +++ .../src/onion_message/functional_tests.rs | 51 ++++++++++++------- lightning/src/onion_message/messenger.rs | 51 ++++++++++--------- lightning/src/routing/router.rs | 10 ++-- lightning/src/util/test_utils.rs | 21 +++++--- 14 files changed, 163 insertions(+), 86 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 39ed7300c..7d660f459 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -33,6 +33,7 @@ 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::chain; @@ -138,7 +139,8 @@ impl MessageRouter for FuzzRouter { } fn create_blinded_paths( - &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, + _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() } diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 86f4ef4de..9c45c66e1 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -30,6 +30,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hashes::Hash as _; use bitcoin::WPubkeyHash; +use lightning::blinded_path::message::MessageContext; use lightning::blinded_path::payment::ReceiveTlvs; use lightning::blinded_path::BlindedPath; use lightning::chain; @@ -175,7 +176,8 @@ impl MessageRouter for FuzzRouter { } fn create_blinded_paths( - &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, + _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() } diff --git a/fuzz/src/invoice_request_deser.rs b/fuzz/src/invoice_request_deser.rs index 642da5823..54b842feb 100644 --- a/fuzz/src/invoice_request_deser.rs +++ b/fuzz/src/invoice_request_deser.rs @@ -10,7 +10,7 @@ use crate::utils::test_logger; use bitcoin::secp256k1::{self, Keypair, Parity, PublicKey, Secp256k1, SecretKey}; use core::convert::TryFrom; -use lightning::blinded_path::message::ForwardNode; +use lightning::blinded_path::message::{ForwardNode, MessageContext, OffersContext}; use lightning::blinded_path::BlindedPath; use lightning::ln::features::BlindedHopFeatures; use lightning::ln::PaymentHash; @@ -87,10 +87,22 @@ fn build_response( ], ]; let paths = vec![ - 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(), + BlindedPath::new_for_message( + &intermediate_nodes[0], + pubkey(42), + MessageContext::Offers(OffersContext::Unknown {}), + &entropy_source, + secp_ctx, + ) + .unwrap(), + BlindedPath::new_for_message( + &intermediate_nodes[1], + pubkey(42), + MessageContext::Offers(OffersContext::Unknown {}), + &entropy_source, + secp_ctx, + ) + .unwrap(), ]; let payinfo = vec![ diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index e7f2c8daa..05ee7526f 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -95,7 +95,8 @@ impl MessageRouter for TestMessageRouter { } fn create_blinded_paths( - &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, + _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() } diff --git a/fuzz/src/refund_deser.rs b/fuzz/src/refund_deser.rs index 11907b6d6..8e9e6442f 100644 --- a/fuzz/src/refund_deser.rs +++ b/fuzz/src/refund_deser.rs @@ -10,7 +10,7 @@ use crate::utils::test_logger; use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1, SecretKey}; use core::convert::TryFrom; -use lightning::blinded_path::message::ForwardNode; +use lightning::blinded_path::message::{ForwardNode, MessageContext, OffersContext}; use lightning::blinded_path::BlindedPath; use lightning::ln::features::BlindedHopFeatures; use lightning::ln::PaymentHash; @@ -76,10 +76,22 @@ fn build_response( ], ]; let paths = vec![ - 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(), + BlindedPath::new_for_message( + &intermediate_nodes[0], + pubkey(42), + MessageContext::Offers(OffersContext::Unknown {}), + &entropy_source, + secp_ctx, + ) + .unwrap(), + BlindedPath::new_for_message( + &intermediate_nodes[1], + pubkey(42), + MessageContext::Offers(OffersContext::Unknown {}), + &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 973df8539..06d535a35 100644 --- a/lightning/src/blinded_path/message.rs +++ b/lightning/src/blinded_path/message.rs @@ -12,6 +12,7 @@ //! [`BlindedPath`]: crate::blinded_path::BlindedPath use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; + #[allow(unused_imports)] use crate::prelude::*; @@ -133,7 +134,7 @@ impl_writeable_tlv_based_enum!(OffersContext, /// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`. pub(super) fn blinded_hops( secp_ctx: &Secp256k1, intermediate_nodes: &[ForwardNode], recipient_node_id: PublicKey, - session_priv: &SecretKey + context: MessageContext, session_priv: &SecretKey ) -> Result, secp256k1::Error> { let pks = intermediate_nodes.iter().map(|node| &node.node_id) .chain(core::iter::once(&recipient_node_id)); @@ -145,7 +146,7 @@ pub(super) fn blinded_hops( None => NextMessageHop::NodeId(*pubkey), }) .map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None })) - .chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { context: None }))); + .chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs{ context: Some(context) }))); utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv) } diff --git a/lightning/src/blinded_path/mod.rs b/lightning/src/blinded_path/mod.rs index 2d3d085bd..db90e1659 100644 --- a/lightning/src/blinded_path/mod.rs +++ b/lightning/src/blinded_path/mod.rs @@ -14,6 +14,7 @@ pub mod message; pub(crate) mod utils; use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; +use message::MessageContext; use core::ops::Deref; use crate::ln::msgs::DecodeError; @@ -123,9 +124,9 @@ pub struct BlindedHop { impl BlindedPath { /// Create a one-hop blinded path for a message. pub fn one_hop_for_message( - recipient_node_id: PublicKey, entropy_source: ES, secp_ctx: &Secp256k1 + recipient_node_id: PublicKey, context: MessageContext, 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, context, entropy_source, secp_ctx) } /// Create a blinded path for an onion message, to be forwarded along `node_pks`. The last node @@ -135,7 +136,7 @@ impl BlindedPath { // 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, - entropy_source: ES, secp_ctx: &Secp256k1 + 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) @@ -147,7 +148,8 @@ impl 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, &blinding_secret, + secp_ctx, intermediate_nodes, recipient_node_id, + context, &blinding_secret, ).map_err(|_| ())?, }) } diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index a5c32897d..7794d118a 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -31,7 +31,7 @@ use bitcoin::secp256k1::{SecretKey,PublicKey}; use bitcoin::secp256k1::Secp256k1; use bitcoin::{secp256k1, Sequence}; -use crate::blinded_path::message::OffersContext; +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}; @@ -8377,7 +8377,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => { let entropy = &*$self.entropy_source; let secp_ctx = &$self.secp_ctx; - let path = $self.create_blinded_path_using_absolute_expiry(absolute_expiry) + let path = $self.create_blinded_path_using_absolute_expiry(OffersContext::Unknown {}, absolute_expiry) .map_err(|_| Bolt12SemanticError::MissingPaths)?; let builder = OfferBuilder::deriving_signing_pubkey( node_id, expanded_key, entropy, secp_ctx @@ -8449,7 +8449,8 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => { let entropy = &*$self.entropy_source; let secp_ctx = &$self.secp_ctx; - let path = $self.create_blinded_path_using_absolute_expiry(Some(absolute_expiry)) + let context = OffersContext::OutboundPayment { payment_id }; + let path = $self.create_blinded_path_using_absolute_expiry(context, Some(absolute_expiry)) .map_err(|_| Bolt12SemanticError::MissingPaths)?; let builder = RefundBuilder::deriving_payer_id( node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id @@ -8572,7 +8573,9 @@ where Some(payer_note) => builder.payer_note(payer_note), }; let invoice_request = builder.build_and_sign()?; - let reply_path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?; + + let context = OffersContext::OutboundPayment { payment_id }; + let reply_path = self.create_blinded_path(context).map_err(|_| Bolt12SemanticError::MissingPaths)?; let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); @@ -8672,7 +8675,7 @@ where )?; let builder: InvoiceBuilder = builder.into(); let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?; - let reply_path = self.create_blinded_path() + let reply_path = self.create_blinded_path(OffersContext::Unknown {}) .map_err(|_| Bolt12SemanticError::MissingPaths)?; let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap(); @@ -8805,15 +8808,15 @@ where /// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See /// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. fn create_blinded_path_using_absolute_expiry( - &self, absolute_expiry: Option + &self, context: OffersContext, absolute_expiry: Option, ) -> Result { let now = self.duration_since_epoch(); let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY); if absolute_expiry.unwrap_or(Duration::MAX) <= max_short_lived_absolute_expiry { - self.create_compact_blinded_path() + self.create_compact_blinded_path(context) } else { - self.create_blinded_path() + self.create_blinded_path(context) } } @@ -8833,7 +8836,7 @@ where /// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`]. /// /// Errors if the `MessageRouter` errors or returns an empty `Vec`. - fn create_blinded_path(&self) -> Result { + fn create_blinded_path(&self, context: OffersContext) -> Result { let recipient = self.get_our_node_id(); let secp_ctx = &self.secp_ctx; @@ -8846,14 +8849,14 @@ where .collect::>(); self.router - .create_blinded_paths(recipient, peers, secp_ctx) + .create_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx) .and_then(|paths| paths.into_iter().next().ok_or(())) } /// Creates a blinded path by delegating to [`MessageRouter::create_compact_blinded_paths`]. /// /// Errors if the `MessageRouter` errors or returns an empty `Vec`. - fn create_compact_blinded_path(&self) -> Result { + fn create_compact_blinded_path(&self, context: OffersContext) -> Result { let recipient = self.get_our_node_id(); let secp_ctx = &self.secp_ctx; @@ -8873,7 +8876,7 @@ where .collect::>(); self.router - .create_compact_blinded_paths(recipient, peers, secp_ctx) + .create_compact_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx) .and_then(|paths| paths.into_iter().next().ok_or(())) } diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index a77d91e89..096bcf963 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -13,7 +13,7 @@ use bitcoin::secp256k1::{Secp256k1, PublicKey}; use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode}; use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, ReceiveTlvs}; -use crate::events::MessageSendEventsProvider; +use crate::events::{Event, MessageSendEventsProvider}; use crate::ln::PaymentSecret; use crate::ln::blinded_payment_tests::get_blinded_route_parameters; use crate::ln::channelmanager::PaymentId; @@ -389,4 +389,13 @@ fn bolt12_invoice_too_large_blinded_paths() { nodes[0].onion_messenger.handle_onion_message(&nodes[1].node.get_our_node_id(), &invoice_om); // TODO: assert on the invoice error once we support replying to invoice OMs with failure info nodes[0].logger.assert_log_contains("lightning::ln::channelmanager", "Failed paying invoice: OnionPacketSizeExceeded", 1); + + let events = nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::PaymentFailed { payment_id: id, .. } => { + assert_eq!(id, payment_id) + }, + _ => panic!("Unexpected event"), + } } diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 405ab87be..83ff8ce6d 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -1412,6 +1412,14 @@ fn fails_sending_invoice_without_blinded_payment_paths_for_offer() { let invoice_error = extract_invoice_error(david, &onion_message); assert_eq!(invoice_error, InvoiceError::from(Bolt12SemanticError::MissingPaths)); + + // Confirm that david drops this failed payment from his pending outbound payments. + match get_event!(david, Event::InvoiceRequestFailed) { + Event::InvoiceRequestFailed { payment_id: pay_id } => { + assert_eq!(pay_id, payment_id) + }, + _ => panic!("No Event::InvoiceRequestFailed"), + } } #[test] diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 2851cfed1..371b4f587 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -10,7 +10,7 @@ //! Onion message testing and test utilities live here. use crate::blinded_path::{BlindedPath, EmptyNodeIdLookUp}; -use crate::blinded_path::message::{ForwardNode, OffersContext}; +use crate::blinded_path::message::{ForwardNode, MessageContext, OffersContext}; use crate::events::{Event, EventsProvider}; use crate::ln::features::{ChannelFeatures, InitFeatures}; use crate::ln::msgs::{self, DecodeError, OnionMessageHandler}; @@ -174,7 +174,7 @@ impl Drop for TestCustomMessageHandler { impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; - fn handle_custom_message(&self, msg: Self::CustomMessage, _context: Option>, responder: Option) -> ResponseInstruction { + fn handle_custom_message(&self, msg: Self::CustomMessage, context: Option>, responder: Option) -> ResponseInstruction { let expectation = self.get_next_expectation(); assert_eq!(msg, expectation.expect); @@ -190,7 +190,7 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler { match responder { Some(responder) if expectation.include_reply_path => { - responder.respond_with_reply_path(response) + responder.respond_with_reply_path(response, MessageContext::Custom(context.unwrap_or_else(Vec::new))) }, Some(responder) => responder.respond(response), None => ResponseInstruction::NoResponse, @@ -372,7 +372,8 @@ fn one_blinded_hop() { let test_msg = TestCustomMessage::Pong; let secp_ctx = Secp256k1::new(); - let blinded_path = BlindedPath::new_for_message(&[], nodes[1].node_id, &*nodes[1].entropy_source, &secp_ctx).unwrap(); + 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 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); @@ -386,7 +387,8 @@ 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 blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[4].node_id, &*nodes[4].entropy_source, &secp_ctx).unwrap(); + 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 path = OnionMessagePath { intermediate_nodes: vec![nodes[1].node_id, nodes[2].node_id], destination: Destination::BlindedPath(blinded_path), @@ -408,7 +410,8 @@ fn three_blinded_hops() { 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 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 destination = Destination::BlindedPath(blinded_path); nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap(); @@ -430,7 +433,8 @@ 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 reply_path = BlindedPath::new_for_message(&[], nodes[1].node_id, &*nodes[1].entropy_source, &secp_ctx).unwrap(); + 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(); // 4. Create a responder using the reply path for Alice. let responder = Some(Responder::new(reply_path)); @@ -465,7 +469,8 @@ 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 reply_path = BlindedPath::new_for_message(&[], bob.node_id, &*bob.entropy_source, &secp_ctx).unwrap(); + let context = MessageContext::Custom(Vec::new()); + let reply_path = BlindedPath::new_for_message(&[], 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); @@ -501,7 +506,8 @@ 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 reply_path = BlindedPath::new_for_message(&[], bob.node_id, &*bob.entropy_source, &secp_ctx).unwrap(); + let context = MessageContext::Custom(Vec::new()); + let reply_path = BlindedPath::new_for_message(&[], 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. @@ -545,7 +551,8 @@ fn we_are_intro_node() { 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 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 destination = Destination::BlindedPath(blinded_path); nodes[0].messenger.send_onion_message(test_msg.clone(), destination, None).unwrap(); @@ -554,7 +561,8 @@ 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 blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[1].node_id, &*nodes[1].entropy_source, &secp_ctx).unwrap(); + 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 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); @@ -570,7 +578,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 mut blinded_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[2].node_id, &*nodes[2].entropy_source, &secp_ctx).unwrap(); + 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 destination = Destination::BlindedPath(blinded_path); let err = nodes[0].messenger.send_onion_message(test_msg, destination, None).unwrap_err(); @@ -593,7 +602,8 @@ fn reply_path() { 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(); + 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(); 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); @@ -607,13 +617,15 @@ fn reply_path() { 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 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 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 reply_path = BlindedPath::new_for_message(&intermediate_nodes, nodes[0].node_id, &*nodes[0].entropy_source, &secp_ctx).unwrap(); + 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(); nodes[0].messenger.send_onion_message(test_msg, destination, Some(reply_path)).unwrap(); nodes[3].custom_message_handler.expect_message(TestCustomMessage::Ping); @@ -694,8 +706,9 @@ fn requests_peer_connection_for_buffered_messages() { 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 context = MessageContext::Custom(Vec::new()); let blinded_path = BlindedPath::new_for_message( - &intermediate_nodes, nodes[2].node_id, &*nodes[0].entropy_source, &secp_ctx + &intermediate_nodes, nodes[2].node_id, context, &*nodes[0].entropy_source, &secp_ctx ).unwrap(); let destination = Destination::BlindedPath(blinded_path); @@ -732,8 +745,9 @@ fn drops_buffered_messages_waiting_for_peer_connection() { 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 context = MessageContext::Custom(Vec::new()); let blinded_path = BlindedPath::new_for_message( - &intermediate_nodes, nodes[2].node_id, &*nodes[0].entropy_source, &secp_ctx + &intermediate_nodes, nodes[2].node_id, context, &*nodes[0].entropy_source, &secp_ctx ).unwrap(); let destination = Destination::BlindedPath(blinded_path); @@ -782,8 +796,9 @@ fn intercept_offline_peer_oms() { let message = TestCustomMessage::Pong; 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( - &intermediate_nodes, nodes[2].node_id, &*nodes[2].entropy_source, &secp_ctx + &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 f96937fd9..28f1bc792 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -145,7 +145,7 @@ for OnionMessenger where /// # 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::blinded_path::message::{ForwardNode, MessageContext}; /// # use lightning::sign::{EntropySource, KeysManager}; /// # use lightning::ln::peer_handler::IgnoringMessageHandler; /// # use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath, OnionMessenger}; @@ -172,7 +172,7 @@ for OnionMessenger where /// # }) /// # } /// # fn create_blinded_paths( -/// # &self, _recipient: PublicKey, _peers: Vec, _secp_ctx: &Secp256k1 +/// # &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, _secp_ctx: &Secp256k1 /// # ) -> Result, ()> { /// # unreachable!() /// # } @@ -225,7 +225,8 @@ for OnionMessenger where /// 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(); +/// let context = MessageContext::Custom(Vec::new()); +/// let blinded_path = BlindedPath::new_for_message(&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); @@ -371,11 +372,11 @@ impl Responder { /// Creates a [`ResponseInstruction::WithReplyPath`] for a given response. /// /// Use when the recipient needs to send back a reply to us. - pub fn respond_with_reply_path(self, response: T) -> ResponseInstruction { + pub fn respond_with_reply_path(self, response: T, context: MessageContext) -> ResponseInstruction { ResponseInstruction::WithReplyPath(OnionMessageResponse { message: response, reply_path: self.reply_path, - }) + }, context) } } @@ -389,7 +390,7 @@ pub struct OnionMessageResponse { pub enum ResponseInstruction { /// Indicates that a response should be sent including a reply path for /// the recipient to respond back. - WithReplyPath(OnionMessageResponse), + WithReplyPath(OnionMessageResponse, MessageContext), /// Indicates that a response should be sent without including a reply path /// for the recipient to respond back. WithoutReplyPath(OnionMessageResponse), @@ -441,7 +442,7 @@ pub trait MessageRouter { fn create_blinded_paths< T: secp256k1::Signing + secp256k1::Verification >( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()>; /// Creates compact [`BlindedPath`]s to the `recipient` node. The nodes in `peers` are assumed @@ -460,13 +461,14 @@ pub trait MessageRouter { fn create_compact_blinded_paths< T: secp256k1::Signing + secp256k1::Verification >( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, context: MessageContext, + peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { let peers = peers .into_iter() .map(|ForwardNode { node_id, short_channel_id: _ }| node_id) .collect(); - self.create_blinded_paths(recipient, peers, secp_ctx) + self.create_blinded_paths(recipient, context, peers, secp_ctx) } } @@ -501,7 +503,8 @@ where I: ExactSizeIterator, T: secp256k1::Signing + secp256k1::Verification >( - &self, recipient: PublicKey, peers: I, secp_ctx: &Secp256k1, compact_paths: bool + &self, recipient: PublicKey, context: MessageContext, peers: I, + secp_ctx: &Secp256k1, compact_paths: bool ) -> Result, ()> { // Limit the number of blinded paths that are computed. const MAX_PATHS: usize = 3; @@ -540,7 +543,7 @@ where let paths = peer_info.into_iter() .map(|(peer, _, _)| { - BlindedPath::new_for_message(&[peer], recipient, &*self.entropy_source, secp_ctx) + BlindedPath::new_for_message(&[peer], recipient, context.clone(), &*self.entropy_source, secp_ctx) }) .take(MAX_PATHS) .collect::, _>>(); @@ -549,7 +552,7 @@ where Ok(paths) if !paths.is_empty() => Ok(paths), _ => { if is_recipient_announced { - BlindedPath::one_hop_for_message(recipient, &*self.entropy_source, secp_ctx) + BlindedPath::one_hop_for_message(recipient, context, &*self.entropy_source, secp_ctx) .map(|path| vec![path]) } else { Err(()) @@ -608,20 +611,22 @@ where fn create_blinded_paths< T: secp256k1::Signing + secp256k1::Verification >( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, context: MessageContext, + peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { let peers = peers .into_iter() .map(|node_id| ForwardNode { node_id, short_channel_id: None }); - self.create_blinded_paths_from_iter(recipient, peers, secp_ctx, false) + self.create_blinded_paths_from_iter(recipient, context, peers, secp_ctx, false) } fn create_compact_blinded_paths< T: secp256k1::Signing + secp256k1::Verification >( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, context: MessageContext, + peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { - self.create_blinded_paths_from_iter(recipient, peers.into_iter(), secp_ctx, true) + self.create_blinded_paths_from_iter(recipient, context, peers.into_iter(), secp_ctx, true) } } @@ -1165,7 +1170,7 @@ where .map_err(|_| SendError::PathNotFound) } - fn create_blinded_path(&self) -> Result { + fn create_blinded_path(&self, context: MessageContext) -> Result { let recipient = self.node_signer .get_node_id(Recipient::Node) .map_err(|_| SendError::GetNodeIdFailed)?; @@ -1178,7 +1183,7 @@ where .collect::>(); self.message_router - .create_blinded_paths(recipient, peers, secp_ctx) + .create_blinded_paths(recipient, context, peers, secp_ctx) .and_then(|paths| paths.into_iter().next().ok_or(())) .map_err(|_| SendError::PathNotFound) } @@ -1267,15 +1272,15 @@ where pub fn handle_onion_message_response( &self, response: ResponseInstruction ) -> Result, SendError> { - let (response, create_reply_path) = match response { - ResponseInstruction::WithReplyPath(response) => (response, true), - ResponseInstruction::WithoutReplyPath(response) => (response, false), + let (response, context) = match response { + ResponseInstruction::WithReplyPath(response, context) => (response, Some(context)), + ResponseInstruction::WithoutReplyPath(response) => (response, None), ResponseInstruction::NoResponse => return Ok(None), }; let message_type = response.message.msg_type(); - let reply_path = if create_reply_path { - match self.create_blinded_path() { + let reply_path = if let Some(context) = context { + match self.create_blinded_path(context) { Ok(reply_path) => Some(reply_path), Err(err) => { log_trace!( diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 8062f5983..46d79854a 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -12,7 +12,7 @@ use bitcoin::secp256k1::{PublicKey, Secp256k1, self}; use crate::blinded_path::{BlindedHop, BlindedPath, Direction, IntroductionNode}; -use crate::blinded_path::message; +use crate::blinded_path::message::{self, MessageContext}; use crate::blinded_path::payment::{ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs, self}; use crate::ln::{PaymentHash, PaymentPreimage}; use crate::ln::channel_state::ChannelDetails; @@ -193,17 +193,17 @@ 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, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { - self.message_router.create_blinded_paths(recipient, peers, secp_ctx) + self.message_router.create_blinded_paths(recipient, context, peers, secp_ctx) } fn create_compact_blinded_paths< T: secp256k1::Signing + secp256k1::Verification > ( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, context: MessageContext, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { - self.message_router.create_compact_blinded_paths(recipient, peers, secp_ctx) + self.message_router.create_compact_blinded_paths(recipient, context, peers, secp_ctx) } } diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 4c4df2688..f734f7f94 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -7,6 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. +use crate::blinded_path::message::MessageContext; use crate::blinded_path::BlindedPath; use crate::blinded_path::message::ForwardNode; use crate::blinded_path::payment::ReceiveTlvs; @@ -263,17 +264,19 @@ 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, context: MessageContext, + peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { - self.router.create_blinded_paths(recipient, peers, secp_ctx) + self.router.create_blinded_paths(recipient, context, peers, secp_ctx) } fn create_compact_blinded_paths< T: secp256k1::Signing + secp256k1::Verification >( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, context: MessageContext, + peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { - self.router.create_compact_blinded_paths(recipient, peers, secp_ctx) + self.router.create_compact_blinded_paths(recipient, context, peers, secp_ctx) } } @@ -306,15 +309,17 @@ impl<'a> MessageRouter for TestMessageRouter<'a> { } fn create_blinded_paths( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, context: MessageContext, + peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { - self.inner.create_blinded_paths(recipient, peers, secp_ctx) + self.inner.create_blinded_paths(recipient, context, peers, secp_ctx) } fn create_compact_blinded_paths( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, context: MessageContext, + peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { - self.inner.create_compact_blinded_paths(recipient, peers, secp_ctx) + self.inner.create_compact_blinded_paths(recipient, context, peers, secp_ctx) } } -- 2.39.5