From a2f78b2c6407ffda417355b0cd744d85b654d053 Mon Sep 17 00:00:00 2001 From: shaavan Date: Wed, 19 Feb 2025 19:43:06 +0530 Subject: [PATCH 01/10] f: Update BlindedPath creation functions to take recipient_tlvs as input --- fuzz/src/chanmon_consistency.rs | 6 +- fuzz/src/full_stack.rs | 6 +- fuzz/src/onion_message.rs | 4 +- lightning-dns-resolver/src/lib.rs | 10 +- lightning/src/blinded_path/message.rs | 19 +- lightning/src/ln/async_payments_tests.rs | 26 ++- lightning/src/ln/channelmanager.rs | 14 +- .../src/onion_message/functional_tests.rs | 162 ++++++++++++------ lightning/src/onion_message/messenger.rs | 58 ++++--- lightning/src/util/test_utils.rs | 12 +- 10 files changed, 210 insertions(+), 107 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 54c9a7e481b..753f37f6dc9 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -33,7 +33,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hashes::Hash as TraitImport; use bitcoin::WPubkeyHash; -use lightning::blinded_path::message::{BlindedMessagePath, MessageContext}; +use lightning::blinded_path::message::{self, BlindedMessagePath, MessageContext}; use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs}; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; @@ -138,8 +138,8 @@ impl MessageRouter for FuzzRouter { } fn create_blinded_paths( - &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, - _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _recipient_tlvs: message::ReceiveTlvs, + _peers: Vec, _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() } diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 7b9a9ae1d00..cb4a690be91 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -30,7 +30,7 @@ use bitcoin::hashes::Hash as _; use bitcoin::hex::FromHex; use bitcoin::WPubkeyHash; -use lightning::blinded_path::message::{BlindedMessagePath, MessageContext}; +use lightning::blinded_path::message::{self, BlindedMessagePath, MessageContext}; use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs}; use lightning::chain; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; @@ -171,8 +171,8 @@ impl MessageRouter for FuzzRouter { } fn create_blinded_paths( - &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, - _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _recipient_tlvs: message::ReceiveTlvs, + _peers: Vec, _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() } diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 10a667fb594..1b80bdc606d 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -6,7 +6,7 @@ use bitcoin::secp256k1::schnorr; use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1, SecretKey}; use lightning::blinded_path::message::{ - AsyncPaymentsContext, BlindedMessagePath, MessageContext, OffersContext, + AsyncPaymentsContext, BlindedMessagePath, MessageContext, OffersContext, ReceiveTlvs, }; use lightning::blinded_path::EmptyNodeIdLookUp; use lightning::ln::inbound_payment::ExpandedKey; @@ -100,7 +100,7 @@ impl MessageRouter for TestMessageRouter { } fn create_blinded_paths( - &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, + &self, _recipient: PublicKey, _recipient_tlvs: ReceiveTlvs, _peers: Vec, _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() diff --git a/lightning-dns-resolver/src/lib.rs b/lightning-dns-resolver/src/lib.rs index 8f855cb5fb7..baed636a570 100644 --- a/lightning-dns-resolver/src/lib.rs +++ b/lightning-dns-resolver/src/lib.rs @@ -159,7 +159,7 @@ mod test { use bitcoin::secp256k1::{self, PublicKey, Secp256k1}; use bitcoin::Block; - use lightning::blinded_path::message::{BlindedMessagePath, MessageContext}; + use lightning::blinded_path::message::{BlindedMessagePath, MessageContext, ReceiveTlvs}; use lightning::blinded_path::NodeIdLookUp; use lightning::events::{Event, PaymentPurpose}; use lightning::ln::channelmanager::{PaymentId, Retry}; @@ -225,11 +225,13 @@ mod test { } fn create_blinded_paths( - &self, recipient: PublicKey, context: MessageContext, _peers: Vec, + &self, recipient: PublicKey, recipient_tlvs: ReceiveTlvs, _peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { let keys = KeysManager::new(&[0; 32], 42, 43); - Ok(vec![BlindedMessagePath::one_hop(recipient, context, &keys, secp_ctx).unwrap()]) + Ok(vec![ + BlindedMessagePath::one_hop(recipient, recipient_tlvs, &keys, secp_ctx).unwrap() + ]) } } impl Deref for DirectlyConnectedRouter { @@ -330,7 +332,7 @@ mod test { let (msg, context) = payer.resolver.resolve_name(payment_id, name.clone(), &*payer_keys).unwrap(); - let query_context = MessageContext::DNSResolver(context); + let query_context = ReceiveTlvs { context: Some(MessageContext::DNSResolver(context)) }; let reply_path = BlindedMessagePath::one_hop(payer_id, query_context, &*payer_keys, &secp_ctx).unwrap(); payer.pending_messages.lock().unwrap().push(( diff --git a/lightning/src/blinded_path/message.rs b/lightning/src/blinded_path/message.rs index 441a2c2a625..02b3203b72a 100644 --- a/lightning/src/blinded_path/message.rs +++ b/lightning/src/blinded_path/message.rs @@ -55,13 +55,13 @@ impl Readable for BlindedMessagePath { impl BlindedMessagePath { /// Create a one-hop blinded path for a message. pub fn one_hop( - recipient_node_id: PublicKey, context: MessageContext, entropy_source: ES, + recipient_node_id: PublicKey, recipient_tlvs: ReceiveTlvs, entropy_source: ES, secp_ctx: &Secp256k1, ) -> Result where ES::Target: EntropySource, { - Self::new(&[], recipient_node_id, context, entropy_source, secp_ctx) + Self::new(&[], recipient_node_id, recipient_tlvs, entropy_source, secp_ctx) } /// Create a path for an onion message, to be forwarded along `node_pks`. The last node @@ -71,7 +71,7 @@ impl BlindedMessagePath { // TODO: make all payloads the same size with padding + add dummy hops pub fn new( intermediate_nodes: &[MessageForwardNode], recipient_node_id: PublicKey, - context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1, + recipient_tlvs: ReceiveTlvs, entropy_source: ES, secp_ctx: &Secp256k1, ) -> Result where ES::Target: EntropySource, @@ -90,7 +90,7 @@ impl BlindedMessagePath { secp_ctx, intermediate_nodes, recipient_node_id, - context, + recipient_tlvs, &blinding_secret, ) .map_err(|_| ())?, @@ -251,8 +251,11 @@ pub(crate) struct ForwardTlvs { pub(crate) next_blinding_override: Option, } -/// Similar to [`ForwardTlvs`], but these TLVs are for the final node. -pub(crate) struct ReceiveTlvs { +/// TLVs to encode in the final onion message packet's hop data. These TLVs are specific to the +/// recipient node and provide information necessary for final processing of the message. +/// When provided in a blinded route, they are encoded into [`BlindedHop::encrypted_payload`]. +#[derive(Clone)] +pub struct ReceiveTlvs { /// If `context` is `Some`, it is used to identify the blinded path that this onion message is /// sending to. This is useful for receivers to check that said blinded path is being used in /// the right context. @@ -498,7 +501,7 @@ impl_writeable_tlv_based!(DNSResolverContext, { /// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`. pub(super) fn blinded_hops( secp_ctx: &Secp256k1, intermediate_nodes: &[MessageForwardNode], - recipient_node_id: PublicKey, context: MessageContext, session_priv: &SecretKey, + recipient_node_id: PublicKey, recipient_tlvs: ReceiveTlvs, session_priv: &SecretKey, ) -> Result, secp256k1::Error> { let pks = intermediate_nodes .iter() @@ -515,7 +518,7 @@ pub(super) fn blinded_hops( .map(|next_hop| { ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None }) }) - .chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { context: Some(context) }))); + .chain(core::iter::once(ControlTlvs::Receive(recipient_tlvs))); let path = pks.zip(tlvs); diff --git a/lightning/src/ln/async_payments_tests.rs b/lightning/src/ln/async_payments_tests.rs index 8d18938272c..ffade89eacc 100644 --- a/lightning/src/ln/async_payments_tests.rs +++ b/lightning/src/ln/async_payments_tests.rs @@ -7,7 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::blinded_path::message::{MessageContext, OffersContext}; +use crate::blinded_path::message::{MessageContext, OffersContext, ReceiveTlvs}; use crate::blinded_path::payment::PaymentContext; use crate::blinded_path::payment::{AsyncBolt12OfferContext, BlindedPaymentTlvs}; use crate::chain::channelmonitor::{HTLC_FAIL_BACK_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS}; @@ -106,11 +106,17 @@ fn create_static_invoice( always_online_counterparty: &Node, recipient: &Node, relative_expiry: Option, secp_ctx: &Secp256k1, ) -> (Offer, StaticInvoice) { + let recipient_tlvs = ReceiveTlvs { + context: Some(MessageContext::Offers(OffersContext::InvoiceRequest { + nonce: Nonce([42; 16]), + })), + }; + let blinded_paths_to_always_online_node = always_online_counterparty .message_router .create_blinded_paths( always_online_counterparty.node.get_our_node_id(), - MessageContext::Offers(OffersContext::InvoiceRequest { nonce: Nonce([42; 16]) }), + recipient_tlvs, Vec::new(), &secp_ctx, ) @@ -212,11 +218,17 @@ fn static_invoice_unknown_required_features() { create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0); create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0); + let recipient_tlvs = ReceiveTlvs { + context: Some(MessageContext::Offers(OffersContext::InvoiceRequest { + nonce: Nonce([42; 16]), + })), + }; + let blinded_paths_to_always_online_node = nodes[1] .message_router .create_blinded_paths( nodes[1].node.get_our_node_id(), - MessageContext::Offers(OffersContext::InvoiceRequest { nonce: Nonce([42; 16]) }), + recipient_tlvs, Vec::new(), &secp_ctx, ) @@ -813,11 +825,17 @@ fn invalid_async_receive_with_retry( create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0); create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0); + let recipient_tlvs = ReceiveTlvs { + context: Some(MessageContext::Offers(OffersContext::InvoiceRequest { + nonce: Nonce([42; 16]), + })), + }; + let blinded_paths_to_always_online_node = nodes[1] .message_router .create_blinded_paths( nodes[1].node.get_our_node_id(), - MessageContext::Offers(OffersContext::InvoiceRequest { nonce: Nonce([42; 16]) }), + recipient_tlvs, Vec::new(), &secp_ctx, ) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 5342cc649d3..ea64dde3b0b 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -33,7 +33,7 @@ use bitcoin::secp256k1::Secp256k1; use bitcoin::{secp256k1, Sequence}; use crate::events::FundingInfo; -use crate::blinded_path::message::{AsyncPaymentsContext, MessageContext, OffersContext}; +use crate::blinded_path::message::{self, AsyncPaymentsContext, MessageContext, OffersContext}; use crate::blinded_path::NodeIdLookUp; use crate::blinded_path::message::{BlindedMessagePath, MessageForwardNode}; use crate::blinded_path::payment::{AsyncBolt12OfferContext, BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, UnauthenticatedReceiveTlvs}; @@ -10598,8 +10598,12 @@ where .map(|(node_id, _)| *node_id) .collect::>(); + let recipient_tlvs = message::ReceiveTlvs { + context: Some(context) + }; + self.message_router - .create_blinded_paths(recipient, context, peers, secp_ctx) + .create_blinded_paths(recipient, recipient_tlvs, peers, secp_ctx) .and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(())) } @@ -10626,8 +10630,12 @@ where }) .collect::>(); + let recipient_tlvs = message::ReceiveTlvs { + context: Some(MessageContext::Offers(context)) + }; + self.message_router - .create_compact_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx) + .create_compact_blinded_paths(recipient, recipient_tlvs, peers, secp_ctx) .and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(())) } diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 239625de9e4..f919d06fdce 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -21,7 +21,7 @@ use super::offers::{OffersMessage, OffersMessageHandler}; use super::packet::{OnionMessageContents, Packet}; use crate::blinded_path::message::{ AsyncPaymentsContext, BlindedMessagePath, DNSResolverContext, MessageContext, - MessageForwardNode, OffersContext, + MessageForwardNode, OffersContext, ReceiveTlvs, }; use crate::blinded_path::EmptyNodeIdLookUp; use crate::events::{Event, EventsProvider}; @@ -406,10 +406,11 @@ fn one_blinded_hop() { let test_msg = TestCustomMessage::Pong; let secp_ctx = Secp256k1::new(); - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[1].entropy_source; + let blinded_path = - BlindedMessagePath::new(&[], nodes[1].node_id, context, entropy, &secp_ctx).unwrap(); + BlindedMessagePath::new(&[], nodes[1].node_id, recipient_tlvs, entropy, &secp_ctx).unwrap(); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap(); @@ -425,11 +426,16 @@ fn two_unblinded_two_blinded() { let secp_ctx = Secp256k1::new(); let intermediate_nodes = [MessageForwardNode { node_id: nodes[3].node_id, short_channel_id: None }]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[4].entropy_source; - let blinded_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[4].node_id, context, entropy, &secp_ctx) - .unwrap(); + let blinded_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[4].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); let path = OnionMessagePath { intermediate_nodes: vec![nodes[1].node_id, nodes[2].node_id], destination: Destination::BlindedPath(blinded_path), @@ -451,11 +457,16 @@ fn three_blinded_hops() { MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, MessageForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, ]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[3].entropy_source; - let blinded_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[3].node_id, context, entropy, &secp_ctx) - .unwrap(); + let blinded_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[3].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -478,10 +489,10 @@ 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 recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[1].entropy_source; let reply_path = - BlindedMessagePath::new(&[], nodes[1].node_id, context, entropy, &secp_ctx).unwrap(); + BlindedMessagePath::new(&[], nodes[1].node_id, recipient_tlvs, entropy, &secp_ctx).unwrap(); // 4. Create a responder using the reply path for Alice. let responder = Some(Responder::new(reply_path)); @@ -518,9 +529,9 @@ 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 recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let reply_path = - BlindedMessagePath::new(&[], bob.node_id, context, &*bob.entropy_source, &secp_ctx) + BlindedMessagePath::new(&[], bob.node_id, recipient_tlvs, &*bob.entropy_source, &secp_ctx) .unwrap(); // Alice asynchronously responds to Bob, expecting a response back from him. @@ -559,9 +570,9 @@ 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 recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let reply_path = - BlindedMessagePath::new(&[], bob.node_id, context, &*bob.entropy_source, &secp_ctx) + BlindedMessagePath::new(&[], bob.node_id, recipient_tlvs, &*bob.entropy_source, &secp_ctx) .unwrap(); // Alice tries to asynchronously respond to Bob, but fails because the nodes are unannounced and @@ -608,11 +619,16 @@ fn we_are_intro_node() { MessageForwardNode { node_id: nodes[0].node_id, short_channel_id: None }, MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, ]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[2].entropy_source; - let blinded_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, entropy, &secp_ctx) - .unwrap(); + let blinded_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[2].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -623,11 +639,16 @@ fn we_are_intro_node() { // Try with a two-hop blinded path where we are the introduction node. let intermediate_nodes = [MessageForwardNode { node_id: nodes[0].node_id, short_channel_id: None }]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[1].entropy_source; - let blinded_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[1].node_id, context, entropy, &secp_ctx) - .unwrap(); + let blinded_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[1].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -646,11 +667,16 @@ fn invalid_blinded_path_error() { let secp_ctx = Secp256k1::new(); let intermediate_nodes = [MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[2].entropy_source; - let mut blinded_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, entropy, &secp_ctx) - .unwrap(); + let mut blinded_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[2].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); blinded_path.clear_blinded_hops(); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -675,11 +701,16 @@ fn reply_path() { MessageForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, ]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[0].entropy_source; - let reply_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[0].node_id, context, entropy, &secp_ctx) - .unwrap(); + let reply_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[0].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); nodes[0] .messenger .send_onion_message_using_path(path, test_msg.clone(), Some(reply_path)) @@ -696,21 +727,31 @@ fn reply_path() { MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, MessageForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, ]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[3].entropy_source; - let blinded_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[3].node_id, context, entropy, &secp_ctx) - .unwrap(); + let blinded_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[3].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); let destination = Destination::BlindedPath(blinded_path); let intermediate_nodes = [ MessageForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, ]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[0].entropy_source; - let reply_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[0].node_id, context, entropy, &secp_ctx) - .unwrap(); + let reply_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[0].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); let instructions = MessageSendInstructions::WithSpecifiedReplyPath { destination, reply_path }; nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap(); @@ -804,11 +845,16 @@ fn requests_peer_connection_for_buffered_messages() { let intermediate_nodes = [MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[0].entropy_source; - let blinded_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, entropy, &secp_ctx) - .unwrap(); + let blinded_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[2].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -846,11 +892,16 @@ fn drops_buffered_messages_waiting_for_peer_connection() { let intermediate_nodes = [MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[0].entropy_source; - let blinded_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, entropy, &secp_ctx) - .unwrap(); + let blinded_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[2].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; @@ -904,11 +955,16 @@ fn intercept_offline_peer_oms() { let secp_ctx = Secp256k1::new(); let intermediate_nodes = [MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; - let context = MessageContext::Custom(Vec::new()); + let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; let entropy = &*nodes[2].entropy_source; - let blinded_path = - BlindedMessagePath::new(&intermediate_nodes, nodes[2].node_id, context, entropy, &secp_ctx) - .unwrap(); + let blinded_path = BlindedMessagePath::new( + &intermediate_nodes, + nodes[2].node_id, + recipient_tlvs, + entropy, + &secp_ctx, + ) + .unwrap(); let destination = Destination::BlindedPath(blinded_path); let instructions = MessageSendInstructions::WithoutReplyPath { destination }; diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 012b7978053..3c85ba6d880 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -186,7 +186,7 @@ where /// # use bitcoin::hex::FromHex; /// # use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey, self}; /// # use lightning::blinded_path::EmptyNodeIdLookUp; -/// # use lightning::blinded_path::message::{BlindedMessagePath, MessageForwardNode, MessageContext}; +/// # use lightning::blinded_path::message::{BlindedMessagePath, MessageForwardNode, MessageContext, ReceiveTlvs}; /// # use lightning::sign::{EntropySource, KeysManager}; /// # use lightning::ln::peer_handler::IgnoringMessageHandler; /// # use lightning::onion_message::messenger::{Destination, MessageRouter, MessageSendInstructions, OnionMessagePath, OnionMessenger}; @@ -213,7 +213,7 @@ where /// # }) /// # } /// # fn create_blinded_paths( -/// # &self, _recipient: PublicKey, _context: MessageContext, _peers: Vec, _secp_ctx: &Secp256k1 +/// # &self, _recipient: PublicKey, _recipient_tlvs: ReceiveTlvs, _peers: Vec, _secp_ctx: &Secp256k1 /// # ) -> Result, ()> { /// # unreachable!() /// # } @@ -268,8 +268,10 @@ where /// MessageForwardNode { node_id: hop_node_id3, short_channel_id: None }, /// MessageForwardNode { node_id: hop_node_id4, short_channel_id: None }, /// ]; -/// let context = MessageContext::Custom(Vec::new()); -/// let blinded_path = BlindedMessagePath::new(&hops, your_node_id, context, &keys_manager, &secp_ctx).unwrap(); +/// let recipient_tlvs = ReceiveTlvs { +/// context: Some(MessageContext::Custom(Vec::new())), +/// }; +/// let blinded_path = BlindedMessagePath::new(&hops, your_node_id, recipient_tlvs, &keys_manager, &secp_ctx).unwrap(); /// /// // Send a custom onion message to a blinded path. /// let destination = Destination::BlindedPath(blinded_path); @@ -491,7 +493,7 @@ pub trait MessageRouter { /// Creates [`BlindedMessagePath`]s to the `recipient` node. The nodes in `peers` are assumed to /// be direct peers with the `recipient`. fn create_blinded_paths( - &self, recipient: PublicKey, context: MessageContext, peers: Vec, + &self, recipient: PublicKey, recipient_tlvs: ReceiveTlvs, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()>; @@ -509,14 +511,14 @@ pub trait MessageRouter { /// The provided implementation simply delegates to [`MessageRouter::create_blinded_paths`], /// ignoring the short channel ids. fn create_compact_blinded_paths( - &self, recipient: PublicKey, context: MessageContext, peers: Vec, + &self, recipient: PublicKey, recipient_tlvs: ReceiveTlvs, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { let peers = peers .into_iter() .map(|MessageForwardNode { node_id, short_channel_id: _ }| node_id) .collect(); - self.create_blinded_paths(recipient, context, peers, secp_ctx) + self.create_blinded_paths(recipient, recipient_tlvs, peers, secp_ctx) } } @@ -551,7 +553,7 @@ where I: ExactSizeIterator, T: secp256k1::Signing + secp256k1::Verification, >( - network_graph: &G, recipient: PublicKey, context: MessageContext, peers: I, + network_graph: &G, recipient: PublicKey, recipient_tlvs: ReceiveTlvs, peers: I, entropy_source: &ES, secp_ctx: &Secp256k1, compact_paths: bool, ) -> Result, ()> { // Limit the number of blinded paths that are computed. @@ -591,7 +593,13 @@ where let paths = peer_info .into_iter() .map(|(peer, _, _)| { - BlindedMessagePath::new(&[peer], recipient, context.clone(), entropy, secp_ctx) + BlindedMessagePath::new( + &[peer], + recipient, + recipient_tlvs.clone(), + entropy, + secp_ctx, + ) }) .take(MAX_PATHS) .collect::, _>>(); @@ -600,8 +608,14 @@ where Ok(paths) if !paths.is_empty() => Ok(paths), _ => { if is_recipient_announced { - BlindedMessagePath::new(&[], recipient, context, &**entropy_source, secp_ctx) - .map(|path| vec![path]) + BlindedMessagePath::new( + &[], + recipient, + recipient_tlvs, + &**entropy_source, + secp_ctx, + ) + .map(|path| vec![path]) } else { Err(()) } @@ -659,15 +673,15 @@ where } pub(crate) fn create_blinded_paths( - network_graph: &G, recipient: PublicKey, context: MessageContext, peers: Vec, - entropy_source: &ES, secp_ctx: &Secp256k1, + network_graph: &G, recipient: PublicKey, recipient_tlvs: ReceiveTlvs, + peers: Vec, entropy_source: &ES, secp_ctx: &Secp256k1, ) -> Result, ()> { let peers = peers.into_iter().map(|node_id| MessageForwardNode { node_id, short_channel_id: None }); Self::create_blinded_paths_from_iter( network_graph, recipient, - context, + recipient_tlvs, peers.into_iter(), entropy_source, secp_ctx, @@ -676,13 +690,13 @@ where } pub(crate) fn create_compact_blinded_paths( - network_graph: &G, recipient: PublicKey, context: MessageContext, + network_graph: &G, recipient: PublicKey, recipient_tlvs: ReceiveTlvs, peers: Vec, entropy_source: &ES, secp_ctx: &Secp256k1, ) -> Result, ()> { Self::create_blinded_paths_from_iter( network_graph, recipient, - context, + recipient_tlvs, peers.into_iter(), entropy_source, secp_ctx, @@ -704,13 +718,13 @@ where } fn create_blinded_paths( - &self, recipient: PublicKey, context: MessageContext, peers: Vec, + &self, recipient: PublicKey, recipient_tlvs: ReceiveTlvs, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { Self::create_blinded_paths( &self.network_graph, recipient, - context, + recipient_tlvs, peers, &self.entropy_source, secp_ctx, @@ -718,13 +732,13 @@ where } fn create_compact_blinded_paths( - &self, recipient: PublicKey, context: MessageContext, peers: Vec, + &self, recipient: PublicKey, recipient_tlvs: ReceiveTlvs, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { Self::create_compact_blinded_paths( &self.network_graph, recipient, - context, + recipient_tlvs, peers, &self.entropy_source, secp_ctx, @@ -1404,8 +1418,10 @@ where .collect::>() }; + let recipient_tlvs = ReceiveTlvs { context: Some(context) }; + self.message_router - .create_blinded_paths(recipient, context, peers, secp_ctx) + .create_blinded_paths(recipient, recipient_tlvs, peers, secp_ctx) .and_then(|paths| paths.into_iter().next().ok_or(())) .map_err(|_| SendError::PathNotFound) } diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 9d02452010d..6debfb273cf 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -7,7 +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::message; use crate::blinded_path::message::{BlindedMessagePath, MessageForwardNode}; use crate::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs}; use crate::chain; @@ -331,17 +331,17 @@ impl<'a> MessageRouter for TestMessageRouter<'a> { } fn create_blinded_paths( - &self, recipient: PublicKey, context: MessageContext, peers: Vec, + &self, recipient: PublicKey, recipient_tlvs: message::ReceiveTlvs, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { - self.inner.create_blinded_paths(recipient, context, peers, secp_ctx) + self.inner.create_blinded_paths(recipient, recipient_tlvs, peers, secp_ctx) } fn create_compact_blinded_paths( - &self, recipient: PublicKey, context: MessageContext, peers: Vec, - secp_ctx: &Secp256k1, + &self, recipient: PublicKey, recipient_tlvs: message::ReceiveTlvs, + peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { - self.inner.create_compact_blinded_paths(recipient, context, peers, secp_ctx) + self.inner.create_compact_blinded_paths(recipient, recipient_tlvs, peers, secp_ctx) } } From f5da27cce622a22a6fca43a7c0615b627bea08c1 Mon Sep 17 00:00:00 2001 From: shaavan Date: Mon, 13 Jan 2025 20:58:57 +0530 Subject: [PATCH 02/10] Introduce Custom Data in ReceiveTlvs. This commit introduce the ability to add custom data in the receive tlvs of blinded path they create, which the intend to receive back when the blinded path is used. This can be used for custom analysis, and information receival. This commit, omits using the custom data in the ChannelManager's implementation of handle_message. This will be handled in a follow-up. --- fuzz/src/onion_message.rs | 2 +- lightning-dns-resolver/src/lib.rs | 3 +- lightning/src/blinded_path/message.rs | 14 ++++++ lightning/src/ln/async_payments_tests.rs | 3 ++ lightning/src/ln/channelmanager.rs | 9 ++-- lightning/src/ln/offers_tests.rs | 10 ++-- lightning/src/ln/peer_handler.rs | 2 +- .../src/onion_message/functional_tests.rs | 47 ++++++++++++------- lightning/src/onion_message/messenger.rs | 37 ++++++++++----- lightning/src/onion_message/offers.rs | 3 +- lightning/src/onion_message/packet.rs | 3 +- 11 files changed, 92 insertions(+), 41 deletions(-) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 1b80bdc606d..f285d1124bc 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -112,7 +112,7 @@ struct TestOffersMessageHandler {} impl OffersMessageHandler for TestOffersMessageHandler { fn handle_message( &self, _message: OffersMessage, _context: Option, - _responder: Option, + _custom_data: Option>, _responder: Option, ) -> Option<(OffersMessage, ResponseInstruction)> { None } diff --git a/lightning-dns-resolver/src/lib.rs b/lightning-dns-resolver/src/lib.rs index baed636a570..d9d51c4bf1c 100644 --- a/lightning-dns-resolver/src/lib.rs +++ b/lightning-dns-resolver/src/lib.rs @@ -332,7 +332,8 @@ mod test { let (msg, context) = payer.resolver.resolve_name(payment_id, name.clone(), &*payer_keys).unwrap(); - let query_context = ReceiveTlvs { context: Some(MessageContext::DNSResolver(context)) }; + let query_context = + ReceiveTlvs { context: Some(MessageContext::DNSResolver(context)), custom_data: None }; let reply_path = BlindedMessagePath::one_hop(payer_id, query_context, &*payer_keys, &secp_ctx).unwrap(); payer.pending_messages.lock().unwrap().push(( diff --git a/lightning/src/blinded_path/message.rs b/lightning/src/blinded_path/message.rs index 02b3203b72a..993aca61bde 100644 --- a/lightning/src/blinded_path/message.rs +++ b/lightning/src/blinded_path/message.rs @@ -260,6 +260,19 @@ pub struct ReceiveTlvs { /// sending to. This is useful for receivers to check that said blinded path is being used in /// the right context. pub context: Option, + + /// Custom data set by the user. If `custom_data` is `Some`, it will be provided to the message + /// recipient when the blinded path is used. + /// + /// This field allows encoding custom data intended to be provided back when the blinded path is used. + /// + /// ## Note on Forward Compatibility: + /// Users can encode any kind of data into the `Vec` bytes here. However, they should ensure + /// that the data is structured in a forward-compatible manner. This is especially important as + /// `ReceiveTlvs` created in one version of the software may still appear in messages received + /// shortly after a software upgrade. Proper forward compatibility helps prevent data loss or + /// misinterpretation in future versions. + pub custom_data: Option>, } impl Writeable for ForwardTlvs { @@ -283,6 +296,7 @@ impl Writeable for ReceiveTlvs { // TODO: write padding encode_tlv_stream!(writer, { (65537, self.context, option), + (65539, self.custom_data, option) }); Ok(()) } diff --git a/lightning/src/ln/async_payments_tests.rs b/lightning/src/ln/async_payments_tests.rs index ffade89eacc..5ae5bcb02cd 100644 --- a/lightning/src/ln/async_payments_tests.rs +++ b/lightning/src/ln/async_payments_tests.rs @@ -110,6 +110,7 @@ fn create_static_invoice( context: Some(MessageContext::Offers(OffersContext::InvoiceRequest { nonce: Nonce([42; 16]), })), + custom_data: None, }; let blinded_paths_to_always_online_node = always_online_counterparty @@ -222,6 +223,7 @@ fn static_invoice_unknown_required_features() { context: Some(MessageContext::Offers(OffersContext::InvoiceRequest { nonce: Nonce([42; 16]), })), + custom_data: None, }; let blinded_paths_to_always_online_node = nodes[1] @@ -829,6 +831,7 @@ fn invalid_async_receive_with_retry( context: Some(MessageContext::Offers(OffersContext::InvoiceRequest { nonce: Nonce([42; 16]), })), + custom_data: None, }; let blinded_paths_to_always_online_node = nodes[1] diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index ea64dde3b0b..799affeac7b 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -10599,7 +10599,8 @@ where .collect::>(); let recipient_tlvs = message::ReceiveTlvs { - context: Some(context) + context: Some(context), + custom_data: None, }; self.message_router @@ -10631,7 +10632,8 @@ where .collect::>(); let recipient_tlvs = message::ReceiveTlvs { - context: Some(MessageContext::Offers(context)) + context: Some(MessageContext::Offers(context)), + custom_data: None, }; self.message_router @@ -12150,7 +12152,8 @@ where L::Target: Logger, { fn handle_message( - &self, message: OffersMessage, context: Option, responder: Option, + // todo: Allow user to analyse `custom_data`. + &self, message: OffersMessage, context: Option, _custom_data: Option>, responder: Option, ) -> Option<(OffersMessage, ResponseInstruction)> { let secp_ctx = &self.secp_ctx; let expanded_key = &self.inbound_payment_key; diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index 803441f09fe..dd6a18f186e 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -193,8 +193,8 @@ fn claim_bolt12_payment<'a, 'b, 'c>( fn extract_offer_nonce<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) -> Nonce { match node.onion_messenger.peel_onion_message(message) { - Ok(PeeledOnion::Receive(_, Some(MessageContext::Offers(OffersContext::InvoiceRequest { nonce })), _)) => nonce, - Ok(PeeledOnion::Receive(_, context, _)) => panic!("Unexpected onion message context: {:?}", context), + Ok(PeeledOnion::Receive(_, Some(MessageContext::Offers(OffersContext::InvoiceRequest { nonce })), _, _)) => nonce, + Ok(PeeledOnion::Receive(_, context, _, _)) => panic!("Unexpected onion message context: {:?}", context), Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"), Err(e) => panic!("Failed to process onion message {:?}", e), } @@ -204,7 +204,7 @@ pub(super) fn extract_invoice_request<'a, 'b, 'c>( node: &Node<'a, 'b, 'c>, message: &OnionMessage ) -> (InvoiceRequest, BlindedMessagePath) { match node.onion_messenger.peel_onion_message(message) { - Ok(PeeledOnion::Receive(message, _, reply_path)) => match message { + Ok(PeeledOnion::Receive(message, _, _, reply_path)) => match message { ParsedOnionMessageContents::Offers(offers_message) => match offers_message { OffersMessage::InvoiceRequest(invoice_request) => (invoice_request, reply_path.unwrap()), OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), @@ -221,7 +221,7 @@ pub(super) fn extract_invoice_request<'a, 'b, 'c>( fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) -> (Bolt12Invoice, BlindedMessagePath) { match node.onion_messenger.peel_onion_message(message) { - Ok(PeeledOnion::Receive(message, _, reply_path)) => match message { + Ok(PeeledOnion::Receive(message, _, _, reply_path)) => match message { ParsedOnionMessageContents::Offers(offers_message) => match offers_message { OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request), OffersMessage::Invoice(invoice) => (invoice, reply_path.unwrap()), @@ -240,7 +240,7 @@ fn extract_invoice_error<'a, 'b, 'c>( node: &Node<'a, 'b, 'c>, message: &OnionMessage ) -> InvoiceError { match node.onion_messenger.peel_onion_message(message) { - Ok(PeeledOnion::Receive(message, _, _)) => match message { + Ok(PeeledOnion::Receive(message, _, _, _)) => match message { ParsedOnionMessageContents::Offers(offers_message) => match offers_message { OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request), OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice), diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index aca1afbff39..e7d0b9fb636 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -146,7 +146,7 @@ impl OnionMessageHandler for IgnoringMessageHandler { } impl OffersMessageHandler for IgnoringMessageHandler { - fn handle_message(&self, _message: OffersMessage, _context: Option, _responder: Option) -> Option<(OffersMessage, ResponseInstruction)> { + fn handle_message(&self, _message: OffersMessage, _context: Option, _custom_data: Option>, _responder: Option) -> Option<(OffersMessage, ResponseInstruction)> { None } } diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index f919d06fdce..e5afa737400 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -81,7 +81,7 @@ struct TestOffersMessageHandler {} impl OffersMessageHandler for TestOffersMessageHandler { fn handle_message( &self, _message: OffersMessage, _context: Option, - _responder: Option, + _custom_data: Option>, _responder: Option, ) -> Option<(OffersMessage, ResponseInstruction)> { None } @@ -406,7 +406,8 @@ fn one_blinded_hop() { let test_msg = TestCustomMessage::Pong; let secp_ctx = Secp256k1::new(); - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[1].entropy_source; let blinded_path = @@ -426,7 +427,8 @@ fn two_unblinded_two_blinded() { let secp_ctx = Secp256k1::new(); let intermediate_nodes = [MessageForwardNode { node_id: nodes[3].node_id, short_channel_id: None }]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[4].entropy_source; let blinded_path = BlindedMessagePath::new( &intermediate_nodes, @@ -457,7 +459,8 @@ fn three_blinded_hops() { MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, MessageForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, ]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[3].entropy_source; let blinded_path = BlindedMessagePath::new( &intermediate_nodes, @@ -489,7 +492,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 recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[1].entropy_source; let reply_path = BlindedMessagePath::new(&[], nodes[1].node_id, recipient_tlvs, entropy, &secp_ctx).unwrap(); @@ -529,7 +533,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 recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let reply_path = BlindedMessagePath::new(&[], bob.node_id, recipient_tlvs, &*bob.entropy_source, &secp_ctx) .unwrap(); @@ -570,7 +575,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 recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let reply_path = BlindedMessagePath::new(&[], bob.node_id, recipient_tlvs, &*bob.entropy_source, &secp_ctx) .unwrap(); @@ -619,7 +625,8 @@ fn we_are_intro_node() { MessageForwardNode { node_id: nodes[0].node_id, short_channel_id: None }, MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, ]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[2].entropy_source; let blinded_path = BlindedMessagePath::new( &intermediate_nodes, @@ -639,7 +646,8 @@ fn we_are_intro_node() { // Try with a two-hop blinded path where we are the introduction node. let intermediate_nodes = [MessageForwardNode { node_id: nodes[0].node_id, short_channel_id: None }]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[1].entropy_source; let blinded_path = BlindedMessagePath::new( &intermediate_nodes, @@ -667,7 +675,8 @@ fn invalid_blinded_path_error() { let secp_ctx = Secp256k1::new(); let intermediate_nodes = [MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[2].entropy_source; let mut blinded_path = BlindedMessagePath::new( &intermediate_nodes, @@ -701,7 +710,8 @@ fn reply_path() { MessageForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, ]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[0].entropy_source; let reply_path = BlindedMessagePath::new( &intermediate_nodes, @@ -727,7 +737,8 @@ fn reply_path() { MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, MessageForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, ]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[3].entropy_source; let blinded_path = BlindedMessagePath::new( &intermediate_nodes, @@ -742,7 +753,8 @@ fn reply_path() { MessageForwardNode { node_id: nodes[2].node_id, short_channel_id: None }, MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }, ]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[0].entropy_source; let reply_path = BlindedMessagePath::new( &intermediate_nodes, @@ -845,7 +857,8 @@ fn requests_peer_connection_for_buffered_messages() { let intermediate_nodes = [MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[0].entropy_source; let blinded_path = BlindedMessagePath::new( &intermediate_nodes, @@ -892,7 +905,8 @@ fn drops_buffered_messages_waiting_for_peer_connection() { let intermediate_nodes = [MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[0].entropy_source; let blinded_path = BlindedMessagePath::new( &intermediate_nodes, @@ -955,7 +969,8 @@ fn intercept_offline_peer_oms() { let secp_ctx = Secp256k1::new(); let intermediate_nodes = [MessageForwardNode { node_id: nodes[1].node_id, short_channel_id: None }]; - let recipient_tlvs = ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())) }; + let recipient_tlvs = + ReceiveTlvs { context: Some(MessageContext::Custom(Vec::new())), custom_data: None }; let entropy = &*nodes[2].entropy_source; let blinded_path = BlindedMessagePath::new( &intermediate_nodes, diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 3c85ba6d880..2793e807b39 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -270,6 +270,7 @@ where /// ]; /// let recipient_tlvs = ReceiveTlvs { /// context: Some(MessageContext::Custom(Vec::new())), +/// custom_data: None, /// }; /// let blinded_path = BlindedMessagePath::new(&hops, your_node_id, recipient_tlvs, &keys_manager, &secp_ctx).unwrap(); /// @@ -910,7 +911,12 @@ 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>, + Option, + ), } /// Creates an [`OnionMessage`] with the given `contents` for sending to the destination of @@ -1081,25 +1087,25 @@ where Ok(( Payload::Receive { message, - control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { context }), + control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { context, custom_data }), reply_path, }, None, )) => match (&message, &context) { - (_, None) => Ok(PeeledOnion::Receive(message, None, reply_path)), + (_, None) => Ok(PeeledOnion::Receive(message, None, custom_data, reply_path)), (ParsedOnionMessageContents::Offers(_), Some(MessageContext::Offers(_))) => { - Ok(PeeledOnion::Receive(message, context, reply_path)) + Ok(PeeledOnion::Receive(message, context, custom_data, reply_path)) }, #[cfg(async_payments)] ( ParsedOnionMessageContents::AsyncPayments(_), Some(MessageContext::AsyncPayments(_)), - ) => Ok(PeeledOnion::Receive(message, context, reply_path)), + ) => Ok(PeeledOnion::Receive(message, context, custom_data, reply_path)), (ParsedOnionMessageContents::Custom(_), Some(MessageContext::Custom(_))) => { - Ok(PeeledOnion::Receive(message, context, reply_path)) + Ok(PeeledOnion::Receive(message, context, custom_data, reply_path)) }, (ParsedOnionMessageContents::DNSResolver(_), Some(MessageContext::DNSResolver(_))) => { - Ok(PeeledOnion::Receive(message, context, reply_path)) + Ok(PeeledOnion::Receive(message, context, custom_data, reply_path)) }, _ => { log_trace!( @@ -1418,7 +1424,7 @@ where .collect::>() }; - let recipient_tlvs = ReceiveTlvs { context: Some(context) }; + let recipient_tlvs = ReceiveTlvs { context: Some(context), custom_data: None }; self.message_router .create_blinded_paths(recipient, recipient_tlvs, peers, secp_ctx) @@ -1837,7 +1843,7 @@ where fn handle_onion_message(&self, peer_node_id: PublicKey, msg: &OnionMessage) { let logger = WithContext::from(&self.logger, Some(peer_node_id), None, None); match self.peel_onion_message(msg) { - Ok(PeeledOnion::Receive(message, context, reply_path)) => { + Ok(PeeledOnion::Receive(message, context, custom_data, reply_path)) => { log_trace!( logger, "Received an onion message with {} reply_path: {:?}", @@ -1856,8 +1862,12 @@ where return; }, }; - let response_instructions = - self.offers_handler.handle_message(msg, context, responder); + let response_instructions = self.offers_handler.handle_message( + msg, + context, + custom_data, + responder, + ); if let Some((msg, instructions)) = response_instructions { let _ = self.handle_onion_message_response(msg, instructions); } @@ -2286,7 +2296,10 @@ fn packet_payloads_and_keys< } else { payloads.push(( Payload::Receive { - control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { context: None }), + control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { + context: None, + custom_data: None, + }), reply_path: reply_path.take(), message, }, diff --git a/lightning/src/onion_message/offers.rs b/lightning/src/onion_message/offers.rs index 1d0f9c7b664..d4ffa9dfec3 100644 --- a/lightning/src/onion_message/offers.rs +++ b/lightning/src/onion_message/offers.rs @@ -44,7 +44,8 @@ pub trait OffersMessageHandler { /// /// [`OnionMessenger`]: crate::onion_message::messenger::OnionMessenger fn handle_message( - &self, message: OffersMessage, context: Option, responder: Option, + &self, message: OffersMessage, context: Option, + custom_data: Option>, responder: Option, ) -> Option<(OffersMessage, ResponseInstruction)>; /// Releases any [`OffersMessage`]s that need to be sent. diff --git a/lightning/src/onion_message/packet.rs b/lightning/src/onion_message/packet.rs index 961ae71a2d9..9e9a811293b 100644 --- a/lightning/src/onion_message/packet.rs +++ b/lightning/src/onion_message/packet.rs @@ -341,6 +341,7 @@ impl Readable for ControlTlvs { (4, next_node_id, option), (8, next_blinding_override, option), (65537, context, option), + (65539, custom_data, option) }); let _padding: Option = _padding; @@ -360,7 +361,7 @@ impl Readable for ControlTlvs { next_blinding_override, }) } else if valid_recv_fmt { - ControlTlvs::Receive(ReceiveTlvs { context }) + ControlTlvs::Receive(ReceiveTlvs { context, custom_data }) } else { return Err(DecodeError::InvalidValue); }; From b14b154400c8f3a1d53737b7dee625315b857ed6 Mon Sep 17 00:00:00 2001 From: shaavan Date: Wed, 15 Jan 2025 19:43:14 +0530 Subject: [PATCH 03/10] Introduce custom_data in handle_dnssec_proof --- lightning-dns-resolver/src/lib.rs | 13 +++++++++---- lightning/src/ln/channelmanager.rs | 4 ++-- lightning/src/ln/peer_handler.rs | 2 +- lightning/src/onion_message/dns_resolution.rs | 11 +++++++---- lightning/src/onion_message/functional_tests.rs | 5 ++++- lightning/src/onion_message/messenger.rs | 2 +- 6 files changed, 24 insertions(+), 13 deletions(-) diff --git a/lightning-dns-resolver/src/lib.rs b/lightning-dns-resolver/src/lib.rs index d9d51c4bf1c..7851e350280 100644 --- a/lightning-dns-resolver/src/lib.rs +++ b/lightning-dns-resolver/src/lib.rs @@ -107,9 +107,11 @@ impl DNSResolverMessageHandler for OMDomainResolver where PH::Target: DNSResolverMessageHandler, { - fn handle_dnssec_proof(&self, proof: DNSSECProof, context: DNSResolverContext) { + fn handle_dnssec_proof( + &self, proof: DNSSECProof, context: DNSResolverContext, custom_data: Option>, + ) { if let Some(proof_handler) = &self.proof_handler { - proof_handler.handle_dnssec_proof(proof, context); + proof_handler.handle_dnssec_proof(proof, context, custom_data); } } @@ -253,8 +255,11 @@ mod test { panic!(); } - fn handle_dnssec_proof(&self, msg: DNSSECProof, context: DNSResolverContext) { - let mut proof = self.resolver.handle_dnssec_proof_for_uri(msg, context).unwrap(); + fn handle_dnssec_proof( + &self, msg: DNSSECProof, context: DNSResolverContext, custom_data: Option>, + ) { + let mut proof = + self.resolver.handle_dnssec_proof_for_uri(msg, context, custom_data).unwrap(); assert_eq!(proof.0.len(), 1); let payment = proof.0.pop().unwrap(); let mut result = Some((payment.0, payment.1, proof.1)); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 799affeac7b..556f8397ad3 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -12446,8 +12446,8 @@ where None } - fn handle_dnssec_proof(&self, message: DNSSECProof, context: DNSResolverContext) { - let offer_opt = self.hrn_resolver.handle_dnssec_proof_for_offer(message, context); + fn handle_dnssec_proof(&self, message: DNSSECProof, context: DNSResolverContext, custom_data: Option>) { + let offer_opt = self.hrn_resolver.handle_dnssec_proof_for_offer(message, context, custom_data); #[cfg_attr(not(feature = "_test_utils"), allow(unused_mut))] if let Some((completed_requests, mut offer)) = offer_opt { for (name, payment_id) in completed_requests { diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index e7d0b9fb636..fb59b1e142a 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -165,7 +165,7 @@ impl DNSResolverMessageHandler for IgnoringMessageHandler { ) -> Option<(DNSResolverMessage, ResponseInstruction)> { None } - fn handle_dnssec_proof(&self, _message: DNSSECProof, _context: DNSResolverContext) {} + fn handle_dnssec_proof(&self, _message: DNSSECProof, _context: DNSResolverContext, _custom_data: Option>) {} } impl CustomOnionMessageHandler for IgnoringMessageHandler { type CustomMessage = Infallible; diff --git a/lightning/src/onion_message/dns_resolution.rs b/lightning/src/onion_message/dns_resolution.rs index 0f6071e73a3..fd013db8637 100644 --- a/lightning/src/onion_message/dns_resolution.rs +++ b/lightning/src/onion_message/dns_resolution.rs @@ -67,7 +67,9 @@ pub trait DNSResolverMessageHandler { /// Handle a [`DNSSECProof`] message (in response to a [`DNSSECQuery`] we presumably sent). /// /// With this, we should be able to validate the DNS record we requested. - fn handle_dnssec_proof(&self, message: DNSSECProof, context: DNSResolverContext); + fn handle_dnssec_proof( + &self, message: DNSSECProof, context: DNSResolverContext, custom_data: Option>, + ); /// Gets the node feature flags which this handler itself supports. Useful for setting the /// `dns_resolver` flag if this handler supports returning [`DNSSECProof`] messages in response @@ -362,9 +364,10 @@ impl OMNameResolver { /// If an [`Offer`] is found, it, as well as the [`PaymentId`] and original `name` passed to /// [`Self::resolve_name`] are returned. pub fn handle_dnssec_proof_for_offer( - &self, msg: DNSSECProof, context: DNSResolverContext, + &self, msg: DNSSECProof, context: DNSResolverContext, custom_data: Option>, ) -> Option<(Vec<(HumanReadableName, PaymentId)>, Offer)> { - let (completed_requests, uri) = self.handle_dnssec_proof_for_uri(msg, context)?; + let (completed_requests, uri) = + self.handle_dnssec_proof_for_uri(msg, context, custom_data)?; if let Some((_onchain, params)) = uri.split_once("?") { for param in params.split("&") { let (k, v) = if let Some(split) = param.split_once("=") { @@ -395,7 +398,7 @@ impl OMNameResolver { /// This method is useful for those who handle bitcoin: URIs already, handling more than just /// BOLT12 [`Offer`]s. pub fn handle_dnssec_proof_for_uri( - &self, msg: DNSSECProof, context: DNSResolverContext, + &self, msg: DNSSECProof, context: DNSResolverContext, _custom_data: Option>, ) -> Option<(Vec<(HumanReadableName, PaymentId)>, String)> { let DNSSECProof { name: answer_name, proof } = msg; let mut pending_resolves = self.pending_resolves.lock().unwrap(); diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index e5afa737400..b3c80849b16 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -107,7 +107,10 @@ impl DNSResolverMessageHandler for TestDNSResolverMessageHandler { ) -> Option<(DNSResolverMessage, ResponseInstruction)> { None } - fn handle_dnssec_proof(&self, _message: DNSSECProof, _context: DNSResolverContext) {} + fn handle_dnssec_proof( + &self, _message: DNSSECProof, _context: DNSResolverContext, _custom_data: Option>, + ) { + } } #[derive(Clone, Debug, PartialEq)] diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 2793e807b39..05cc68fbbf2 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -1921,7 +1921,7 @@ where Some(MessageContext::DNSResolver(context)) => context, _ => return, }; - self.dns_resolver_handler.handle_dnssec_proof(msg, context); + self.dns_resolver_handler.handle_dnssec_proof(msg, context, custom_data); }, ParsedOnionMessageContents::Custom(msg) => { let context = match context { From 96f671933cce3bdec80824389818a19a99a20e31 Mon Sep 17 00:00:00 2001 From: shaavan Date: Mon, 13 Jan 2025 21:32:29 +0530 Subject: [PATCH 04/10] Introduce custom data in handle_custom_message --- fuzz/src/onion_message.rs | 2 +- lightning/src/ln/channelmanager.rs | 2 +- lightning/src/ln/peer_handler.rs | 2 +- .../src/onion_message/functional_tests.rs | 11 +++--- lightning/src/onion_message/messenger.rs | 39 ++++++++++++------- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index f285d1124bc..af93fd3e42e 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -161,7 +161,7 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; fn handle_custom_message( &self, message: Self::CustomMessage, _context: Option>, - responder: Option, + _custom_data: Option>, responder: Option, ) -> Option<(Self::CustomMessage, ResponseInstruction)> { match responder { Some(responder) => Some((message, responder.respond())), diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 556f8397ad3..8be05cb8923 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -12296,7 +12296,7 @@ where let nonce = Nonce::from_entropy_source(&*self.entropy_source); let hmac = payment_hash.hmac_for_offer_payment(nonce, expanded_key); let context = MessageContext::Offers(OffersContext::InboundPayment { payment_hash, nonce, hmac }); - Some((OffersMessage::Invoice(invoice), responder.respond_with_reply_path(context))) + Some((OffersMessage::Invoice(invoice), responder.respond_with_reply_path(context, None))) }, Err(error) => Some((OffersMessage::InvoiceError(error.into()), responder.respond())), } diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index fb59b1e142a..14e5870cfc9 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -169,7 +169,7 @@ impl DNSResolverMessageHandler for IgnoringMessageHandler { } impl CustomOnionMessageHandler for IgnoringMessageHandler { type CustomMessage = Infallible; - fn handle_custom_message(&self, _message: Infallible, _context: Option>, _responder: Option) -> Option<(Infallible, ResponseInstruction)> { + fn handle_custom_message(&self, _message: Infallible, _context: Option>, _custom_data: Option>, _responder: Option) -> Option<(Infallible, ResponseInstruction)> { // Since we always return `None` in the read the handle method should never be called. unreachable!(); } diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index b3c80849b16..110eed2bd60 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -191,7 +191,8 @@ impl Drop for TestCustomMessageHandler { impl CustomOnionMessageHandler for TestCustomMessageHandler { type CustomMessage = TestCustomMessage; fn handle_custom_message( - &self, msg: Self::CustomMessage, context: Option>, responder: Option, + &self, msg: Self::CustomMessage, context: Option>, custom_data: Option>, + responder: Option, ) -> Option<(Self::CustomMessage, ResponseInstruction)> { let expectation = self.get_next_expectation(); assert_eq!(msg, expectation.expect); @@ -209,7 +210,7 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler { match responder { Some(responder) if expectation.include_reply_path => { let context = MessageContext::Custom(context.unwrap_or_else(Vec::new)); - let reply = responder.respond_with_reply_path(context); + let reply = responder.respond_with_reply_path(context, custom_data); Some((response, reply)) }, Some(responder) => Some((response, responder.respond())), @@ -507,7 +508,7 @@ fn async_response_over_one_blinded_hop() { // 5. Expect Alice to receive the message and create a response instruction for it. alice.custom_message_handler.expect_message(message.clone()); let response_instruction = - nodes[0].custom_message_handler.handle_custom_message(message, None, responder); + nodes[0].custom_message_handler.handle_custom_message(message, None, None, responder); // 6. Simulate Alice asynchronously responding back to Bob with a response. let (msg, instructions) = response_instruction.unwrap(); @@ -546,7 +547,7 @@ fn async_response_with_reply_path_succeeds() { let responder = Responder::new(reply_path); alice.custom_message_handler.expect_message_and_response(message.clone()); let response_instruction = - alice.custom_message_handler.handle_custom_message(message, None, Some(responder)); + alice.custom_message_handler.handle_custom_message(message, None, None, Some(responder)); let (msg, instructions) = response_instruction.unwrap(); assert_eq!( @@ -590,7 +591,7 @@ fn async_response_with_reply_path_fails() { let responder = Responder::new(reply_path); alice.custom_message_handler.expect_message_and_response(message.clone()); let response_instruction = - alice.custom_message_handler.handle_custom_message(message, None, Some(responder)); + alice.custom_message_handler.handle_custom_message(message, None, None, Some(responder)); let (msg, instructions) = response_instruction.unwrap(); assert_eq!( diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index 05cc68fbbf2..103dd98f1a8 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -418,17 +418,19 @@ impl Responder { pub fn respond(self) -> ResponseInstruction { ResponseInstruction { destination: Destination::BlindedPath(self.reply_path), - context: None, + reply_data: (None, None), } } /// Creates a [`ResponseInstruction`] for responding including a reply path. /// /// Use when the recipient needs to send back a reply to us. - pub fn respond_with_reply_path(self, context: MessageContext) -> ResponseInstruction { + pub fn respond_with_reply_path( + self, context: MessageContext, custom_data: Option>, + ) -> ResponseInstruction { ResponseInstruction { destination: Destination::BlindedPath(self.reply_path), - context: Some(context), + reply_data: (Some(context), custom_data), } } } @@ -440,7 +442,7 @@ pub struct ResponseInstruction { /// [`Destination`] rather than an explicit [`BlindedMessagePath`] simplifies the logic in /// [`OnionMessenger::send_onion_message_internal`] somewhat. destination: Destination, - context: Option, + reply_data: (Option, Option>), } impl ResponseInstruction { @@ -469,7 +471,7 @@ pub enum MessageSendInstructions { destination: Destination, /// The context to include in the reply path we'll give the recipient so they can respond /// to us. - context: MessageContext, + reply_data: (MessageContext, Option>), }, /// Indicates that a message should be sent without including a reply path, preventing the /// recipient from responding. @@ -886,7 +888,8 @@ pub trait CustomOnionMessageHandler { /// /// The returned [`Self::CustomMessage`], if any, is enqueued to be sent by [`OnionMessenger`]. fn handle_custom_message( - &self, message: Self::CustomMessage, context: Option>, responder: Option, + &self, message: Self::CustomMessage, context: Option>, + custom_data: Option>, responder: Option, ) -> Option<(Self::CustomMessage, ResponseInstruction)>; /// Read a custom message of type `message_type` from `buffer`, returning `Ok(None)` if the @@ -1332,10 +1335,14 @@ where MessageSendInstructions::WithSpecifiedReplyPath { destination, reply_path } => { (destination, Some(reply_path)) }, - MessageSendInstructions::WithReplyPath { destination, context } + MessageSendInstructions::WithReplyPath { + destination, + reply_data: (context, custom_data), + } | MessageSendInstructions::ForReply { - instructions: ResponseInstruction { destination, context: Some(context) }, - } => match self.create_blinded_path(context) { + instructions: + ResponseInstruction { destination, reply_data: (Some(context), custom_data) }, + } => match self.create_blinded_path(context, custom_data) { Ok(reply_path) => (destination, Some(reply_path)), Err(err) => { log_trace!( @@ -1349,7 +1356,7 @@ where }, MessageSendInstructions::WithoutReplyPath { destination } | MessageSendInstructions::ForReply { - instructions: ResponseInstruction { destination, context: None }, + instructions: ResponseInstruction { destination, reply_data: (None, _) }, } => (destination, None), }; @@ -1407,7 +1414,7 @@ where } fn create_blinded_path( - &self, context: MessageContext, + &self, context: MessageContext, custom_data: Option>, ) -> Result { let recipient = self .node_signer @@ -1424,7 +1431,7 @@ where .collect::>() }; - let recipient_tlvs = ReceiveTlvs { context: Some(context), custom_data: None }; + let recipient_tlvs = ReceiveTlvs { context: Some(context), custom_data }; self.message_router .create_blinded_paths(recipient, recipient_tlvs, peers, secp_ctx) @@ -1932,8 +1939,12 @@ where return; }, }; - let response_instructions = - self.custom_handler.handle_custom_message(msg, context, responder); + let response_instructions = self.custom_handler.handle_custom_message( + msg, + context, + custom_data, + responder, + ); if let Some((msg, instructions)) = response_instructions { let _ = self.handle_onion_message_response(msg, instructions); } From fad7d497c319ad300f95fb33e2506d4a8753181e Mon Sep 17 00:00:00 2001 From: shaavan Date: Tue, 14 Jan 2025 19:26:31 +0530 Subject: [PATCH 05/10] Introduce custom_data test framework for message::ReceiveTlvs --- .../src/onion_message/functional_tests.rs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 110eed2bd60..f55aad77f1d 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -157,6 +157,7 @@ struct TestCustomMessageHandler { struct OnHandleCustomMessage { expect: TestCustomMessage, include_reply_path: bool, + custom_data: Option>, } impl TestCustomMessageHandler { @@ -165,13 +166,25 @@ impl TestCustomMessageHandler { } fn expect_message(&self, message: TestCustomMessage) { - let expectation = OnHandleCustomMessage { expect: message, include_reply_path: false }; + let expectation = + OnHandleCustomMessage { expect: message, include_reply_path: false, custom_data: None }; self.expectations.lock().unwrap().push_back(expectation); } fn expect_message_and_response(&self, message: TestCustomMessage) { - let expectation = OnHandleCustomMessage { expect: message, include_reply_path: true }; - self.expectations.lock().unwrap().push_back(expectation); + self.expectations.lock().unwrap().push_back(OnHandleCustomMessage { + expect: message, + include_reply_path: true, + custom_data: None, + }); + } + + fn expect_message_with_custom_data(&self, message: TestCustomMessage, custom_data: Vec) { + self.expectations.lock().unwrap().push_back(OnHandleCustomMessage { + expect: message, + include_reply_path: false, + custom_data: Some(custom_data), + }); } fn get_next_expectation(&self) -> OnHandleCustomMessage { @@ -196,6 +209,7 @@ impl CustomOnionMessageHandler for TestCustomMessageHandler { ) -> Option<(Self::CustomMessage, ResponseInstruction)> { let expectation = self.get_next_expectation(); assert_eq!(msg, expectation.expect); + assert_eq!(custom_data, expectation.custom_data); let response = match msg { TestCustomMessage::Ping => TestCustomMessage::Pong, From 3831984ee70056ce7a65ea2ee12bc68fa5e1e7eb Mon Sep 17 00:00:00 2001 From: shaavan Date: Tue, 14 Jan 2025 19:57:08 +0530 Subject: [PATCH 06/10] Introduce custom data test for message::ReceiveTlvs --- lightning/src/ln/async_payments_tests.rs | 7 +++++ .../src/onion_message/functional_tests.rs | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/lightning/src/ln/async_payments_tests.rs b/lightning/src/ln/async_payments_tests.rs index 5ae5bcb02cd..c031af32fb4 100644 --- a/lightning/src/ln/async_payments_tests.rs +++ b/lightning/src/ln/async_payments_tests.rs @@ -305,6 +305,13 @@ fn ignore_unexpected_static_invoice() { create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0); create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0); + let recipient_tlvs = ReceiveTlvs { + context: Some(MessageContext::Offers(OffersContext::InvoiceRequest { + nonce: Nonce([42; 16]), + })), + custom_data: None, + }; + // Initiate payment to the sender's intended offer. let (offer, valid_static_invoice) = create_static_invoice(&nodes[1], &nodes[2], None, &secp_ctx); diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index f55aad77f1d..d56cc98a88b 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -437,6 +437,33 @@ fn one_blinded_hop() { pass_along_path(&nodes); } +#[test] +fn one_blinded_hop_with_custom_data() { + let nodes = create_nodes(2); + let test_msg = TestCustomMessage::Pong; + + let secp_ctx = Secp256k1::new(); + let recipient_tlvs = ReceiveTlvs { + context: Some(MessageContext::Custom(Vec::new())), + custom_data: Some(vec![42; 42]), + }; + let blinded_path = BlindedMessagePath::new( + &[], + nodes[1].node_id, + recipient_tlvs, + &*nodes[1].entropy_source, + &secp_ctx, + ) + .unwrap(); + let destination = Destination::BlindedPath(blinded_path); + let instructions = MessageSendInstructions::WithoutReplyPath { destination }; + nodes[0].messenger.send_onion_message(test_msg, instructions).unwrap(); + nodes[1] + .custom_message_handler + .expect_message_with_custom_data(TestCustomMessage::Pong, vec![42; 42]); + pass_along_path(&nodes); +} + #[test] fn two_unblinded_two_blinded() { let nodes = create_nodes(5); From c238f91c64c46d40b04cd17f3a1124f584d20d63 Mon Sep 17 00:00:00 2001 From: shaavan Date: Wed, 15 Jan 2025 20:29:31 +0530 Subject: [PATCH 07/10] Rename custom_tlvs -> sender_custom_tlvs --- lightning/src/events/mod.rs | 12 +-- lightning/src/ln/async_payments_tests.rs | 7 -- lightning/src/ln/blinded_payment_tests.rs | 8 +- lightning/src/ln/channelmanager.rs | 62 ++++++++-------- lightning/src/ln/functional_test_utils.rs | 26 +++---- .../src/ln/max_payment_path_len_tests.rs | 38 +++++----- lightning/src/ln/msgs.rs | 72 +++++++++--------- lightning/src/ln/onion_payment.rs | 16 ++-- lightning/src/ln/onion_route_tests.rs | 2 +- lightning/src/ln/onion_utils.rs | 12 +-- lightning/src/ln/outbound_payment.rs | 74 +++++++++---------- lightning/src/ln/payment_tests.rs | 72 +++++++++--------- lightning/src/routing/router.rs | 2 +- 13 files changed, 199 insertions(+), 204 deletions(-) diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index b5dad96a979..eff9f695c59 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -705,15 +705,15 @@ pub enum Event { /// [`ChannelManager::fail_htlc_backwards`] or [`ChannelManager::fail_htlc_backwards_with_reason`] /// to free up resources for this HTLC and avoid network congestion. /// - /// If [`Event::PaymentClaimable::onion_fields`] is `Some`, and includes custom TLVs with even type + /// If [`Event::PaymentClaimable::onion_fields`] is `Some`, and includes sender custom TLVs with even type /// numbers, you should use [`ChannelManager::fail_htlc_backwards_with_reason`] with /// [`FailureCode::InvalidOnionPayload`] if you fail to understand and handle the contents, or - /// [`ChannelManager::claim_funds_with_known_custom_tlvs`] upon successful handling. - /// If you don't intend to check for custom TLVs, you can simply use - /// [`ChannelManager::claim_funds`], which will automatically fail back even custom TLVs. + /// [`ChannelManager::claim_funds_with_known_sender_custom_tlvs`] upon successful handling. + /// If you don't intend to check for sender custom TLVs, you can simply use + /// [`ChannelManager::claim_funds`], which will automatically fail back even sender custom TLVs. /// /// If you fail to call [`ChannelManager::claim_funds`], - /// [`ChannelManager::claim_funds_with_known_custom_tlvs`], + /// [`ChannelManager::claim_funds_with_known_sender_custom_tlvs`], /// [`ChannelManager::fail_htlc_backwards`], or /// [`ChannelManager::fail_htlc_backwards_with_reason`] within the HTLC's timeout, the HTLC will /// be automatically failed. @@ -732,7 +732,7 @@ pub enum Event { /// returning `Err(ReplayEvent ())`) and will be persisted across restarts. /// /// [`ChannelManager::claim_funds`]: crate::ln::channelmanager::ChannelManager::claim_funds - /// [`ChannelManager::claim_funds_with_known_custom_tlvs`]: crate::ln::channelmanager::ChannelManager::claim_funds_with_known_custom_tlvs + /// [`ChannelManager::claim_funds_with_known_sender_custom_tlvs`]: crate::ln::channelmanager::ChannelManager::claim_funds_with_known_sender_custom_tlvs /// [`FailureCode::InvalidOnionPayload`]: crate::ln::channelmanager::FailureCode::InvalidOnionPayload /// [`ChannelManager::fail_htlc_backwards`]: crate::ln::channelmanager::ChannelManager::fail_htlc_backwards /// [`ChannelManager::fail_htlc_backwards_with_reason`]: crate::ln::channelmanager::ChannelManager::fail_htlc_backwards_with_reason diff --git a/lightning/src/ln/async_payments_tests.rs b/lightning/src/ln/async_payments_tests.rs index c031af32fb4..5ae5bcb02cd 100644 --- a/lightning/src/ln/async_payments_tests.rs +++ b/lightning/src/ln/async_payments_tests.rs @@ -305,13 +305,6 @@ fn ignore_unexpected_static_invoice() { create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0); create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0); - let recipient_tlvs = ReceiveTlvs { - context: Some(MessageContext::Offers(OffersContext::InvoiceRequest { - nonce: Nonce([42; 16]), - })), - custom_data: None, - }; - // Initiate payment to the sender's intended offer. let (offer, valid_static_invoice) = create_static_invoice(&nodes[1], &nodes[2], None, &secp_ctx); diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 0662d5f9395..52b46e05a2b 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -1283,7 +1283,7 @@ fn conditionally_round_fwd_amt() { #[test] -fn custom_tlvs_to_blinded_path() { +fn sender_custom_tlvs_to_blinded_path() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); @@ -1315,7 +1315,7 @@ fn custom_tlvs_to_blinded_path() { ); let recipient_onion_fields = RecipientOnionFields::spontaneous_empty() - .with_custom_tlvs(vec![((1 << 16) + 1, vec![42, 42])]) + .with_sender_custom_tlvs(vec![((1 << 16) + 1, vec![42, 42])]) .unwrap(); nodes[0].node.send_payment(payment_hash, recipient_onion_fields.clone(), PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap(); @@ -1328,11 +1328,11 @@ fn custom_tlvs_to_blinded_path() { let path = &[&nodes[1]]; let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, ev) .with_payment_secret(payment_secret) - .with_custom_tlvs(recipient_onion_fields.custom_tlvs.clone()); + .with_sender_custom_tlvs(recipient_onion_fields.sender_custom_tlvs.clone()); do_pass_along_path(args); claim_payment_along_route( ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1]]], payment_preimage) - .with_custom_tlvs(recipient_onion_fields.custom_tlvs.clone()) + .with_sender_custom_tlvs(recipient_onion_fields.sender_custom_tlvs.clone()) ); } diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 8be05cb8923..39f527bcd6c 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -216,12 +216,12 @@ pub enum PendingHTLCRouting { /// provide the onion shared secret used to decrypt the next level of forwarding /// instructions. phantom_shared_secret: Option<[u8; 32]>, - /// Custom TLVs which were set by the sender. + /// Sender custom TLVs which were set by the sender. /// /// For HTLCs received by LDK, this will ultimately be exposed in /// [`Event::PaymentClaimable::onion_fields`] as - /// [`RecipientOnionFields::custom_tlvs`]. - custom_tlvs: Vec<(u64, Vec)>, + /// [`RecipientOnionFields::sender_custom_tlvs`]. + sender_custom_tlvs: Vec<(u64, Vec)>, /// Set if this HTLC is the final hop in a multi-hop blinded path. requires_blinded_error: bool, }, @@ -247,11 +247,11 @@ pub enum PendingHTLCRouting { /// /// Used to track when we should expire pending HTLCs that go unclaimed. incoming_cltv_expiry: u32, - /// Custom TLVs which were set by the sender. + /// Sender custom TLVs which were set by the sender. /// /// For HTLCs received by LDK, these will ultimately bubble back up as - /// [`RecipientOnionFields::custom_tlvs`]. - custom_tlvs: Vec<(u64, Vec)>, + /// [`RecipientOnionFields::sender_custom_tlvs`]. + sender_custom_tlvs: Vec<(u64, Vec)>, /// Set if this HTLC is the final hop in a multi-hop blinded path. requires_blinded_error: bool, /// Set if we are receiving a keysend to a blinded path, meaning we created the @@ -984,17 +984,17 @@ struct ClaimablePayments { impl ClaimablePayments { /// Moves a payment from [`Self::claimable_payments`] to [`Self::pending_claiming_payments`]. /// - /// If `custom_tlvs_known` is false and custom even TLVs are set by the sender, the set of + /// If `sender_custom_tlvs_known` is false and custom even TLVs are set by the sender, the set of /// pending HTLCs will be returned in the `Err` variant of this method. They MUST then be /// failed by the caller as they will not be in either [`Self::claimable_payments`] or /// [`Self::pending_claiming_payments`]. /// - /// If `custom_tlvs_known` is true, and a matching payment is found, it will always be moved. + /// If `sender_custom_tlvs_known` is true, and a matching payment is found, it will always be moved. /// /// If no payment is found, `Err(Vec::new())` is returned. fn begin_claiming_payment( &mut self, payment_hash: PaymentHash, node_signer: &S, logger: &L, - inbound_payment_id_secret: &[u8; 32], custom_tlvs_known: bool, + inbound_payment_id_secret: &[u8; 32], sender_custom_tlvs_known: bool, ) -> Result<(Vec, ClaimingPayment), Vec> where L::Target: Logger, S::Target: NodeSigner, { @@ -1011,10 +1011,10 @@ impl ClaimablePayments { } } - if let Some(RecipientOnionFields { custom_tlvs, .. }) = &payment.onion_fields { - if !custom_tlvs_known && custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) { + if let Some(RecipientOnionFields { sender_custom_tlvs, .. }) = &payment.onion_fields { + if !sender_custom_tlvs_known && sender_custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) { log_info!(logger, "Rejecting payment with payment hash {} as we cannot accept payment with unknown even TLVs: {}", - &payment_hash, log_iter!(custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0))); + &payment_hash, log_iter!(sender_custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0))); return Err(payment.htlcs); } } @@ -6118,25 +6118,25 @@ where ) = match routing { PendingHTLCRouting::Receive { payment_data, payment_metadata, payment_context, - incoming_cltv_expiry, phantom_shared_secret, custom_tlvs, + incoming_cltv_expiry, phantom_shared_secret, sender_custom_tlvs, requires_blinded_error: _ } => { let _legacy_hop_data = Some(payment_data.clone()); let onion_fields = RecipientOnionFields { payment_secret: Some(payment_data.payment_secret), - payment_metadata, custom_tlvs }; + payment_metadata, sender_custom_tlvs }; (incoming_cltv_expiry, OnionPayload::Invoice { _legacy_hop_data }, Some(payment_data), payment_context, phantom_shared_secret, onion_fields, true, None) }, PendingHTLCRouting::ReceiveKeysend { payment_data, payment_preimage, payment_metadata, - incoming_cltv_expiry, custom_tlvs, requires_blinded_error: _, + incoming_cltv_expiry, sender_custom_tlvs, requires_blinded_error: _, has_recipient_created_payment_secret, payment_context, invoice_request, } => { let onion_fields = RecipientOnionFields { payment_secret: payment_data.as_ref().map(|data| data.payment_secret), payment_metadata, - custom_tlvs, + sender_custom_tlvs, }; (incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage), payment_data, payment_context, None, onion_fields, @@ -7001,9 +7001,9 @@ where /// event matches your expectation. If you fail to do so and call this method, you may provide /// the sender "proof-of-payment" when they did not fulfill the full expected payment. /// - /// This function will fail the payment if it has custom TLVs with even type numbers, as we - /// will assume they are unknown. If you intend to accept even custom TLVs, you should use - /// [`claim_funds_with_known_custom_tlvs`]. + /// This function will fail the payment if it has sender custom TLVs with even type numbers, as we + /// will assume they are unknown. If you intend to accept even sender custom TLVs, you should use + /// [`claim_funds_with_known_sender_custom_tlvs`]. /// /// [`Event::PaymentClaimable`]: crate::events::Event::PaymentClaimable /// [`Event::PaymentClaimable::claim_deadline`]: crate::events::Event::PaymentClaimable::claim_deadline @@ -7011,12 +7011,12 @@ where /// [`process_pending_events`]: EventsProvider::process_pending_events /// [`create_inbound_payment`]: Self::create_inbound_payment /// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash - /// [`claim_funds_with_known_custom_tlvs`]: Self::claim_funds_with_known_custom_tlvs + /// [`claim_funds_with_known_sender_custom_tlvs`]: Self::claim_funds_with_known_sender_custom_tlvs pub fn claim_funds(&self, payment_preimage: PaymentPreimage) { self.claim_payment_internal(payment_preimage, false); } - /// This is a variant of [`claim_funds`] that allows accepting a payment with custom TLVs with + /// This is a variant of [`claim_funds`] that allows accepting a payment with sender custom TLVs with /// even type numbers. /// /// # Note @@ -7025,11 +7025,11 @@ where /// claim, otherwise you may unintentionally agree to some protocol you do not understand. /// /// [`claim_funds`]: Self::claim_funds - pub fn claim_funds_with_known_custom_tlvs(&self, payment_preimage: PaymentPreimage) { + pub fn claim_funds_with_known_sender_custom_tlvs(&self, payment_preimage: PaymentPreimage) { self.claim_payment_internal(payment_preimage, true); } - fn claim_payment_internal(&self, payment_preimage: PaymentPreimage, custom_tlvs_known: bool) { + fn claim_payment_internal(&self, payment_preimage: PaymentPreimage, sender_custom_tlvs_known: bool) { let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0).to_byte_array()); let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); @@ -7037,7 +7037,7 @@ where let (sources, claiming_payment) = { let res = self.claimable_payments.lock().unwrap().begin_claiming_payment( payment_hash, &self.node_signer, &self.logger, &self.inbound_payment_id_secret, - custom_tlvs_known, + sender_custom_tlvs_known, ); match res { @@ -12600,7 +12600,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, (1, phantom_shared_secret, option), (2, incoming_cltv_expiry, required), (3, payment_metadata, option), - (5, custom_tlvs, optional_vec), + (5, sender_custom_tlvs, optional_vec), (7, requires_blinded_error, (default_value, false)), (9, payment_context, option), }, @@ -12610,7 +12610,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, (2, incoming_cltv_expiry, required), (3, payment_metadata, option), (4, payment_data, option), // Added in 0.0.116 - (5, custom_tlvs, optional_vec), + (5, sender_custom_tlvs, optional_vec), (7, has_recipient_created_payment_secret, (default_value, false)), (9, payment_context, option), (11, invoice_request, option), @@ -12629,7 +12629,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, (1, phantom_shared_secret, option), (2, incoming_cltv_expiry, required), (3, payment_metadata, option), - (5, custom_tlvs, optional_vec), + (5, sender_custom_tlvs, optional_vec), (7, requires_blinded_error, (default_value, false)), (9, payment_context, option), }, @@ -12639,7 +12639,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, (2, incoming_cltv_expiry, required), (3, payment_metadata, option), (4, payment_data, option), // Added in 0.0.116 - (5, custom_tlvs, optional_vec), + (5, sender_custom_tlvs, optional_vec), (7, has_recipient_created_payment_secret, (default_value, false)), (9, payment_context, option), (11, invoice_request, option), @@ -15771,7 +15771,7 @@ mod tests { payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat, }), - custom_tlvs: Vec::new(), + sender_custom_tlvs: Vec::new(), }); // Check that if the amount we received + the penultimate hop extra fee is less than the sender // intended amount, we fail the payment. @@ -15794,7 +15794,7 @@ mod tests { payment_secret: PaymentSecret([0; 32]), total_msat: sender_intended_amt_msat, }), - custom_tlvs: Vec::new(), + sender_custom_tlvs: Vec::new(), }); let current_height: u32 = node[0].node.best_block.read().unwrap().height; assert!(create_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]), @@ -15819,7 +15819,7 @@ mod tests { payment_secret: PaymentSecret([0; 32]), total_msat: 100, }), - custom_tlvs: Vec::new(), + sender_custom_tlvs: Vec::new(), }), [0; 32], PaymentHash([0; 32]), 100, 23, None, true, None, current_height); // Should not return an error as this condition: diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index fa21967fdde..7e449dbb633 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -2658,7 +2658,7 @@ pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> { pub clear_recipient_events: bool, pub expected_preimage: Option, pub is_probe: bool, - pub custom_tlvs: Vec<(u64, Vec)>, + pub sender_custom_tlvs: Vec<(u64, Vec)>, pub payment_metadata: Option>, pub expected_failure: Option, } @@ -2671,7 +2671,7 @@ impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> { Self { origin_node, expected_path, recv_value, payment_hash, payment_secret: None, event, payment_claimable_expected: true, clear_recipient_events: true, expected_preimage: None, - is_probe: false, custom_tlvs: Vec::new(), payment_metadata: None, expected_failure: None, + is_probe: false, sender_custom_tlvs: Vec::new(), payment_metadata: None, expected_failure: None, } } pub fn without_clearing_recipient_events(mut self) -> Self { @@ -2695,8 +2695,8 @@ impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> { self.expected_preimage = Some(payment_preimage); self } - pub fn with_custom_tlvs(mut self, custom_tlvs: Vec<(u64, Vec)>) -> Self { - self.custom_tlvs = custom_tlvs; + pub fn with_sender_custom_tlvs(mut self, sender_custom_tlvs: Vec<(u64, Vec)>) -> Self { + self.sender_custom_tlvs = sender_custom_tlvs; self } pub fn with_payment_metadata(mut self, payment_metadata: Vec) -> Self { @@ -2714,7 +2714,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option let PassAlongPathArgs { origin_node, expected_path, recv_value, payment_hash: our_payment_hash, payment_secret: our_payment_secret, event: ev, payment_claimable_expected, - clear_recipient_events, expected_preimage, is_probe, custom_tlvs, payment_metadata, + clear_recipient_events, expected_preimage, is_probe, sender_custom_tlvs, payment_metadata, expected_failure } = args; @@ -2750,7 +2750,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option assert_eq!(our_payment_hash, *payment_hash); assert_eq!(node.node.get_our_node_id(), receiver_node_id.unwrap()); assert!(onion_fields.is_some()); - assert_eq!(onion_fields.as_ref().unwrap().custom_tlvs, custom_tlvs); + assert_eq!(onion_fields.as_ref().unwrap().sender_custom_tlvs, sender_custom_tlvs); assert_eq!(onion_fields.as_ref().unwrap().payment_metadata, payment_metadata); match &purpose { PaymentPurpose::Bolt11InvoicePayment { payment_preimage, payment_secret, .. } => { @@ -2881,7 +2881,7 @@ pub struct ClaimAlongRouteArgs<'a, 'b, 'c, 'd> { pub expected_min_htlc_overpay: Vec, pub skip_last: bool, pub payment_preimage: PaymentPreimage, - pub custom_tlvs: Vec<(u64, Vec)>, + pub sender_custom_tlvs: Vec<(u64, Vec)>, // Allow forwarding nodes to have taken 1 msat more fee than expected based on the downstream // fulfill amount. // @@ -2900,7 +2900,7 @@ impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> { Self { origin_node, expected_paths, expected_extra_fees: vec![0; expected_paths.len()], expected_min_htlc_overpay: vec![0; expected_paths.len()], skip_last: false, payment_preimage, - allow_1_msat_fee_overpay: false, custom_tlvs: vec![], + allow_1_msat_fee_overpay: false, sender_custom_tlvs: vec![], } } pub fn skip_last(mut self, skip_last: bool) -> Self { @@ -2919,8 +2919,8 @@ impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> { self.allow_1_msat_fee_overpay = true; self } - pub fn with_custom_tlvs(mut self, custom_tlvs: Vec<(u64, Vec)>) -> Self { - self.custom_tlvs = custom_tlvs; + pub fn with_sender_custom_tlvs(mut self, sender_custom_tlvs: Vec<(u64, Vec)>) -> Self { + self.sender_custom_tlvs = sender_custom_tlvs; self } } @@ -2928,7 +2928,7 @@ impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> { pub fn pass_claimed_payment_along_route(args: ClaimAlongRouteArgs) -> u64 { let ClaimAlongRouteArgs { origin_node, expected_paths, expected_extra_fees, expected_min_htlc_overpay, skip_last, - payment_preimage: our_payment_preimage, allow_1_msat_fee_overpay, custom_tlvs, + payment_preimage: our_payment_preimage, allow_1_msat_fee_overpay, sender_custom_tlvs, } = args; let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events(); assert_eq!(claim_event.len(), 1); @@ -2948,7 +2948,7 @@ pub fn pass_claimed_payment_along_route(args: ClaimAlongRouteArgs) -> u64 { assert_eq!(preimage, our_payment_preimage); assert_eq!(htlcs.len(), expected_paths.len()); // One per path. assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::(), amount_msat); - assert_eq!(onion_fields.as_ref().unwrap().custom_tlvs, custom_tlvs); + assert_eq!(onion_fields.as_ref().unwrap().sender_custom_tlvs, sender_custom_tlvs); check_claimed_htlcs_match_route(origin_node, expected_paths, htlcs); fwd_amt_msat = amount_msat; }, @@ -2965,7 +2965,7 @@ pub fn pass_claimed_payment_along_route(args: ClaimAlongRouteArgs) -> u64 { assert_eq!(&payment_hash.0, &Sha256::hash(&our_payment_preimage.0)[..]); assert_eq!(htlcs.len(), expected_paths.len()); // One per path. assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::(), amount_msat); - assert_eq!(onion_fields.as_ref().unwrap().custom_tlvs, custom_tlvs); + assert_eq!(onion_fields.as_ref().unwrap().sender_custom_tlvs, sender_custom_tlvs); check_claimed_htlcs_match_route(origin_node, expected_paths, htlcs); fwd_amt_msat = amount_msat; } diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index 98c3a062bc4..43c0f840489 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -7,7 +7,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -//! Tests for calculating the maximum length of a path based on the payment metadata, custom TLVs, +//! Tests for calculating the maximum length of a path based on the payment metadata, sender custom TLVs, //! and/or blinded paths present. use bitcoin::secp256k1::{Secp256k1, PublicKey}; @@ -60,7 +60,7 @@ fn large_payment_metadata() { }), payment_metadata: None, keysend_preimage: None, - custom_tlvs: &Vec::new(), + sender_custom_tlvs: &Vec::new(), sender_intended_htlc_amt_msat: MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, cltv_expiry_height: nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, }.serialized_length(); @@ -77,7 +77,7 @@ fn large_payment_metadata() { let mut recipient_onion_max_md_size = RecipientOnionFields { payment_secret: Some(payment_secret), payment_metadata: Some(payment_metadata.clone()), - custom_tlvs: Vec::new(), + sender_custom_tlvs: Vec::new(), }; nodes[0].node.send_payment(payment_hash, recipient_onion_max_md_size.clone(), PaymentId(payment_hash.0), route_0_1.route_params.clone().unwrap(), Retry::Attempts(0)).unwrap(); check_added_monitors!(nodes[0], 1); @@ -125,7 +125,7 @@ fn large_payment_metadata() { let mut recipient_onion_allows_2_hops = RecipientOnionFields { payment_secret: Some(payment_secret_2), payment_metadata: Some(vec![42; max_metadata_len - INTERMED_PAYLOAD_LEN_ESTIMATE]), - custom_tlvs: Vec::new(), + sender_custom_tlvs: Vec::new(), }; let mut route_params_0_2 = route_0_2.route_params.clone().unwrap(); route_params_0_2.payment_params.max_path_length = 2; @@ -190,7 +190,7 @@ fn one_hop_blinded_path_with_custom_tlv() { intro_node_blinding_point: Some(blinded_path.blinding_point()), keysend_preimage: None, invoice_request: None, - custom_tlvs: &Vec::new() + sender_custom_tlvs: &Vec::new() }.serialized_length(); let max_custom_tlv_len = 1300 - crate::util::ser::BigSize(CUSTOM_TLV_TYPE).serialized_length() // custom TLV type @@ -201,7 +201,7 @@ fn one_hop_blinded_path_with_custom_tlv() { // Check that we can send the maximum custom TLV with 1 blinded hop. let recipient_onion_max_custom_tlv_size = RecipientOnionFields::spontaneous_empty() - .with_custom_tlvs(vec![(CUSTOM_TLV_TYPE, vec![42; max_custom_tlv_len])]) + .with_sender_custom_tlvs(vec![(CUSTOM_TLV_TYPE, vec![42; max_custom_tlv_len])]) .unwrap(); nodes[1].node.send_payment(payment_hash, recipient_onion_max_custom_tlv_size.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap(); check_added_monitors(&nodes[1], 1); @@ -211,16 +211,16 @@ fn one_hop_blinded_path_with_custom_tlv() { let path = &[&nodes[2]]; let args = PassAlongPathArgs::new(&nodes[1], path, amt_msat, payment_hash, events.pop().unwrap()) .with_payment_secret(payment_secret) - .with_custom_tlvs(recipient_onion_max_custom_tlv_size.custom_tlvs.clone()); + .with_sender_custom_tlvs(recipient_onion_max_custom_tlv_size.sender_custom_tlvs.clone()); do_pass_along_path(args); claim_payment_along_route( ClaimAlongRouteArgs::new(&nodes[1], &[&[&nodes[2]]], payment_preimage) - .with_custom_tlvs(recipient_onion_max_custom_tlv_size.custom_tlvs.clone()) + .with_sender_custom_tlvs(recipient_onion_max_custom_tlv_size.sender_custom_tlvs.clone()) ); // If 1 byte is added to the custom TLV value, we'll fail to send prior to pathfinding. let mut recipient_onion_too_large_custom_tlv = recipient_onion_max_custom_tlv_size.clone(); - recipient_onion_too_large_custom_tlv.custom_tlvs[0].1.push(42); + recipient_onion_too_large_custom_tlv.sender_custom_tlvs[0].1.push(42); let err = nodes[1].node.send_payment(payment_hash, recipient_onion_too_large_custom_tlv, PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap_err(); assert_eq!(err, RetryableSendFailure::OnionPacketSizeExceeded); @@ -232,7 +232,7 @@ fn one_hop_blinded_path_with_custom_tlv() { // If we remove enough custom TLV bytes to allow for 1 intermediate unblinded hop, we're now able // to send nodes[0] -> nodes[2]. let mut recipient_onion_allows_2_hops = recipient_onion_max_custom_tlv_size.clone(); - recipient_onion_allows_2_hops.custom_tlvs[0].1.resize(max_custom_tlv_len - INTERMED_PAYLOAD_LEN_ESTIMATE, 0); + recipient_onion_allows_2_hops.sender_custom_tlvs[0].1.resize(max_custom_tlv_len - INTERMED_PAYLOAD_LEN_ESTIMATE, 0); nodes[0].node.send_payment(payment_hash, recipient_onion_allows_2_hops.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap(); check_added_monitors(&nodes[0], 1); @@ -241,11 +241,11 @@ fn one_hop_blinded_path_with_custom_tlv() { let path = &[&nodes[1], &nodes[2]]; let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, events.pop().unwrap()) .with_payment_secret(payment_secret) - .with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs.clone()); + .with_sender_custom_tlvs(recipient_onion_allows_2_hops.sender_custom_tlvs.clone()); do_pass_along_path(args); claim_payment_along_route( ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1], &nodes[2]]], payment_preimage) - .with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs) + .with_sender_custom_tlvs(recipient_onion_allows_2_hops.sender_custom_tlvs) ); } @@ -297,7 +297,7 @@ fn blinded_path_with_custom_tlv() { // Check that we can send the maximum custom TLV size with 0 intermediate unblinded hops. let recipient_onion_max_custom_tlv_size = RecipientOnionFields::spontaneous_empty() - .with_custom_tlvs(vec![(CUSTOM_TLV_TYPE, vec![42; max_custom_tlv_len])]) + .with_sender_custom_tlvs(vec![(CUSTOM_TLV_TYPE, vec![42; max_custom_tlv_len])]) .unwrap(); nodes[1].node.send_payment(payment_hash, recipient_onion_max_custom_tlv_size.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap(); check_added_monitors(&nodes[1], 1); @@ -307,16 +307,16 @@ fn blinded_path_with_custom_tlv() { let path = &[&nodes[2], &nodes[3]]; let args = PassAlongPathArgs::new(&nodes[1], path, amt_msat, payment_hash, events.pop().unwrap()) .with_payment_secret(payment_secret) - .with_custom_tlvs(recipient_onion_max_custom_tlv_size.custom_tlvs.clone()); + .with_sender_custom_tlvs(recipient_onion_max_custom_tlv_size.sender_custom_tlvs.clone()); do_pass_along_path(args); claim_payment_along_route( ClaimAlongRouteArgs::new(&nodes[1], &[&[&nodes[2], &nodes[3]]], payment_preimage) - .with_custom_tlvs(recipient_onion_max_custom_tlv_size.custom_tlvs.clone()) + .with_sender_custom_tlvs(recipient_onion_max_custom_tlv_size.sender_custom_tlvs.clone()) ); // If 1 byte is added to the custom TLV value, we'll fail to send prior to pathfinding. let mut recipient_onion_too_large_custom_tlv = recipient_onion_max_custom_tlv_size.clone(); - recipient_onion_too_large_custom_tlv.custom_tlvs[0].1.push(42); + recipient_onion_too_large_custom_tlv.sender_custom_tlvs[0].1.push(42); let err = nodes[1].node.send_payment(payment_hash, recipient_onion_too_large_custom_tlv.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap_err(); assert_eq!(err, RetryableSendFailure::OnionPacketSizeExceeded); @@ -340,7 +340,7 @@ fn blinded_path_with_custom_tlv() { // If we remove enough custom TLV bytes to allow for 1 intermediate unblinded hop, we're now able // to send nodes[0] -> nodes[3]. let mut recipient_onion_allows_2_hops = recipient_onion_max_custom_tlv_size.clone(); - recipient_onion_allows_2_hops.custom_tlvs[0].1.resize(max_custom_tlv_len - INTERMED_PAYLOAD_LEN_ESTIMATE, 0); + recipient_onion_allows_2_hops.sender_custom_tlvs[0].1.resize(max_custom_tlv_len - INTERMED_PAYLOAD_LEN_ESTIMATE, 0); nodes[0].node.send_payment(payment_hash, recipient_onion_allows_2_hops.clone(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap(); check_added_monitors(&nodes[0], 1); @@ -349,11 +349,11 @@ fn blinded_path_with_custom_tlv() { let path = &[&nodes[1], &nodes[2], &nodes[3]]; let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, events.pop().unwrap()) .with_payment_secret(payment_secret) - .with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs.clone()); + .with_sender_custom_tlvs(recipient_onion_allows_2_hops.sender_custom_tlvs.clone()); do_pass_along_path(args); claim_payment_along_route( ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1], &nodes[2], &nodes[3]]], payment_preimage) - .with_custom_tlvs(recipient_onion_allows_2_hops.custom_tlvs) + .with_sender_custom_tlvs(recipient_onion_allows_2_hops.sender_custom_tlvs) ); } diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 5f8d270a60f..c1854dfe16c 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -1815,7 +1815,7 @@ mod fuzzy_internal_msgs { pub payment_data: Option, pub payment_metadata: Option>, pub keysend_preimage: Option, - pub custom_tlvs: Vec<(u64, Vec)>, + pub sender_custom_tlvs: Vec<(u64, Vec)>, pub sender_intended_htlc_amt_msat: u64, pub cltv_expiry_height: u32, } @@ -1837,7 +1837,7 @@ mod fuzzy_internal_msgs { pub intro_node_blinding_point: Option, pub keysend_preimage: Option, pub invoice_request: Option, - pub custom_tlvs: Vec<(u64, Vec)>, + pub sender_custom_tlvs: Vec<(u64, Vec)>, } pub enum InboundOnionPayload { @@ -1864,7 +1864,7 @@ mod fuzzy_internal_msgs { payment_data: Option, payment_metadata: Option<&'a Vec>, keysend_preimage: Option, - custom_tlvs: &'a Vec<(u64, Vec)>, + sender_custom_tlvs: &'a Vec<(u64, Vec)>, sender_intended_htlc_amt_msat: u64, cltv_expiry_height: u32, }, @@ -1879,7 +1879,7 @@ mod fuzzy_internal_msgs { encrypted_tlvs: &'a Vec, intro_node_blinding_point: Option, // Set if the introduction node of the blinded path is the final node keysend_preimage: Option, - custom_tlvs: &'a Vec<(u64, Vec)>, + sender_custom_tlvs: &'a Vec<(u64, Vec)>, invoice_request: Option<&'a InvoiceRequest>, } } @@ -1915,7 +1915,7 @@ mod fuzzy_internal_msgs { encrypted_tlvs: &'a Vec, intro_node_blinding_point: Option, // Set if the introduction node of the blinded path is the final node keysend_preimage: Option, - custom_tlvs: &'a Vec<(u64, Vec)>, + sender_custom_tlvs: &'a Vec<(u64, Vec)>, } } @@ -2796,20 +2796,20 @@ impl<'a> Writeable for OutboundOnionPayload<'a> { }, Self::Receive { ref payment_data, ref payment_metadata, ref keysend_preimage, sender_intended_htlc_amt_msat, - cltv_expiry_height, ref custom_tlvs, + cltv_expiry_height, ref sender_custom_tlvs, } => { - // We need to update [`ln::outbound_payment::RecipientOnionFields::with_custom_tlvs`] + // We need to update [`ln::outbound_payment::RecipientOnionFields::with_sender_custom_tlvs`] // to reject any reserved types in the experimental range if new ones are ever // standardized. let keysend_tlv = keysend_preimage.map(|preimage| (5482373484, preimage.encode())); - let mut custom_tlvs: Vec<&(u64, Vec)> = custom_tlvs.iter().chain(keysend_tlv.iter()).collect(); - custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ); + let mut sender_custom_tlvs: Vec<&(u64, Vec)> = sender_custom_tlvs.iter().chain(keysend_tlv.iter()).collect(); + sender_custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ); _encode_varint_length_prefixed_tlv!(w, { (2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required), (4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required), (8, payment_data, option), (16, payment_metadata.map(|m| WithoutLength(m)), option) - }, custom_tlvs.iter()); + }, sender_custom_tlvs.iter()); }, Self::BlindedForward { encrypted_tlvs, intro_node_blinding_point } => { _encode_varint_length_prefixed_tlv!(w, { @@ -2819,25 +2819,25 @@ impl<'a> Writeable for OutboundOnionPayload<'a> { }, Self::BlindedReceive { sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs, - intro_node_blinding_point, keysend_preimage, ref invoice_request, ref custom_tlvs, + intro_node_blinding_point, keysend_preimage, ref invoice_request, ref sender_custom_tlvs, } => { - // We need to update [`ln::outbound_payment::RecipientOnionFields::with_custom_tlvs`] + // We need to update [`ln::outbound_payment::RecipientOnionFields::with_sender_custom_tlvs`] // to reject any reserved types in the experimental range if new ones are ever // standardized. let invoice_request_tlv = invoice_request.map(|invreq| (77_777, invreq.encode())); // TODO: update TLV type once the async payments spec is merged let keysend_tlv = keysend_preimage.map(|preimage| (5482373484, preimage.encode())); - let mut custom_tlvs: Vec<&(u64, Vec)> = custom_tlvs.iter() + let mut sender_custom_tlvs: Vec<&(u64, Vec)> = sender_custom_tlvs.iter() .chain(invoice_request_tlv.iter()) .chain(keysend_tlv.iter()) .collect(); - custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ); + sender_custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ); _encode_varint_length_prefixed_tlv!(w, { (2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required), (4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required), (10, **encrypted_tlvs, required_vec), (12, intro_node_blinding_point, option), (18, HighZeroBytesDroppedBigSize(*total_msat), required) - }, custom_tlvs.iter()); + }, sender_custom_tlvs.iter()); }, } Ok(()) @@ -2879,7 +2879,7 @@ impl<'a> Writeable for OutboundTrampolinePayload<'a> { (12, intro_node_blinding_point, option) }); }, - Self::BlindedReceive { sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs, intro_node_blinding_point, keysend_preimage, custom_tlvs } => { + Self::BlindedReceive { sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs, intro_node_blinding_point, keysend_preimage, sender_custom_tlvs } => { _encode_varint_length_prefixed_tlv!(w, { (2, HighZeroBytesDroppedBigSize(*sender_intended_htlc_amt_msat), required), (4, HighZeroBytesDroppedBigSize(*cltv_expiry_height), required), @@ -2887,7 +2887,7 @@ impl<'a> Writeable for OutboundTrampolinePayload<'a> { (12, intro_node_blinding_point, option), (18, HighZeroBytesDroppedBigSize(*total_msat), required), (20, keysend_preimage, option) - }, custom_tlvs.iter()); + }, sender_custom_tlvs.iter()); } } Ok(()) @@ -2933,6 +2933,8 @@ impl ReadableArgs<(Option, NS)> for InboundOnionPayload wh Ok(true) }); + let sender_custom_tlvs = custom_tlvs; + if amt.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) } if intro_node_blinding_point.is_some() && update_add_blinding_point.is_some() { return Err(DecodeError::InvalidValue) @@ -2987,7 +2989,7 @@ impl ReadableArgs<(Option, NS)> for InboundOnionPayload wh intro_node_blinding_point, keysend_preimage, invoice_request, - custom_tlvs, + sender_custom_tlvs, })) }, } @@ -3015,7 +3017,7 @@ impl ReadableArgs<(Option, NS)> for InboundOnionPayload wh keysend_preimage, sender_intended_htlc_amt_msat: amt.ok_or(DecodeError::InvalidValue)?, cltv_expiry_height: cltv_value.ok_or(DecodeError::InvalidValue)?, - custom_tlvs, + sender_custom_tlvs, })) } } @@ -4646,7 +4648,7 @@ mod tests { keysend_preimage: None, sender_intended_htlc_amt_msat: 0x0badf00d01020304, cltv_expiry_height: 0xffffffff, - custom_tlvs: &vec![], + sender_custom_tlvs: &vec![], }; let encoded_value = outbound_msg.encode(); let target_value = >::from_hex("1002080badf00d010203040404ffffffff").unwrap(); @@ -4674,7 +4676,7 @@ mod tests { keysend_preimage: None, sender_intended_htlc_amt_msat: 0x0badf00d01020304, cltv_expiry_height: 0xffffffff, - custom_tlvs: &vec![], + sender_custom_tlvs: &vec![], }; let encoded_value = outbound_msg.encode(); let target_value = >::from_hex("3602080badf00d010203040404ffffffff082442424242424242424242424242424242424242424242424242424242424242421badca1f").unwrap(); @@ -4690,18 +4692,18 @@ mod tests { sender_intended_htlc_amt_msat, cltv_expiry_height, payment_metadata: None, keysend_preimage: None, - custom_tlvs, + sender_custom_tlvs, }) = inbound_msg { assert_eq!(payment_secret, expected_payment_secret); assert_eq!(sender_intended_htlc_amt_msat, 0x0badf00d01020304); assert_eq!(cltv_expiry_height, 0xffffffff); - assert_eq!(custom_tlvs, vec![]); + assert_eq!(sender_custom_tlvs, vec![]); } else { panic!(); } } #[test] - fn encoding_final_onion_hop_data_with_bad_custom_tlvs() { - // If custom TLVs have type number within the range reserved for protocol, treat them as if + fn encoding_final_onion_hop_data_with_bad_sender_custom_tlvs() { + // If sender custom TLVs have type number within the range reserved for protocol, treat them as if // they're unknown let bad_type_range_tlvs = vec![ ((1 << 16) - 4, vec![42]), @@ -4711,7 +4713,7 @@ mod tests { payment_data: None, payment_metadata: None, keysend_preimage: None, - custom_tlvs: &bad_type_range_tlvs, + sender_custom_tlvs: &bad_type_range_tlvs, sender_intended_htlc_amt_msat: 0x0badf00d01020304, cltv_expiry_height: 0xffffffff, }; @@ -4722,20 +4724,20 @@ mod tests { ((1 << 16) - 3, vec![42]), ((1 << 16) - 1, vec![42; 32]), ]; - if let msgs::OutboundOnionPayload::Receive { ref mut custom_tlvs, .. } = msg { - *custom_tlvs = &good_type_range_tlvs; + if let msgs::OutboundOnionPayload::Receive { ref mut sender_custom_tlvs, .. } = msg { + *sender_custom_tlvs = &good_type_range_tlvs; } let encoded_value = msg.encode(); let inbound_msg = ReadableArgs::read(&mut Cursor::new(&encoded_value[..]), (None, &node_signer)).unwrap(); match inbound_msg { - msgs::InboundOnionPayload::Receive(InboundOnionReceivePayload { custom_tlvs, .. }) => assert!(custom_tlvs.is_empty()), + msgs::InboundOnionPayload::Receive(InboundOnionReceivePayload { sender_custom_tlvs, .. }) => assert!(sender_custom_tlvs.is_empty()), _ => panic!(), } } #[test] - fn encoding_final_onion_hop_data_with_custom_tlvs() { - let expected_custom_tlvs = vec![ + fn encoding_final_onion_hop_data_with_sender_custom_tlvs() { + let expected_sender_custom_tlvs = vec![ (5482373483, vec![0x12, 0x34]), (5482373487, vec![0x42u8; 8]), ]; @@ -4743,7 +4745,7 @@ mod tests { payment_data: None, payment_metadata: None, keysend_preimage: None, - custom_tlvs: &expected_custom_tlvs, + sender_custom_tlvs: &expected_sender_custom_tlvs, sender_intended_htlc_amt_msat: 0x0badf00d01020304, cltv_expiry_height: 0xffffffff, }; @@ -4756,12 +4758,12 @@ mod tests { payment_data: None, payment_metadata: None, keysend_preimage: None, - custom_tlvs, + sender_custom_tlvs, sender_intended_htlc_amt_msat, cltv_expiry_height: outgoing_cltv_value, .. }) = inbound_msg { - assert_eq!(custom_tlvs, expected_custom_tlvs); + assert_eq!(sender_custom_tlvs, expected_sender_custom_tlvs); assert_eq!(sender_intended_htlc_amt_msat, 0x0badf00d01020304); assert_eq!(outgoing_cltv_value, 0xffffffff); } else { panic!(); } @@ -4871,7 +4873,7 @@ mod tests { encrypted_tlvs: &>::from_hex("bcd747394fbd4d99588da075a623316e15a576df5bc785cccc7cd6ec7b398acce6faf520175f9ec920f2ef261cdb83dc28cc3a0eeb970107b3306489bf771ef5b1213bca811d345285405861d08a655b6c237fa247a8b4491beee20c878a60e9816492026d8feb9dafa84585b253978db6a0aa2945df5ef445c61e801fb82f43d5f00716baf9fc9b3de50bc22950a36bda8fc27bfb1242e5860c7e687438d4133e058770361a19b6c271a2a07788d34dccc27e39b9829b061a4d960eac4a2c2b0f4de506c24f9af3868c0aff6dda27281c").unwrap(), intro_node_blinding_point: None, keysend_preimage: None, - custom_tlvs: &vec![], + sender_custom_tlvs: &vec![], }; let eve_payload = trampoline_payload_eve.encode().to_lower_hex_string(); assert_eq!(eve_payload, "e4020408f0d18004030c35000ad1bcd747394fbd4d99588da075a623316e15a576df5bc785cccc7cd6ec7b398acce6faf520175f9ec920f2ef261cdb83dc28cc3a0eeb970107b3306489bf771ef5b1213bca811d345285405861d08a655b6c237fa247a8b4491beee20c878a60e9816492026d8feb9dafa84585b253978db6a0aa2945df5ef445c61e801fb82f43d5f00716baf9fc9b3de50bc22950a36bda8fc27bfb1242e5860c7e687438d4133e058770361a19b6c271a2a07788d34dccc27e39b9829b061a4d960eac4a2c2b0f4de506c24f9af3868c0aff6dda27281c120408f0d180"); diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs index e3505e536de..c6deab524d0 100644 --- a/lightning/src/ln/onion_payment.rs +++ b/lightning/src/ln/onion_payment.rs @@ -135,20 +135,20 @@ pub(super) fn create_recv_pending_htlc_info( counterparty_skimmed_fee_msat: Option, current_height: u32 ) -> Result { let ( - payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, onion_cltv_expiry, + payment_data, keysend_preimage, sender_custom_tlvs, onion_amt_msat, onion_cltv_expiry, payment_metadata, payment_context, requires_blinded_error, has_recipient_created_payment_secret, invoice_request ) = match hop_data { msgs::InboundOnionPayload::Receive(msgs::InboundOnionReceivePayload { - payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat, + payment_data, keysend_preimage, sender_custom_tlvs, sender_intended_htlc_amt_msat, cltv_expiry_height, payment_metadata, .. }) => - (payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat, + (payment_data, keysend_preimage, sender_custom_tlvs, sender_intended_htlc_amt_msat, cltv_expiry_height, payment_metadata, None, false, keysend_preimage.is_none(), None), msgs::InboundOnionPayload::BlindedReceive(msgs::InboundOnionBlindedReceivePayload { sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret, intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage, - custom_tlvs, invoice_request + sender_custom_tlvs, invoice_request }) => { check_blinded_payment_constraints( sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints @@ -161,7 +161,7 @@ pub(super) fn create_recv_pending_htlc_info( } })?; let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat }; - (Some(payment_data), keysend_preimage, custom_tlvs, + (Some(payment_data), keysend_preimage, sender_custom_tlvs, sender_intended_htlc_amt_msat, cltv_expiry_height, None, Some(payment_context), intro_node_blinding_point.is_none(), true, invoice_request) } @@ -234,7 +234,7 @@ pub(super) fn create_recv_pending_htlc_info( payment_preimage, payment_metadata, incoming_cltv_expiry: onion_cltv_expiry, - custom_tlvs, + sender_custom_tlvs, requires_blinded_error, has_recipient_created_payment_secret, payment_context, @@ -247,7 +247,7 @@ pub(super) fn create_recv_pending_htlc_info( payment_context, incoming_cltv_expiry: onion_cltv_expiry, phantom_shared_secret, - custom_tlvs, + sender_custom_tlvs, requires_blinded_error, } } else { @@ -532,7 +532,7 @@ mod tests { ) = payment_onion_args(bob_pk, charlie_pk); // Ensure the onion will not fit all the payloads by adding a large custom TLV. - recipient_onion.custom_tlvs.push((13377331, vec![0; 1156])); + recipient_onion.sender_custom_tlvs.push((13377331, vec![0; 1156])); let path = Path { hops, blinded_tail: None, }; let onion_keys = super::onion_utils::construct_onion_keys(&secp_ctx, &path, &session_priv).unwrap(); diff --git a/lightning/src/ln/onion_route_tests.rs b/lightning/src/ln/onion_route_tests.rs index cee8bd1d301..f73a8b87cc8 100644 --- a/lightning/src/ln/onion_route_tests.rs +++ b/lightning/src/ln/onion_route_tests.rs @@ -1191,7 +1191,7 @@ fn test_trampoline_onion_payload_construction_vectors() { encrypted_tlvs: &>::from_hex("bcd747394fbd4d99588da075a623316e15a576df5bc785cccc7cd6ec7b398acce6faf520175f9ec920f2ef261cdb83dc28cc3a0eeb970107b3306489bf771ef5b1213bca811d345285405861d08a655b6c237fa247a8b4491beee20c878a60e9816492026d8feb9dafa84585b253978db6a0aa2945df5ef445c61e801fb82f43d5f00716baf9fc9b3de50bc22950a36bda8fc27bfb1242e5860c7e687438d4133e058770361a19b6c271a2a07788d34dccc27e39b9829b061a4d960eac4a2c2b0f4de506c24f9af3868c0aff6dda27281c").unwrap(), intro_node_blinding_point: None, keysend_preimage: None, - custom_tlvs: &vec![], + sender_custom_tlvs: &vec![], }; let eve_payload = trampoline_payload_eve.encode().to_lower_hex_string(); assert_eq!(eve_payload, "e4020408f0d18004030c35000ad1bcd747394fbd4d99588da075a623316e15a576df5bc785cccc7cd6ec7b398acce6faf520175f9ec920f2ef261cdb83dc28cc3a0eeb970107b3306489bf771ef5b1213bca811d345285405861d08a655b6c237fa247a8b4491beee20c878a60e9816492026d8feb9dafa84585b253978db6a0aa2945df5ef445c61e801fb82f43d5f00716baf9fc9b3de50bc22950a36bda8fc27bfb1242e5860c7e687438d4133e058770361a19b6c271a2a07788d34dccc27e39b9829b061a4d960eac4a2c2b0f4de506c24f9af3868c0aff6dda27281c120408f0d180"); diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index 35de2403441..395cee341b0 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -205,7 +205,7 @@ impl<'a, 'b> OnionPayload<'a, 'b> for msgs::OutboundOnionPayload<'a> { .map(|payment_secret| msgs::FinalOnionHopData { payment_secret, total_msat }), payment_metadata: recipient_onion.payment_metadata.as_ref(), keysend_preimage, - custom_tlvs: &recipient_onion.custom_tlvs, + sender_custom_tlvs: &recipient_onion.sender_custom_tlvs, sender_intended_htlc_amt_msat, cltv_expiry_height, }) @@ -219,7 +219,7 @@ impl<'a, 'b> OnionPayload<'a, 'b> for msgs::OutboundOnionPayload<'a> { sender_intended_htlc_amt_msat: u64, total_msat: u64, cltv_expiry_height: u32, encrypted_tlvs: &'a Vec, intro_node_blinding_point: Option, keysend_preimage: Option, invoice_request: Option<&'a InvoiceRequest>, - custom_tlvs: &'a Vec<(u64, Vec)>, + sender_custom_tlvs: &'a Vec<(u64, Vec)>, ) -> Self { Self::BlindedReceive { sender_intended_htlc_amt_msat, @@ -229,7 +229,7 @@ impl<'a, 'b> OnionPayload<'a, 'b> for msgs::OutboundOnionPayload<'a> { intro_node_blinding_point, keysend_preimage, invoice_request, - custom_tlvs, + sender_custom_tlvs, } } @@ -272,7 +272,7 @@ impl<'a, 'b> OnionPayload<'a, 'b> for msgs::OutboundTrampolinePayload<'a> { sender_intended_htlc_amt_msat: u64, total_msat: u64, cltv_expiry_height: u32, encrypted_tlvs: &'a Vec, intro_node_blinding_point: Option, keysend_preimage: Option, _invoice_request: Option<&'a InvoiceRequest>, - custom_tlvs: &'a Vec<(u64, Vec)>, + sender_custom_tlvs: &'a Vec<(u64, Vec)>, ) -> Self { Self::BlindedReceive { sender_intended_htlc_amt_msat, @@ -281,7 +281,7 @@ impl<'a, 'b> OnionPayload<'a, 'b> for msgs::OutboundTrampolinePayload<'a> { encrypted_tlvs, intro_node_blinding_point, keysend_preimage, - custom_tlvs, + sender_custom_tlvs, } } @@ -539,7 +539,7 @@ where blinding_point.take(), *keysend_preimage, invoice_request, - &recipient_onion.custom_tlvs, + &recipient_onion.sender_custom_tlvs, ), ); } else { diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index eb57c8a94c4..df712b4a9e5 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -104,7 +104,7 @@ pub(crate) enum PendingOutboundPayment { payment_metadata: Option>, keysend_preimage: Option, invoice_request: Option, - custom_tlvs: Vec<(u64, Vec)>, + sender_custom_tlvs: Vec<(u64, Vec)>, pending_amt_msat: u64, /// Used to track the fee paid. Present iff the payment was serialized on 0.0.103+. pending_fee_msat: Option, @@ -493,7 +493,7 @@ pub enum RetryableSendFailure { /// [`Event::PaymentSent`]: crate::events::Event::PaymentSent /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed DuplicatePayment, - /// The [`RecipientOnionFields::payment_metadata`], [`RecipientOnionFields::custom_tlvs`], or + /// The [`RecipientOnionFields::payment_metadata`], [`RecipientOnionFields::sender_custom_tlvs`], or /// [`BlindedPaymentPath`]s provided are too large and caused us to exceed the maximum onion /// packet size of 1300 bytes. /// @@ -650,13 +650,13 @@ pub struct RecipientOnionFields { /// [`Self::payment_secret`] and while nearly all lightning senders support secrets, metadata /// may not be supported as universally. pub payment_metadata: Option>, - /// See [`Self::custom_tlvs`] for more info. - pub(super) custom_tlvs: Vec<(u64, Vec)>, + /// See [`Self::sender_custom_tlvs`] for more info. + pub(super) sender_custom_tlvs: Vec<(u64, Vec)>, } impl_writeable_tlv_based!(RecipientOnionFields, { (0, payment_secret, option), - (1, custom_tlvs, optional_vec), + (1, sender_custom_tlvs, optional_vec), (2, payment_metadata, option), }); @@ -665,7 +665,7 @@ impl RecipientOnionFields { /// set of onion fields for today's BOLT11 invoices - most nodes require a [`PaymentSecret`] /// but do not require or provide any further data. pub fn secret_only(payment_secret: PaymentSecret) -> Self { - Self { payment_secret: Some(payment_secret), payment_metadata: None, custom_tlvs: Vec::new() } + Self { payment_secret: Some(payment_secret), payment_metadata: None, sender_custom_tlvs: Vec::new() } } /// Creates a new [`RecipientOnionFields`] with no fields. This generally does not create @@ -677,10 +677,10 @@ impl RecipientOnionFields { /// [`ChannelManager::send_spontaneous_payment`]: super::channelmanager::ChannelManager::send_spontaneous_payment /// [`RecipientOnionFields::secret_only`]: RecipientOnionFields::secret_only pub fn spontaneous_empty() -> Self { - Self { payment_secret: None, payment_metadata: None, custom_tlvs: Vec::new() } + Self { payment_secret: None, payment_metadata: None, sender_custom_tlvs: Vec::new() } } - /// Creates a new [`RecipientOnionFields`] from an existing one, adding custom TLVs. Each + /// Creates a new [`RecipientOnionFields`] from an existing one, adding sender custom TLVs. Each /// TLV is provided as a `(u64, Vec)` for the type number and serialized value /// respectively. TLV type numbers must be unique and within the range /// reserved for custom types, i.e. >= 2^16, otherwise this method will return `Err(())`. @@ -688,11 +688,11 @@ impl RecipientOnionFields { /// This method will also error for types in the experimental range which have been /// standardized within the protocol, which only includes 5482373484 (keysend) for now. /// - /// See [`Self::custom_tlvs`] for more info. - pub fn with_custom_tlvs(mut self, mut custom_tlvs: Vec<(u64, Vec)>) -> Result { - custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ); + /// See [`Self::sender_custom_tlvs`] for more info. + pub fn with_sender_custom_tlvs(mut self, mut sender_custom_tlvs: Vec<(u64, Vec)>) -> Result { + sender_custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ); let mut prev_type = None; - for (typ, _) in custom_tlvs.iter() { + for (typ, _) in sender_custom_tlvs.iter() { if *typ < 1 << 16 { return Err(()); } if *typ == 5482373484 { return Err(()); } // keysend if *typ == 77_777 { return Err(()); } // invoice requests for async payments @@ -702,38 +702,38 @@ impl RecipientOnionFields { } prev_type = Some(*typ); } - self.custom_tlvs = custom_tlvs; + self.sender_custom_tlvs = sender_custom_tlvs; Ok(self) } - /// Gets the custom TLVs that will be sent or have been received. + /// Gets the sender custom TLVs that will be sent or have been received. /// - /// Custom TLVs allow sending extra application-specific data with a payment. They provide + /// Sender custom TLVs allow sending extra application-specific data with a payment. They provide /// additional flexibility on top of payment metadata, as while other implementations may - /// require `payment_metadata` to reflect metadata provided in an invoice, custom TLVs + /// require `payment_metadata` to reflect metadata provided in an invoice, sender custom TLVs /// do not have this restriction. /// /// Note that if this field is non-empty, it will contain strictly increasing TLVs, each /// represented by a `(u64, Vec)` for its type number and serialized value respectively. - /// This is validated when setting this field using [`Self::with_custom_tlvs`]. + /// This is validated when setting this field using [`Self::with_sender_custom_tlvs`]. #[cfg(not(c_bindings))] - pub fn custom_tlvs(&self) -> &Vec<(u64, Vec)> { - &self.custom_tlvs + pub fn sender_custom_tlvs(&self) -> &Vec<(u64, Vec)> { + &self.sender_custom_tlvs } - /// Gets the custom TLVs that will be sent or have been received. + /// Gets the sender custom TLVs that will be sent or have been received. /// - /// Custom TLVs allow sending extra application-specific data with a payment. They provide + /// Sender custom TLVs allow sending extra application-specific data with a payment. They provide /// additional flexibility on top of payment metadata, as while other implementations may - /// require `payment_metadata` to reflect metadata provided in an invoice, custom TLVs + /// require `payment_metadata` to reflect metadata provided in an invoice, sender custom TLVs /// do not have this restriction. /// /// Note that if this field is non-empty, it will contain strictly increasing TLVs, each /// represented by a `(u64, Vec)` for its type number and serialized value respectively. - /// This is validated when setting this field using [`Self::with_custom_tlvs`]. + /// This is validated when setting this field using [`Self::with_sender_custom_tlvs`]. #[cfg(c_bindings)] - pub fn custom_tlvs(&self) -> Vec<(u64, Vec)> { - self.custom_tlvs.clone() + pub fn sender_custom_tlvs(&self) -> Vec<(u64, Vec)> { + self.sender_custom_tlvs.clone() } /// When we have received some HTLC(s) towards an MPP payment, as we receive further HTLC(s) we @@ -747,8 +747,8 @@ impl RecipientOnionFields { if self.payment_secret != further_htlc_fields.payment_secret { return Err(()); } if self.payment_metadata != further_htlc_fields.payment_metadata { return Err(()); } - let tlvs = &mut self.custom_tlvs; - let further_tlvs = &mut further_htlc_fields.custom_tlvs; + let tlvs = &mut self.sender_custom_tlvs; + let further_tlvs = &mut further_htlc_fields.sender_custom_tlvs; let even_tlvs = tlvs.iter().filter(|(typ, _)| *typ % 2 == 0); let further_even_tlvs = further_tlvs.iter().filter(|(typ, _)| *typ % 2 == 0); @@ -943,7 +943,7 @@ impl OutboundPayments { let recipient_onion = RecipientOnionFields { payment_secret: None, payment_metadata: None, - custom_tlvs: vec![], + sender_custom_tlvs: vec![], }; let route = match self.find_initial_route( payment_id, payment_hash, &recipient_onion, keysend_preimage, invoice_request, @@ -1369,7 +1369,7 @@ impl OutboundPayments { match payment.get() { PendingOutboundPayment::Retryable { total_msat, keysend_preimage, payment_secret, payment_metadata, - custom_tlvs, pending_amt_msat, invoice_request, .. + sender_custom_tlvs, pending_amt_msat, invoice_request, .. } => { const RETRY_OVERFLOW_PERCENTAGE: u64 = 10; let retry_amt_msat = route.get_total_amount(); @@ -1389,7 +1389,7 @@ impl OutboundPayments { let recipient_onion = RecipientOnionFields { payment_secret: *payment_secret, payment_metadata: payment_metadata.clone(), - custom_tlvs: custom_tlvs.clone(), + sender_custom_tlvs: sender_custom_tlvs.clone(), }; let keysend_preimage = *keysend_preimage; let invoice_request = invoice_request.clone(); @@ -1693,7 +1693,7 @@ impl OutboundPayments { payment_metadata: recipient_onion.payment_metadata, keysend_preimage, invoice_request, - custom_tlvs: recipient_onion.custom_tlvs, + sender_custom_tlvs: recipient_onion.sender_custom_tlvs, starting_block_height: best_block_height, total_msat: route.get_total_amount(), remaining_max_total_routing_fee_msat: @@ -2310,7 +2310,7 @@ impl OutboundPayments { payment_metadata: None, // only used for retries, and we'll never retry on startup keysend_preimage: None, // only used for retries, and we'll never retry on startup invoice_request: None, // only used for retries, and we'll never retry on startup - custom_tlvs: Vec::new(), // only used for retries, and we'll never retry on startup + sender_custom_tlvs: Vec::new(), // only used for retries, and we'll never retry on startup pending_amt_msat: path_amt, pending_fee_msat: Some(path_fee), total_msat: path_amt, @@ -2395,7 +2395,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, (6, total_msat, required), (7, payment_metadata, option), (8, pending_amt_msat, required), - (9, custom_tlvs, optional_vec), + (9, sender_custom_tlvs, optional_vec), (10, starting_block_height, required), (11, remaining_max_total_routing_fee_msat, option), (13, invoice_request, option), @@ -2468,25 +2468,25 @@ mod tests { use alloc::collections::VecDeque; #[test] - fn test_recipient_onion_fields_with_custom_tlvs() { + fn test_recipient_onion_fields_with_sender_custom_tlvs() { let onion_fields = RecipientOnionFields::spontaneous_empty(); let bad_type_range_tlvs = vec![ (0, vec![42]), (1, vec![42; 32]), ]; - assert!(onion_fields.clone().with_custom_tlvs(bad_type_range_tlvs).is_err()); + assert!(onion_fields.clone().with_sender_custom_tlvs(bad_type_range_tlvs).is_err()); let keysend_tlv = vec![ (5482373484, vec![42; 32]), ]; - assert!(onion_fields.clone().with_custom_tlvs(keysend_tlv).is_err()); + assert!(onion_fields.clone().with_sender_custom_tlvs(keysend_tlv).is_err()); let good_tlvs = vec![ ((1 << 16) + 1, vec![42]), ((1 << 16) + 3, vec![42; 32]), ]; - assert!(onion_fields.with_custom_tlvs(good_tlvs).is_ok()); + assert!(onion_fields.with_sender_custom_tlvs(good_tlvs).is_ok()); } #[test] diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index 66322cf107e..3c297788d38 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -3690,20 +3690,20 @@ fn claim_from_closed_chan() { } #[test] -fn test_custom_tlvs_basic() { - do_test_custom_tlvs(false, false, false); - do_test_custom_tlvs(true, false, false); +fn test_sender_custom_tlvs_basic() { + do_test_sender_custom_tlvs(false, false, false); + do_test_sender_custom_tlvs(true, false, false); } #[test] -fn test_custom_tlvs_explicit_claim() { - // Test that when receiving even custom TLVs the user must explicitly accept in case they +fn test_sender_custom_tlvs_explicit_claim() { + // Test that when receiving even sender custom TLVs the user must explicitly accept in case they // are unknown. - do_test_custom_tlvs(false, true, false); - do_test_custom_tlvs(false, true, true); + do_test_sender_custom_tlvs(false, true, false); + do_test_sender_custom_tlvs(false, true, true); } -fn do_test_custom_tlvs(spontaneous: bool, even_tlvs: bool, known_tlvs: bool) { +fn do_test_sender_custom_tlvs(spontaneous: bool, even_tlvs: bool, known_tlvs: bool) { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None; 2]); @@ -3714,14 +3714,14 @@ fn do_test_custom_tlvs(spontaneous: bool, even_tlvs: bool, known_tlvs: bool) { let amt_msat = 100_000; let (mut route, our_payment_hash, our_payment_preimage, our_payment_secret) = get_route_and_payment_hash!(&nodes[0], &nodes[1], amt_msat); let payment_id = PaymentId(our_payment_hash.0); - let custom_tlvs = vec![ + let sender_custom_tlvs = vec![ (if even_tlvs { 5482373482 } else { 5482373483 }, vec![1, 2, 3, 4]), (5482373487, vec![0x42u8; 16]), ]; let onion_fields = RecipientOnionFields { payment_secret: if spontaneous { None } else { Some(our_payment_secret) }, payment_metadata: None, - custom_tlvs: custom_tlvs.clone() + sender_custom_tlvs: sender_custom_tlvs.clone() }; if spontaneous { nodes[0].node.send_spontaneous_payment( @@ -3746,24 +3746,24 @@ fn do_test_custom_tlvs(spontaneous: bool, even_tlvs: bool, known_tlvs: bool) { assert_eq!(events.len(), 1); match events[0] { Event::PaymentClaimable { ref onion_fields, .. } => { - assert_eq!(onion_fields.clone().unwrap().custom_tlvs().clone(), custom_tlvs); + assert_eq!(onion_fields.clone().unwrap().sender_custom_tlvs().clone(), sender_custom_tlvs); }, _ => panic!("Unexpected event"), } match (known_tlvs, even_tlvs) { (true, _) => { - nodes[1].node.claim_funds_with_known_custom_tlvs(our_payment_preimage); + nodes[1].node.claim_funds_with_known_sender_custom_tlvs(our_payment_preimage); let expected_total_fee_msat = pass_claimed_payment_along_route( ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1]]], our_payment_preimage) - .with_custom_tlvs(custom_tlvs) + .with_sender_custom_tlvs(sender_custom_tlvs) ); expect_payment_sent!(&nodes[0], our_payment_preimage, Some(expected_total_fee_msat)); }, (false, false) => { claim_payment_along_route( ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1]]], our_payment_preimage) - .with_custom_tlvs(custom_tlvs) + .with_sender_custom_tlvs(sender_custom_tlvs) ); }, (false, true) => { @@ -3776,8 +3776,8 @@ fn do_test_custom_tlvs(spontaneous: bool, even_tlvs: bool, known_tlvs: bool) { } #[test] -fn test_retry_custom_tlvs() { - // Test that custom TLVs are successfully sent on retries +fn test_retry_sender_custom_tlvs() { + // Test that sender custom TLVs are successfully sent on retries let chanmon_cfgs = create_chanmon_cfgs(3); let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); @@ -3797,9 +3797,9 @@ fn test_retry_custom_tlvs() { let payment_id = PaymentId(payment_hash.0); let mut route_params = route.route_params.clone().unwrap(); - let custom_tlvs = vec![((1 << 16) + 1, vec![0x42u8; 16])]; + let sender_custom_tlvs = vec![((1 << 16) + 1, vec![0x42u8; 16])]; let onion_fields = RecipientOnionFields::secret_only(payment_secret); - let onion_fields = onion_fields.with_custom_tlvs(custom_tlvs.clone()).unwrap(); + let onion_fields = onion_fields.with_sender_custom_tlvs(sender_custom_tlvs.clone()).unwrap(); nodes[0].router.expect_find_route(route_params.clone(), Ok(route.clone())); nodes[0].node.send_payment(payment_hash, onion_fields, @@ -3851,16 +3851,16 @@ fn test_retry_custom_tlvs() { let path = &[&nodes[1], &nodes[2]]; let args = PassAlongPathArgs::new(&nodes[0], path, 1_000_000, payment_hash, events.pop().unwrap()) .with_payment_secret(payment_secret) - .with_custom_tlvs(custom_tlvs.clone()); + .with_sender_custom_tlvs(sender_custom_tlvs.clone()); do_pass_along_path(args); claim_payment_along_route( ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1], &nodes[2]]], payment_preimage) - .with_custom_tlvs(custom_tlvs) + .with_sender_custom_tlvs(sender_custom_tlvs) ); } #[test] -fn test_custom_tlvs_consistency() { +fn test_sender_custom_tlvs_consistency() { let even_type_1 = 1 << 16; let odd_type_1 = (1 << 16)+ 1; let even_type_2 = (1 << 16) + 2; @@ -3870,32 +3870,32 @@ fn test_custom_tlvs_consistency() { let value_2 = || vec![42u8; 16]; // Drop missing odd tlvs - do_test_custom_tlvs_consistency( + do_test_sender_custom_tlvs_consistency( vec![(odd_type_1, value_1()), (odd_type_2, value_2())], vec![(odd_type_1, value_1())], Some(vec![(odd_type_1, value_1())]), ); // Drop non-matching odd tlvs - do_test_custom_tlvs_consistency( + do_test_sender_custom_tlvs_consistency( vec![(odd_type_1, value_1()), (odd_type_2, value_2())], vec![(odd_type_1, differing_value_1()), (odd_type_2, value_2())], Some(vec![(odd_type_2, value_2())]), ); // Fail missing even tlvs - do_test_custom_tlvs_consistency( + do_test_sender_custom_tlvs_consistency( vec![(odd_type_1, value_1()), (even_type_2, value_2())], vec![(odd_type_1, value_1())], None, ); // Fail non-matching even tlvs - do_test_custom_tlvs_consistency( + do_test_sender_custom_tlvs_consistency( vec![(even_type_1, value_1()), (odd_type_2, value_2())], vec![(even_type_1, differing_value_1()), (odd_type_2, value_2())], None, ); } -fn do_test_custom_tlvs_consistency(first_tlvs: Vec<(u64, Vec)>, second_tlvs: Vec<(u64, Vec)>, +fn do_test_sender_custom_tlvs_consistency(first_tlvs: Vec<(u64, Vec)>, second_tlvs: Vec<(u64, Vec)>, expected_receive_tlvs: Option)>>) { let chanmon_cfgs = create_chanmon_cfgs(4); @@ -3926,7 +3926,7 @@ fn do_test_custom_tlvs_consistency(first_tlvs: Vec<(u64, Vec)>, second_tlvs: let onion_fields = RecipientOnionFields { payment_secret: Some(our_payment_secret), payment_metadata: None, - custom_tlvs: first_tlvs + sender_custom_tlvs: first_tlvs }; let session_privs = nodes[0].node.test_add_new_pending_payment(our_payment_hash, onion_fields.clone(), payment_id, &route).unwrap(); @@ -3948,7 +3948,7 @@ fn do_test_custom_tlvs_consistency(first_tlvs: Vec<(u64, Vec)>, second_tlvs: let onion_fields = RecipientOnionFields { payment_secret: Some(our_payment_secret), payment_metadata: None, - custom_tlvs: second_tlvs + sender_custom_tlvs: second_tlvs }; nodes[0].node.test_send_payment_along_path(&route.paths[1], &our_payment_hash, onion_fields.clone(), amt_msat, cur_height, payment_id, &None, session_privs[1]).unwrap(); @@ -3982,14 +3982,14 @@ fn do_test_custom_tlvs_consistency(first_tlvs: Vec<(u64, Vec)>, second_tlvs: assert_eq!(events.len(), 1); match events[0] { Event::PaymentClaimable { ref onion_fields, .. } => { - assert_eq!(onion_fields.clone().unwrap().custom_tlvs, expected_tlvs); + assert_eq!(onion_fields.clone().unwrap().sender_custom_tlvs, expected_tlvs); }, _ => panic!("Unexpected event"), } do_claim_payment_along_route( ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1], &nodes[3]], &[&nodes[2], &nodes[3]]], our_payment_preimage) - .with_custom_tlvs(expected_tlvs) + .with_sender_custom_tlvs(expected_tlvs) ); expect_payment_sent(&nodes[0], our_payment_preimage, Some(Some(2000)), true, true); } else { @@ -4054,7 +4054,7 @@ fn do_test_payment_metadata_consistency(do_reload: bool, do_modify: bool) { // Send the MPP payment, delivering the updated commitment state to nodes[1]. nodes[0].node.send_payment(payment_hash, RecipientOnionFields { - payment_secret: Some(payment_secret), payment_metadata: Some(payment_metadata), custom_tlvs: vec![], + payment_secret: Some(payment_secret), payment_metadata: Some(payment_metadata), sender_custom_tlvs: vec![], }, payment_id, route_params.clone(), Retry::Attempts(1)).unwrap(); check_added_monitors!(nodes[0], 2); @@ -4267,7 +4267,7 @@ fn test_htlc_forward_considers_anchor_outputs_value() { } #[test] -fn peel_payment_onion_custom_tlvs() { +fn peel_payment_onion_sender_custom_tlvs() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); @@ -4281,7 +4281,7 @@ fn peel_payment_onion_custom_tlvs() { let route_params = RouteParameters::from_payment_params_and_value(payment_params, amt_msat); let route = functional_test_utils::get_route(&nodes[0], &route_params).unwrap(); let mut recipient_onion = RecipientOnionFields::spontaneous_empty() - .with_custom_tlvs(vec![(414141, vec![42; 1200])]).unwrap(); + .with_sender_custom_tlvs(vec![(414141, vec![42; 1200])]).unwrap(); let prng_seed = chanmon_cfgs[0].keys_manager.get_secure_random_bytes(); let session_priv = SecretKey::from_slice(&prng_seed[..]).expect("RNG is busted"); let keysend_preimage = PaymentPreimage([42; 32]); @@ -4309,12 +4309,12 @@ fn peel_payment_onion_custom_tlvs() { assert_eq!(peeled_onion.incoming_amt_msat, Some(amt_msat)); match peeled_onion.routing { PendingHTLCRouting::ReceiveKeysend { - payment_data, payment_metadata, custom_tlvs, .. + payment_data, payment_metadata, sender_custom_tlvs, .. } => { #[cfg(not(c_bindings))] - assert_eq!(&custom_tlvs, recipient_onion.custom_tlvs()); + assert_eq!(&sender_custom_tlvs, recipient_onion.sender_custom_tlvs()); #[cfg(c_bindings)] - assert_eq!(custom_tlvs, recipient_onion.custom_tlvs()); + assert_eq!(sender_custom_tlvs, recipient_onion.sender_custom_tlvs()); assert!(payment_metadata.is_none()); assert!(payment_data.is_none()); }, diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 59e4dc7decd..a30ccb56ceb 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -737,7 +737,7 @@ const DEFAULT_MAX_CHANNEL_SATURATION_POW_HALF: u8 = 2; const MEDIAN_HOP_CLTV_EXPIRY_DELTA: u32 = 40; /// Estimated maximum number of hops that can be included in a payment path. May be inaccurate if -/// payment metadata, custom TLVs, or blinded paths are included in the payment. +/// payment metadata, sender custom TLVs, or blinded paths are included in the payment. // During routing, we only consider paths shorter than our maximum length estimate. // In the TLV onion format, there is no fixed maximum length, but the `hop_payloads` // field is always 1300 bytes. As the `tlv_payload` for each hop may vary in length, we have to From f4f5dd4f90b003e5601c993acc83e24d89b55f4e Mon Sep 17 00:00:00 2001 From: shaavan Date: Wed, 15 Jan 2025 20:50:41 +0530 Subject: [PATCH 08/10] Introduce user_custom_data --- lightning/src/ln/channelmanager.rs | 26 ++++++++--- lightning/src/ln/functional_test_utils.rs | 15 +++++-- .../src/ln/max_payment_path_len_tests.rs | 4 +- lightning/src/ln/msgs.rs | 12 ++--- lightning/src/ln/onion_payment.rs | 10 +++-- lightning/src/ln/outbound_payment.rs | 44 ++++++++++++++++--- lightning/src/ln/payment_tests.rs | 12 +++-- 7 files changed, 94 insertions(+), 29 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 39f527bcd6c..c5f0ed2e129 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -222,6 +222,12 @@ pub enum PendingHTLCRouting { /// [`Event::PaymentClaimable::onion_fields`] as /// [`RecipientOnionFields::sender_custom_tlvs`]. sender_custom_tlvs: Vec<(u64, Vec)>, + /// Custom TLVs set by the receiver in the blinded path used to reach them. + /// + /// For HTLCs received by LDK, this will be exposed in + /// [`Event::PaymentClaimable::onion_fields`] as + /// [`RecipientOnionFields::user_custom_data`]. + user_custom_data: Option>, /// Set if this HTLC is the final hop in a multi-hop blinded path. requires_blinded_error: bool, }, @@ -252,6 +258,11 @@ pub enum PendingHTLCRouting { /// For HTLCs received by LDK, these will ultimately bubble back up as /// [`RecipientOnionFields::sender_custom_tlvs`]. sender_custom_tlvs: Vec<(u64, Vec)>, + /// Custom TLVs set by the receiver in the blinded path used to reach them. + /// + /// For HTLCs received by LDK, these will ultimately bubble back up as + /// [`RecipientOnionFields::user_custom_data`]. + user_custom_data: Option>, /// Set if this HTLC is the final hop in a multi-hop blinded path. requires_blinded_error: bool, /// Set if we are receiving a keysend to a blinded path, meaning we created the @@ -6119,24 +6130,25 @@ where PendingHTLCRouting::Receive { payment_data, payment_metadata, payment_context, incoming_cltv_expiry, phantom_shared_secret, sender_custom_tlvs, - requires_blinded_error: _ + user_custom_data, requires_blinded_error: _ } => { let _legacy_hop_data = Some(payment_data.clone()); let onion_fields = RecipientOnionFields { payment_secret: Some(payment_data.payment_secret), - payment_metadata, sender_custom_tlvs }; + payment_metadata, sender_custom_tlvs, user_custom_data }; (incoming_cltv_expiry, OnionPayload::Invoice { _legacy_hop_data }, Some(payment_data), payment_context, phantom_shared_secret, onion_fields, true, None) }, PendingHTLCRouting::ReceiveKeysend { payment_data, payment_preimage, payment_metadata, - incoming_cltv_expiry, sender_custom_tlvs, requires_blinded_error: _, - has_recipient_created_payment_secret, payment_context, invoice_request, + incoming_cltv_expiry, sender_custom_tlvs, user_custom_data, + requires_blinded_error: _, has_recipient_created_payment_secret, payment_context, invoice_request, } => { let onion_fields = RecipientOnionFields { payment_secret: payment_data.as_ref().map(|data| data.payment_secret), payment_metadata, sender_custom_tlvs, + user_custom_data }; (incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage), payment_data, payment_context, None, onion_fields, @@ -10645,7 +10657,7 @@ where /// [`Router::create_blinded_payment_paths`]. fn create_blinded_payment_paths( &self, amount_msats: Option, payment_secret: PaymentSecret, payment_context: PaymentContext, - relative_expiry_seconds: u32 + relative_expiry_seconds: u32, ) -> Result, ()> { let expanded_key = &self.inbound_payment_key; let entropy = &*self.entropy_source; @@ -12603,6 +12615,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, (5, sender_custom_tlvs, optional_vec), (7, requires_blinded_error, (default_value, false)), (9, payment_context, option), + (11, user_custom_data, option), }, (2, ReceiveKeysend) => { (0, payment_preimage, required), @@ -12614,6 +12627,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, (7, has_recipient_created_payment_secret, (default_value, false)), (9, payment_context, option), (11, invoice_request, option), + (13, user_custom_data, option), }, ); #[cfg(trampoline)] @@ -12632,6 +12646,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, (5, sender_custom_tlvs, optional_vec), (7, requires_blinded_error, (default_value, false)), (9, payment_context, option), + (11, user_custom_data, option), }, (2, ReceiveKeysend) => { (0, payment_preimage, required), @@ -12643,6 +12658,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, (7, has_recipient_created_payment_secret, (default_value, false)), (9, payment_context, option), (11, invoice_request, option), + (13, user_custom_data, option), }, (3, TrampolineForward) => { (0, incoming_shared_secret, required), diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 7e449dbb633..78e27f5438e 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -2659,6 +2659,7 @@ pub struct PassAlongPathArgs<'a, 'b, 'c, 'd> { pub expected_preimage: Option, pub is_probe: bool, pub sender_custom_tlvs: Vec<(u64, Vec)>, + pub user_custom_data: Option>, pub payment_metadata: Option>, pub expected_failure: Option, } @@ -2671,7 +2672,7 @@ impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> { Self { origin_node, expected_path, recv_value, payment_hash, payment_secret: None, event, payment_claimable_expected: true, clear_recipient_events: true, expected_preimage: None, - is_probe: false, sender_custom_tlvs: Vec::new(), payment_metadata: None, expected_failure: None, + is_probe: false, sender_custom_tlvs: Vec::new(), user_custom_data: None, payment_metadata: None, expected_failure: None, } } pub fn without_clearing_recipient_events(mut self) -> Self { @@ -2714,7 +2715,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option let PassAlongPathArgs { origin_node, expected_path, recv_value, payment_hash: our_payment_hash, payment_secret: our_payment_secret, event: ev, payment_claimable_expected, - clear_recipient_events, expected_preimage, is_probe, sender_custom_tlvs, payment_metadata, + clear_recipient_events, expected_preimage, is_probe, sender_custom_tlvs, user_custom_data, payment_metadata, expected_failure } = args; @@ -2751,6 +2752,7 @@ pub fn do_pass_along_path<'a, 'b, 'c>(args: PassAlongPathArgs) -> Option assert_eq!(node.node.get_our_node_id(), receiver_node_id.unwrap()); assert!(onion_fields.is_some()); assert_eq!(onion_fields.as_ref().unwrap().sender_custom_tlvs, sender_custom_tlvs); + assert_eq!(onion_fields.as_ref().unwrap().user_custom_data, user_custom_data); assert_eq!(onion_fields.as_ref().unwrap().payment_metadata, payment_metadata); match &purpose { PaymentPurpose::Bolt11InvoicePayment { payment_preimage, payment_secret, .. } => { @@ -2882,6 +2884,7 @@ pub struct ClaimAlongRouteArgs<'a, 'b, 'c, 'd> { pub skip_last: bool, pub payment_preimage: PaymentPreimage, pub sender_custom_tlvs: Vec<(u64, Vec)>, + pub user_custom_data: Option>, // Allow forwarding nodes to have taken 1 msat more fee than expected based on the downstream // fulfill amount. // @@ -2900,7 +2903,7 @@ impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> { Self { origin_node, expected_paths, expected_extra_fees: vec![0; expected_paths.len()], expected_min_htlc_overpay: vec![0; expected_paths.len()], skip_last: false, payment_preimage, - allow_1_msat_fee_overpay: false, sender_custom_tlvs: vec![], + allow_1_msat_fee_overpay: false, sender_custom_tlvs: vec![], user_custom_data: None, } } pub fn skip_last(mut self, skip_last: bool) -> Self { @@ -2923,12 +2926,17 @@ impl<'a, 'b, 'c, 'd> ClaimAlongRouteArgs<'a, 'b, 'c, 'd> { self.sender_custom_tlvs = sender_custom_tlvs; self } + pub fn with_user_custom_data(mut self, user_custom_data: Vec) -> Self { + self.user_custom_data = Some(user_custom_data); + self + } } pub fn pass_claimed_payment_along_route(args: ClaimAlongRouteArgs) -> u64 { let ClaimAlongRouteArgs { origin_node, expected_paths, expected_extra_fees, expected_min_htlc_overpay, skip_last, payment_preimage: our_payment_preimage, allow_1_msat_fee_overpay, sender_custom_tlvs, + user_custom_data } = args; let claim_event = expected_paths[0].last().unwrap().node.get_and_clear_pending_events(); assert_eq!(claim_event.len(), 1); @@ -2966,6 +2974,7 @@ pub fn pass_claimed_payment_along_route(args: ClaimAlongRouteArgs) -> u64 { assert_eq!(htlcs.len(), expected_paths.len()); // One per path. assert_eq!(htlcs.iter().map(|h| h.value_msat).sum::(), amount_msat); assert_eq!(onion_fields.as_ref().unwrap().sender_custom_tlvs, sender_custom_tlvs); + assert_eq!(onion_fields.as_ref().unwrap().user_custom_data, user_custom_data); check_claimed_htlcs_match_route(origin_node, expected_paths, htlcs); fwd_amt_msat = amount_msat; } diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index 43c0f840489..3424b667f20 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -78,6 +78,7 @@ fn large_payment_metadata() { payment_secret: Some(payment_secret), payment_metadata: Some(payment_metadata.clone()), sender_custom_tlvs: Vec::new(), + user_custom_data: None, }; nodes[0].node.send_payment(payment_hash, recipient_onion_max_md_size.clone(), PaymentId(payment_hash.0), route_0_1.route_params.clone().unwrap(), Retry::Attempts(0)).unwrap(); check_added_monitors!(nodes[0], 1); @@ -126,6 +127,7 @@ fn large_payment_metadata() { payment_secret: Some(payment_secret_2), payment_metadata: Some(vec![42; max_metadata_len - INTERMED_PAYLOAD_LEN_ESTIMATE]), sender_custom_tlvs: Vec::new(), + user_custom_data: None, }; let mut route_params_0_2 = route_0_2.route_params.clone().unwrap(); route_params_0_2.payment_params.max_path_length = 2; @@ -190,7 +192,7 @@ fn one_hop_blinded_path_with_custom_tlv() { intro_node_blinding_point: Some(blinded_path.blinding_point()), keysend_preimage: None, invoice_request: None, - sender_custom_tlvs: &Vec::new() + sender_custom_tlvs: &Vec::new(), }.serialized_length(); let max_custom_tlv_len = 1300 - crate::util::ser::BigSize(CUSTOM_TLV_TYPE).serialized_length() // custom TLV type diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index c1854dfe16c..f51fee53ecf 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -1838,6 +1838,7 @@ mod fuzzy_internal_msgs { pub keysend_preimage: Option, pub invoice_request: Option, pub sender_custom_tlvs: Vec<(u64, Vec)>, + pub user_custom_data: Option>, } pub enum InboundOnionPayload { @@ -2796,7 +2797,7 @@ impl<'a> Writeable for OutboundOnionPayload<'a> { }, Self::Receive { ref payment_data, ref payment_metadata, ref keysend_preimage, sender_intended_htlc_amt_msat, - cltv_expiry_height, ref sender_custom_tlvs, + cltv_expiry_height, ref sender_custom_tlvs } => { // We need to update [`ln::outbound_payment::RecipientOnionFields::with_sender_custom_tlvs`] // to reject any reserved types in the experimental range if new ones are ever @@ -2819,7 +2820,7 @@ impl<'a> Writeable for OutboundOnionPayload<'a> { }, Self::BlindedReceive { sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, encrypted_tlvs, - intro_node_blinding_point, keysend_preimage, ref invoice_request, ref sender_custom_tlvs, + intro_node_blinding_point, keysend_preimage, ref invoice_request, ref sender_custom_tlvs } => { // We need to update [`ln::outbound_payment::RecipientOnionFields::with_sender_custom_tlvs`] // to reject any reserved types in the experimental range if new ones are ever @@ -2909,7 +2910,7 @@ impl ReadableArgs<(Option, NS)> for InboundOnionPayload wh let mut total_msat = None; let mut keysend_preimage: Option = None; let mut invoice_request: Option = None; - let mut custom_tlvs = Vec::new(); + let mut sender_custom_tlvs = Vec::new(); let tlv_len = BigSize::read(r)?; let mut rd = FixedLengthReader::new(r, tlv_len.0); @@ -2929,12 +2930,10 @@ impl ReadableArgs<(Option, NS)> for InboundOnionPayload wh if msg_type < 1 << 16 { return Ok(false) } let mut value = Vec::new(); msg_reader.read_to_limit(&mut value, u64::MAX)?; - custom_tlvs.push((msg_type, value)); + sender_custom_tlvs.push((msg_type, value)); Ok(true) }); - let sender_custom_tlvs = custom_tlvs; - if amt.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) } if intro_node_blinding_point.is_some() && update_add_blinding_point.is_some() { return Err(DecodeError::InvalidValue) @@ -2990,6 +2989,7 @@ impl ReadableArgs<(Option, NS)> for InboundOnionPayload wh keysend_preimage, invoice_request, sender_custom_tlvs, + user_custom_data: None, })) }, } diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs index c6deab524d0..0ab14661691 100644 --- a/lightning/src/ln/onion_payment.rs +++ b/lightning/src/ln/onion_payment.rs @@ -135,7 +135,7 @@ pub(super) fn create_recv_pending_htlc_info( counterparty_skimmed_fee_msat: Option, current_height: u32 ) -> Result { let ( - payment_data, keysend_preimage, sender_custom_tlvs, onion_amt_msat, onion_cltv_expiry, + payment_data, keysend_preimage, sender_custom_tlvs, user_custom_data, onion_amt_msat, onion_cltv_expiry, payment_metadata, payment_context, requires_blinded_error, has_recipient_created_payment_secret, invoice_request ) = match hop_data { @@ -143,12 +143,12 @@ pub(super) fn create_recv_pending_htlc_info( payment_data, keysend_preimage, sender_custom_tlvs, sender_intended_htlc_amt_msat, cltv_expiry_height, payment_metadata, .. }) => - (payment_data, keysend_preimage, sender_custom_tlvs, sender_intended_htlc_amt_msat, + (payment_data, keysend_preimage, sender_custom_tlvs, None, sender_intended_htlc_amt_msat, cltv_expiry_height, payment_metadata, None, false, keysend_preimage.is_none(), None), msgs::InboundOnionPayload::BlindedReceive(msgs::InboundOnionBlindedReceivePayload { sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret, intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage, - sender_custom_tlvs, invoice_request + sender_custom_tlvs, user_custom_data, invoice_request }) => { check_blinded_payment_constraints( sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints @@ -161,7 +161,7 @@ pub(super) fn create_recv_pending_htlc_info( } })?; let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat }; - (Some(payment_data), keysend_preimage, sender_custom_tlvs, + (Some(payment_data), keysend_preimage, sender_custom_tlvs, user_custom_data, sender_intended_htlc_amt_msat, cltv_expiry_height, None, Some(payment_context), intro_node_blinding_point.is_none(), true, invoice_request) } @@ -235,6 +235,7 @@ pub(super) fn create_recv_pending_htlc_info( payment_metadata, incoming_cltv_expiry: onion_cltv_expiry, sender_custom_tlvs, + user_custom_data, requires_blinded_error, has_recipient_created_payment_secret, payment_context, @@ -248,6 +249,7 @@ pub(super) fn create_recv_pending_htlc_info( incoming_cltv_expiry: onion_cltv_expiry, phantom_shared_secret, sender_custom_tlvs, + user_custom_data, requires_blinded_error, } } else { diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index df712b4a9e5..8a34f8782c4 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -105,6 +105,7 @@ pub(crate) enum PendingOutboundPayment { keysend_preimage: Option, invoice_request: Option, sender_custom_tlvs: Vec<(u64, Vec)>, + user_custom_data: Option>, pending_amt_msat: u64, /// Used to track the fee paid. Present iff the payment was serialized on 0.0.103+. pending_fee_msat: Option, @@ -652,12 +653,15 @@ pub struct RecipientOnionFields { pub payment_metadata: Option>, /// See [`Self::sender_custom_tlvs`] for more info. pub(super) sender_custom_tlvs: Vec<(u64, Vec)>, + /// See [`Self::user_custom_data`] for more info. + pub(super) user_custom_data: Option> } impl_writeable_tlv_based!(RecipientOnionFields, { (0, payment_secret, option), (1, sender_custom_tlvs, optional_vec), (2, payment_metadata, option), + (3, user_custom_data, option), }); impl RecipientOnionFields { @@ -665,7 +669,7 @@ impl RecipientOnionFields { /// set of onion fields for today's BOLT11 invoices - most nodes require a [`PaymentSecret`] /// but do not require or provide any further data. pub fn secret_only(payment_secret: PaymentSecret) -> Self { - Self { payment_secret: Some(payment_secret), payment_metadata: None, sender_custom_tlvs: Vec::new() } + Self { payment_secret: Some(payment_secret), payment_metadata: None, sender_custom_tlvs: Vec::new(), user_custom_data: None } } /// Creates a new [`RecipientOnionFields`] with no fields. This generally does not create @@ -677,7 +681,7 @@ impl RecipientOnionFields { /// [`ChannelManager::send_spontaneous_payment`]: super::channelmanager::ChannelManager::send_spontaneous_payment /// [`RecipientOnionFields::secret_only`]: RecipientOnionFields::secret_only pub fn spontaneous_empty() -> Self { - Self { payment_secret: None, payment_metadata: None, sender_custom_tlvs: Vec::new() } + Self { payment_secret: None, payment_metadata: None, sender_custom_tlvs: Vec::new(), user_custom_data: None} } /// Creates a new [`RecipientOnionFields`] from an existing one, adding sender custom TLVs. Each @@ -706,12 +710,33 @@ impl RecipientOnionFields { Ok(self) } + /// Creates a new [`RecipientOnionFields`] from an existing one, adding user custom data. + /// + /// See [`Self::user_custom_data`] for more info. + pub fn with_user_custom_data(mut self, custom_data: Vec) -> Self { + self.user_custom_data = Some(custom_data); + self + } + + /// Gets the user custom data that will be sent or have been received. + /// + /// user custom data allow receiving back extra application-specific + /// data that was set by the receiver in the Blinded Path used by the sender + /// to reach them. + /// + /// This provides additional flexibility to users by enabling them to include + /// extra data they want to receive back, which can be used for authentication + /// or other purposes. + pub fn user_custom_data(&self) -> &Option> { + &self.user_custom_data + } + /// Gets the sender custom TLVs that will be sent or have been received. /// - /// Sender custom TLVs allow sending extra application-specific data with a payment. They provide - /// additional flexibility on top of payment metadata, as while other implementations may - /// require `payment_metadata` to reflect metadata provided in an invoice, sender custom TLVs - /// do not have this restriction. + /// Sender custom TLVs allow sending extra application-specific data with a payment. + /// They provide additional flexibility on top of payment metadata, as while other + /// implementations may require `payment_metadata` to reflect metadata provided in + /// an invoice, custom TLVs do not have this restriction. /// /// Note that if this field is non-empty, it will contain strictly increasing TLVs, each /// represented by a `(u64, Vec)` for its type number and serialized value respectively. @@ -944,6 +969,7 @@ impl OutboundPayments { payment_secret: None, payment_metadata: None, sender_custom_tlvs: vec![], + user_custom_data: None, }; let route = match self.find_initial_route( payment_id, payment_hash, &recipient_onion, keysend_preimage, invoice_request, @@ -1369,7 +1395,7 @@ impl OutboundPayments { match payment.get() { PendingOutboundPayment::Retryable { total_msat, keysend_preimage, payment_secret, payment_metadata, - sender_custom_tlvs, pending_amt_msat, invoice_request, .. + sender_custom_tlvs, user_custom_data, pending_amt_msat, invoice_request, .. } => { const RETRY_OVERFLOW_PERCENTAGE: u64 = 10; let retry_amt_msat = route.get_total_amount(); @@ -1390,6 +1416,7 @@ impl OutboundPayments { payment_secret: *payment_secret, payment_metadata: payment_metadata.clone(), sender_custom_tlvs: sender_custom_tlvs.clone(), + user_custom_data: user_custom_data.clone(), }; let keysend_preimage = *keysend_preimage; let invoice_request = invoice_request.clone(); @@ -1694,6 +1721,7 @@ impl OutboundPayments { keysend_preimage, invoice_request, sender_custom_tlvs: recipient_onion.sender_custom_tlvs, + user_custom_data: recipient_onion.user_custom_data, starting_block_height: best_block_height, total_msat: route.get_total_amount(), remaining_max_total_routing_fee_msat: @@ -2311,6 +2339,7 @@ impl OutboundPayments { keysend_preimage: None, // only used for retries, and we'll never retry on startup invoice_request: None, // only used for retries, and we'll never retry on startup sender_custom_tlvs: Vec::new(), // only used for retries, and we'll never retry on startup + user_custom_data: None, // only used for retries, and we'll never retry on startup pending_amt_msat: path_amt, pending_fee_msat: Some(path_fee), total_msat: path_amt, @@ -2399,6 +2428,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment, (10, starting_block_height, required), (11, remaining_max_total_routing_fee_msat, option), (13, invoice_request, option), + (15, user_custom_data, option), (not_written, retry_strategy, (static_value, None)), (not_written, attempts, (static_value, PaymentAttempts::new())), }, diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index 3c297788d38..af0fbf811d2 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -3721,7 +3721,8 @@ fn do_test_sender_custom_tlvs(spontaneous: bool, even_tlvs: bool, known_tlvs: bo let onion_fields = RecipientOnionFields { payment_secret: if spontaneous { None } else { Some(our_payment_secret) }, payment_metadata: None, - sender_custom_tlvs: sender_custom_tlvs.clone() + sender_custom_tlvs: sender_custom_tlvs.clone(), + user_custom_data: None, }; if spontaneous { nodes[0].node.send_spontaneous_payment( @@ -3865,6 +3866,7 @@ fn test_sender_custom_tlvs_consistency() { let odd_type_1 = (1 << 16)+ 1; let even_type_2 = (1 << 16) + 2; let odd_type_2 = (1 << 16) + 3; + // (1<<16) + 5 is reserved for user_custom_data. let value_1 = || vec![1, 2, 3, 4]; let differing_value_1 = || vec![1, 2, 3, 5]; let value_2 = || vec![42u8; 16]; @@ -3926,7 +3928,8 @@ fn do_test_sender_custom_tlvs_consistency(first_tlvs: Vec<(u64, Vec)>, secon let onion_fields = RecipientOnionFields { payment_secret: Some(our_payment_secret), payment_metadata: None, - sender_custom_tlvs: first_tlvs + sender_custom_tlvs: first_tlvs, + user_custom_data: None, }; let session_privs = nodes[0].node.test_add_new_pending_payment(our_payment_hash, onion_fields.clone(), payment_id, &route).unwrap(); @@ -3948,7 +3951,9 @@ fn do_test_sender_custom_tlvs_consistency(first_tlvs: Vec<(u64, Vec)>, secon let onion_fields = RecipientOnionFields { payment_secret: Some(our_payment_secret), payment_metadata: None, - sender_custom_tlvs: second_tlvs + sender_custom_tlvs: second_tlvs, + user_custom_data: None, + }; nodes[0].node.test_send_payment_along_path(&route.paths[1], &our_payment_hash, onion_fields.clone(), amt_msat, cur_height, payment_id, &None, session_privs[1]).unwrap(); @@ -4055,6 +4060,7 @@ fn do_test_payment_metadata_consistency(do_reload: bool, do_modify: bool) { // Send the MPP payment, delivering the updated commitment state to nodes[1]. nodes[0].node.send_payment(payment_hash, RecipientOnionFields { payment_secret: Some(payment_secret), payment_metadata: Some(payment_metadata), sender_custom_tlvs: vec![], + user_custom_data: None, }, payment_id, route_params.clone(), Retry::Attempts(1)).unwrap(); check_added_monitors!(nodes[0], 2); From 84a729f2a3ca9ecdf8dfddd0478327ea2f030d6d Mon Sep 17 00:00:00 2001 From: shaavan Date: Wed, 12 Feb 2025 21:34:38 +0530 Subject: [PATCH 09/10] Add Custom TLVs for payment::ReceiveTlvs - Building on the previous commit, this update allows users to include their own custom TLVs within the reply path of a sent onion message. - With this, users can attach custom data to the message, which will be returned in the response, providing more flexibility for custom use cases. --- fuzz/src/invoice_request_deser.rs | 1 + fuzz/src/refund_deser.rs | 1 + lightning/src/blinded_path/payment.rs | 18 ++++++++++++++++++ lightning/src/ln/async_payments_tests.rs | 1 + lightning/src/ln/blinded_payment_tests.rs | 8 ++++++++ lightning/src/ln/channelmanager.rs | 13 +++++++------ lightning/src/ln/max_payment_path_len_tests.rs | 1 + lightning/src/ln/msgs.rs | 5 +++-- 8 files changed, 40 insertions(+), 8 deletions(-) diff --git a/fuzz/src/invoice_request_deser.rs b/fuzz/src/invoice_request_deser.rs index 37668c1d801..45dd77f0dc4 100644 --- a/fuzz/src/invoice_request_deser.rs +++ b/fuzz/src/invoice_request_deser.rs @@ -103,6 +103,7 @@ fn build_response( htlc_minimum_msat: 1, }, payment_context, + custom_data: None, }; let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let intermediate_nodes = [PaymentForwardNode { diff --git a/fuzz/src/refund_deser.rs b/fuzz/src/refund_deser.rs index 6151d810344..a45cab64015 100644 --- a/fuzz/src/refund_deser.rs +++ b/fuzz/src/refund_deser.rs @@ -80,6 +80,7 @@ fn build_response( htlc_minimum_msat: 1, }, payment_context, + custom_data: None, }; let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let intermediate_nodes = [PaymentForwardNode { diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index df7c29909f8..89f12453bda 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -325,6 +325,15 @@ pub struct UnauthenticatedReceiveTlvs { pub payment_constraints: PaymentConstraints, /// Context for the receiver of this payment. pub payment_context: PaymentContext, + /// Custom data set by the user. And is returned back when the blinded path is used. + /// + /// ## Note on Forward Compatibility: + /// Users can encode any kind of data into the `Vec` bytes here. However, they should ensure + /// that the data is structured in a forward-compatible manner. This is especially important as + /// `ReceiveTlvs` created in one version of the software may still appear in payments received + /// shortly after a software upgrade. Proper forward compatibility helps prevent data loss or + /// misinterpretation in future versions. + pub custom_data: Option>, } impl UnauthenticatedReceiveTlvs { @@ -490,6 +499,7 @@ impl Writeable for ReceiveTlvs { (65536, self.tlvs.payment_secret, required), (65537, self.tlvs.payment_context, required), (65539, self.authentication, required), + (65541, self.tlvs.custom_data, required) }); Ok(()) } @@ -501,6 +511,7 @@ impl Writeable for UnauthenticatedReceiveTlvs { (12, self.payment_constraints, required), (65536, self.payment_secret, required), (65537, self.payment_context, required), + (65541, self.custom_data, (default_value, Vec::new())), }); Ok(()) } @@ -529,6 +540,7 @@ impl Readable for BlindedPaymentTlvs { (65536, payment_secret, option), (65537, payment_context, option), (65539, authentication, option), + (65541, custom_data, option) }); let _padding: Option = _padding; @@ -552,6 +564,7 @@ impl Readable for BlindedPaymentTlvs { payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?, payment_constraints: payment_constraints.0.unwrap(), payment_context: payment_context.ok_or(DecodeError::InvalidValue)?, + custom_data: custom_data.ok_or(DecodeError::InvalidValue)?, }, authentication: authentication.ok_or(DecodeError::InvalidValue)?, })) @@ -794,6 +807,7 @@ mod tests { payment_secret: PaymentSecret([0; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let htlc_maximum_msat = 100_000; let blinded_payinfo = @@ -812,6 +826,7 @@ mod tests { payment_secret: PaymentSecret([0; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let blinded_payinfo = super::compute_payinfo(&[], &recv_tlvs, 4242, TEST_FINAL_CLTV as u16).unwrap(); @@ -869,6 +884,7 @@ mod tests { payment_secret: PaymentSecret([0; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 3 }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let htlc_maximum_msat = 100_000; let blinded_payinfo = super::compute_payinfo( @@ -928,6 +944,7 @@ mod tests { payment_secret: PaymentSecret([0; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let htlc_minimum_msat = 3798; assert!(super::compute_payinfo( @@ -997,6 +1014,7 @@ mod tests { payment_secret: PaymentSecret([0; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let blinded_payinfo = super::compute_payinfo( diff --git a/lightning/src/ln/async_payments_tests.rs b/lightning/src/ln/async_payments_tests.rs index 5ae5bcb02cd..d5726611def 100644 --- a/lightning/src/ln/async_payments_tests.rs +++ b/lightning/src/ln/async_payments_tests.rs @@ -773,6 +773,7 @@ fn reject_bad_payment_secret() { // We don't reach the point of checking the invreq nonce due to the invalid payment secret offer_nonce: Nonce([i; Nonce::LENGTH]), }), + None, u32::MAX, ) .unwrap(); diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 52b46e05a2b..c87ee99a652 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -79,6 +79,7 @@ pub fn blinded_payment_path( intro_node_min_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_minimum_msat), }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let nonce = Nonce([42u8; 16]); @@ -165,6 +166,7 @@ fn do_one_hop_blinded_path(success: bool) { htlc_minimum_msat: chan_upd.htlc_minimum_msat, }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_key(); @@ -213,6 +215,7 @@ fn mpp_to_one_hop_blinded_path() { htlc_minimum_msat: chan_upd_1_3.htlc_minimum_msat, }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[3].keys_manager.get_inbound_payment_key(); @@ -878,6 +881,8 @@ fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) { nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(), &[&chan_upd_1_2], &chanmon_cfgs[2].keys_manager); + route_params.payment_params.max_path_length = 18; + let route = if check == ReceiveCheckFail::ProcessPendingHTLCsCheck { let mut route = get_route(&nodes[0], &route_params).unwrap(); // Set the final CLTV expiry too low to trigger the failure in process_pending_htlc_forwards. @@ -1299,6 +1304,7 @@ fn sender_custom_tlvs_to_blinded_path() { htlc_minimum_msat: chan_upd.htlc_minimum_msat, }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_key(); @@ -1353,6 +1359,7 @@ fn fails_receive_tlvs_authentication() { htlc_minimum_msat: chan_upd.htlc_minimum_msat, }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_key(); @@ -1384,6 +1391,7 @@ fn fails_receive_tlvs_authentication() { htlc_minimum_msat: chan_upd.htlc_minimum_msat, }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let nonce = Nonce([43u8; 16]); let mut payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index c5f0ed2e129..c5f86b0e4a0 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -10120,7 +10120,7 @@ where ).map_err(|()| Bolt12SemanticError::InvalidAmount)?; let payment_paths = self.create_blinded_payment_paths( - amount_msat, payment_secret, payment_context, relative_expiry_secs + amount_msat, payment_secret, payment_context, None, relative_expiry_secs ).map_err(|()| Bolt12SemanticError::MissingPaths)?; let nonce = Nonce::from_entropy_source(entropy); @@ -10339,7 +10339,7 @@ where Ok((payment_hash, payment_secret)) => { let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {}); let payment_paths = self.create_blinded_payment_paths( - Some(amount_msats), payment_secret, payment_context, relative_expiry, + Some(amount_msats), payment_secret, payment_context, None, relative_expiry, ) .map_err(|_| Bolt12SemanticError::MissingPaths)?; @@ -10656,7 +10656,7 @@ where /// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to /// [`Router::create_blinded_payment_paths`]. fn create_blinded_payment_paths( - &self, amount_msats: Option, payment_secret: PaymentSecret, payment_context: PaymentContext, + &self, amount_msats: Option, payment_secret: PaymentSecret, payment_context: PaymentContext, custom_data: Option>, relative_expiry_seconds: u32, ) -> Result, ()> { let expanded_key = &self.inbound_payment_key; @@ -10680,6 +10680,7 @@ where htlc_minimum_msat: 1, }, payment_context, + custom_data, }; let nonce = Nonce::from_entropy_source(entropy); let payee_tlvs = payee_tlvs.authenticate(nonce, expanded_key); @@ -10691,11 +10692,11 @@ where #[cfg(all(test, async_payments))] pub(super) fn test_create_blinded_payment_paths( - &self, amount_msats: Option, payment_secret: PaymentSecret, payment_context: PaymentContext, + &self, amount_msats: Option, payment_secret: PaymentSecret, payment_context: PaymentContext, custom_data: Option>, relative_expiry_seconds: u32 ) -> Result, ()> { self.create_blinded_payment_paths( - amount_msats, payment_secret, payment_context, relative_expiry_seconds + amount_msats, payment_secret, payment_context, custom_data, relative_expiry_seconds ) } @@ -12254,7 +12255,7 @@ where invoice_request: invoice_request.fields(), }); let payment_paths = match self.create_blinded_payment_paths( - Some(amount_msats), payment_secret, payment_context, relative_expiry + Some(amount_msats), payment_secret, payment_context, None, relative_expiry ) { Ok(payment_paths) => payment_paths, Err(()) => { diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index 3424b667f20..75d2e55b4ce 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -168,6 +168,7 @@ fn one_hop_blinded_path_with_custom_tlv() { htlc_minimum_msat: chan_upd_1_2.htlc_minimum_msat, }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + custom_data: None, }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[2].keys_manager.get_inbound_payment_key(); diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index f51fee53ecf..2b3304ee200 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -2967,6 +2967,7 @@ impl ReadableArgs<(Option, NS)> for InboundOnionPayload wh next_blinding_override, })) }, + // Note: The custom data in the receive tlvs is not used here. ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(receive_tlvs) } => { let ReceiveTlvs { tlvs, authentication: (hmac, nonce) } = receive_tlvs; let expanded_key = node_signer.get_inbound_payment_key(); @@ -2975,7 +2976,7 @@ impl ReadableArgs<(Option, NS)> for InboundOnionPayload wh } let UnauthenticatedReceiveTlvs { - payment_secret, payment_constraints, payment_context, + payment_secret, payment_constraints, payment_context, custom_data } = tlvs; if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) } Ok(Self::BlindedReceive(InboundOnionBlindedReceivePayload { @@ -2989,7 +2990,7 @@ impl ReadableArgs<(Option, NS)> for InboundOnionPayload wh keysend_preimage, invoice_request, sender_custom_tlvs, - user_custom_data: None, + user_custom_data: custom_data, })) }, } From fabd1b3fef984583741edc318e5365c275116bd8 Mon Sep 17 00:00:00 2001 From: shaavan Date: Wed, 12 Feb 2025 21:41:13 +0530 Subject: [PATCH 10/10] Test sending and receiving of user_custom_data --- lightning/src/ln/blinded_payment_tests.rs | 7 +++++-- lightning/src/ln/functional_test_utils.rs | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index c87ee99a652..ac6203b148c 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -1288,7 +1288,7 @@ fn conditionally_round_fwd_amt() { #[test] -fn sender_custom_tlvs_to_blinded_path() { +fn custom_tlvs_to_blinded_path() { let chanmon_cfgs = create_chanmon_cfgs(2); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); @@ -1304,7 +1304,7 @@ fn sender_custom_tlvs_to_blinded_path() { htlc_minimum_msat: chan_upd.htlc_minimum_msat, }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), - custom_data: None, + custom_data: Some(vec![43, 43]), }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_key(); @@ -1321,6 +1321,7 @@ fn sender_custom_tlvs_to_blinded_path() { ); let recipient_onion_fields = RecipientOnionFields::spontaneous_empty() + .with_user_custom_data(vec![43, 43]) .with_sender_custom_tlvs(vec![((1 << 16) + 1, vec![42, 42])]) .unwrap(); nodes[0].node.send_payment(payment_hash, recipient_onion_fields.clone(), @@ -1333,11 +1334,13 @@ fn sender_custom_tlvs_to_blinded_path() { let path = &[&nodes[1]]; let args = PassAlongPathArgs::new(&nodes[0], path, amt_msat, payment_hash, ev) + .with_user_custom_data(recipient_onion_fields.user_custom_data.clone().unwrap()) .with_payment_secret(payment_secret) .with_sender_custom_tlvs(recipient_onion_fields.sender_custom_tlvs.clone()); do_pass_along_path(args); claim_payment_along_route( ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1]]], payment_preimage) + .with_user_custom_data(recipient_onion_fields.user_custom_data.clone().unwrap()) .with_sender_custom_tlvs(recipient_onion_fields.sender_custom_tlvs.clone()) ); } diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 78e27f5438e..aa357cab173 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -2696,6 +2696,10 @@ impl<'a, 'b, 'c, 'd> PassAlongPathArgs<'a, 'b, 'c, 'd> { self.expected_preimage = Some(payment_preimage); self } + pub fn with_user_custom_data(mut self, custom_tlvs: Vec) -> Self { + self.user_custom_data = Some(custom_tlvs); + self + } pub fn with_sender_custom_tlvs(mut self, sender_custom_tlvs: Vec<(u64, Vec)>) -> Self { self.sender_custom_tlvs = sender_custom_tlvs; self