Skip to content

Commit 42c096c

Browse files
committed
Allow create_blinded_paths functions to accept MessageContext as input field
- Enabled `create_blinded_paths` to accept `MessageContext` TLVs as an input field. - `MessageContext` is intended to be sent along with the `reply_path` to the counterparty. - Added `MessageContext` in the `create_blinded_paths` flow, optionally appending it within the `reply_path`. - Updated tests to verify the new feature.
1 parent fbe9dfa commit 42c096c

14 files changed

+163
-86
lines changed

fuzz/src/chanmon_consistency.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
3333
use bitcoin::hashes::Hash as TraitImport;
3434
use bitcoin::WPubkeyHash;
3535

36+
use lightning::blinded_path::message::MessageContext;
3637
use lightning::blinded_path::payment::ReceiveTlvs;
3738
use lightning::blinded_path::BlindedPath;
3839
use lightning::chain;
@@ -138,7 +139,8 @@ impl MessageRouter for FuzzRouter {
138139
}
139140

140141
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
141-
&self, _recipient: PublicKey, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
142+
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
143+
_secp_ctx: &Secp256k1<T>,
142144
) -> Result<Vec<BlindedPath>, ()> {
143145
unreachable!()
144146
}

fuzz/src/full_stack.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
3030
use bitcoin::hashes::Hash as _;
3131
use bitcoin::WPubkeyHash;
3232

33+
use lightning::blinded_path::message::MessageContext;
3334
use lightning::blinded_path::payment::ReceiveTlvs;
3435
use lightning::blinded_path::BlindedPath;
3536
use lightning::chain;
@@ -175,7 +176,8 @@ impl MessageRouter for FuzzRouter {
175176
}
176177

177178
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
178-
&self, _recipient: PublicKey, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
179+
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
180+
_secp_ctx: &Secp256k1<T>,
179181
) -> Result<Vec<BlindedPath>, ()> {
180182
unreachable!()
181183
}

fuzz/src/invoice_request_deser.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use crate::utils::test_logger;
1111
use bitcoin::secp256k1::{self, Keypair, Parity, PublicKey, Secp256k1, SecretKey};
1212
use core::convert::TryFrom;
13-
use lightning::blinded_path::message::ForwardNode;
13+
use lightning::blinded_path::message::{ForwardNode, MessageContext, OffersContext};
1414
use lightning::blinded_path::BlindedPath;
1515
use lightning::ln::features::BlindedHopFeatures;
1616
use lightning::ln::PaymentHash;
@@ -87,10 +87,22 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
8787
],
8888
];
8989
let paths = vec![
90-
BlindedPath::new_for_message(&intermediate_nodes[0], pubkey(42), &entropy_source, secp_ctx)
91-
.unwrap(),
92-
BlindedPath::new_for_message(&intermediate_nodes[1], pubkey(42), &entropy_source, secp_ctx)
93-
.unwrap(),
90+
BlindedPath::new_for_message(
91+
&intermediate_nodes[0],
92+
pubkey(42),
93+
MessageContext::Offers(OffersContext::Unknown {}),
94+
&entropy_source,
95+
secp_ctx,
96+
)
97+
.unwrap(),
98+
BlindedPath::new_for_message(
99+
&intermediate_nodes[1],
100+
pubkey(42),
101+
MessageContext::Offers(OffersContext::Unknown {}),
102+
&entropy_source,
103+
secp_ctx,
104+
)
105+
.unwrap(),
94106
];
95107

96108
let payinfo = vec![

fuzz/src/onion_message.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ impl MessageRouter for TestMessageRouter {
9595
}
9696

9797
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
98-
&self, _recipient: PublicKey, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
98+
&self, _recipient: PublicKey, _context: MessageContext, _peers: Vec<PublicKey>,
99+
_secp_ctx: &Secp256k1<T>,
99100
) -> Result<Vec<BlindedPath>, ()> {
100101
unreachable!()
101102
}

fuzz/src/refund_deser.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use crate::utils::test_logger;
1111
use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1, SecretKey};
1212
use core::convert::TryFrom;
13-
use lightning::blinded_path::message::ForwardNode;
13+
use lightning::blinded_path::message::{ForwardNode, MessageContext, OffersContext};
1414
use lightning::blinded_path::BlindedPath;
1515
use lightning::ln::features::BlindedHopFeatures;
1616
use lightning::ln::PaymentHash;
@@ -76,10 +76,22 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
7676
],
7777
];
7878
let paths = vec![
79-
BlindedPath::new_for_message(&intermediate_nodes[0], pubkey(42), &entropy_source, secp_ctx)
80-
.unwrap(),
81-
BlindedPath::new_for_message(&intermediate_nodes[1], pubkey(42), &entropy_source, secp_ctx)
82-
.unwrap(),
79+
BlindedPath::new_for_message(
80+
&intermediate_nodes[0],
81+
pubkey(42),
82+
MessageContext::Offers(OffersContext::Unknown {}),
83+
&entropy_source,
84+
secp_ctx,
85+
)
86+
.unwrap(),
87+
BlindedPath::new_for_message(
88+
&intermediate_nodes[1],
89+
pubkey(42),
90+
MessageContext::Offers(OffersContext::Unknown {}),
91+
&entropy_source,
92+
secp_ctx,
93+
)
94+
.unwrap(),
8395
];
8496

8597
let payinfo = vec![

lightning/src/blinded_path/message.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! [`BlindedPath`]: crate::blinded_path::BlindedPath
1313
1414
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
15+
1516
#[allow(unused_imports)]
1617
use crate::prelude::*;
1718

@@ -133,7 +134,7 @@ impl_writeable_tlv_based_enum!(OffersContext,
133134
/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
134135
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
135136
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[ForwardNode], recipient_node_id: PublicKey,
136-
session_priv: &SecretKey
137+
context: MessageContext, session_priv: &SecretKey
137138
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
138139
let pks = intermediate_nodes.iter().map(|node| &node.node_id)
139140
.chain(core::iter::once(&recipient_node_id));
@@ -145,7 +146,7 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
145146
None => NextMessageHop::NodeId(*pubkey),
146147
})
147148
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None }))
148-
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { context: None })));
149+
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs{ context: Some(context) })));
149150

150151
utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
151152
}

lightning/src/blinded_path/mod.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod message;
1414
pub(crate) mod utils;
1515

1616
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
17+
use message::MessageContext;
1718
use core::ops::Deref;
1819

1920
use crate::ln::msgs::DecodeError;
@@ -123,9 +124,9 @@ pub struct BlindedHop {
123124
impl BlindedPath {
124125
/// Create a one-hop blinded path for a message.
125126
pub fn one_hop_for_message<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
126-
recipient_node_id: PublicKey, entropy_source: ES, secp_ctx: &Secp256k1<T>
127+
recipient_node_id: PublicKey, context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1<T>
127128
) -> Result<Self, ()> where ES::Target: EntropySource {
128-
Self::new_for_message(&[], recipient_node_id, entropy_source, secp_ctx)
129+
Self::new_for_message(&[], recipient_node_id, context, entropy_source, secp_ctx)
129130
}
130131

131132
/// Create a blinded path for an onion message, to be forwarded along `node_pks`. The last node
@@ -135,7 +136,7 @@ impl BlindedPath {
135136
// TODO: make all payloads the same size with padding + add dummy hops
136137
pub fn new_for_message<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
137138
intermediate_nodes: &[message::ForwardNode], recipient_node_id: PublicKey,
138-
entropy_source: ES, secp_ctx: &Secp256k1<T>
139+
context: MessageContext, entropy_source: ES, secp_ctx: &Secp256k1<T>
139140
) -> Result<Self, ()> where ES::Target: EntropySource {
140141
let introduction_node = IntroductionNode::NodeId(
141142
intermediate_nodes.first().map_or(recipient_node_id, |n| n.node_id)
@@ -147,7 +148,8 @@ impl BlindedPath {
147148
introduction_node,
148149
blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
149150
blinded_hops: message::blinded_hops(
150-
secp_ctx, intermediate_nodes, recipient_node_id, &blinding_secret,
151+
secp_ctx, intermediate_nodes, recipient_node_id,
152+
context, &blinding_secret,
151153
).map_err(|_| ())?,
152154
})
153155
}

lightning/src/ln/channelmanager.rs

+15-12
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use bitcoin::secp256k1::{SecretKey,PublicKey};
3131
use bitcoin::secp256k1::Secp256k1;
3232
use bitcoin::{secp256k1, Sequence};
3333

34-
use crate::blinded_path::message::OffersContext;
34+
use crate::blinded_path::message::{MessageContext, OffersContext};
3535
use crate::blinded_path::{BlindedPath, NodeIdLookUp};
3636
use crate::blinded_path::message::ForwardNode;
3737
use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs};
@@ -8377,7 +8377,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
83778377
let entropy = &*$self.entropy_source;
83788378
let secp_ctx = &$self.secp_ctx;
83798379

8380-
let path = $self.create_blinded_path_using_absolute_expiry(absolute_expiry)
8380+
let path = $self.create_blinded_path_using_absolute_expiry(OffersContext::Unknown {}, absolute_expiry)
83818381
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
83828382
let builder = OfferBuilder::deriving_signing_pubkey(
83838383
node_id, expanded_key, entropy, secp_ctx
@@ -8449,7 +8449,8 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
84498449
let entropy = &*$self.entropy_source;
84508450
let secp_ctx = &$self.secp_ctx;
84518451

8452-
let path = $self.create_blinded_path_using_absolute_expiry(Some(absolute_expiry))
8452+
let context = OffersContext::OutboundPayment { payment_id };
8453+
let path = $self.create_blinded_path_using_absolute_expiry(context, Some(absolute_expiry))
84538454
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
84548455
let builder = RefundBuilder::deriving_payer_id(
84558456
node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
@@ -8572,7 +8573,9 @@ where
85728573
Some(payer_note) => builder.payer_note(payer_note),
85738574
};
85748575
let invoice_request = builder.build_and_sign()?;
8575-
let reply_path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
8576+
8577+
let context = OffersContext::OutboundPayment { payment_id };
8578+
let reply_path = self.create_blinded_path(context).map_err(|_| Bolt12SemanticError::MissingPaths)?;
85768579

85778580
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
85788581

@@ -8672,7 +8675,7 @@ where
86728675
)?;
86738676
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
86748677
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
8675-
let reply_path = self.create_blinded_path()
8678+
let reply_path = self.create_blinded_path(OffersContext::Unknown {})
86768679
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
86778680

86788681
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
@@ -8805,15 +8808,15 @@ where
88058808
/// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See
88068809
/// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`].
88078810
fn create_blinded_path_using_absolute_expiry(
8808-
&self, absolute_expiry: Option<Duration>
8811+
&self, context: OffersContext, absolute_expiry: Option<Duration>,
88098812
) -> Result<BlindedPath, ()> {
88108813
let now = self.duration_since_epoch();
88118814
let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY);
88128815

88138816
if absolute_expiry.unwrap_or(Duration::MAX) <= max_short_lived_absolute_expiry {
8814-
self.create_compact_blinded_path()
8817+
self.create_compact_blinded_path(context)
88158818
} else {
8816-
self.create_blinded_path()
8819+
self.create_blinded_path(context)
88178820
}
88188821
}
88198822

@@ -8833,7 +8836,7 @@ where
88338836
/// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
88348837
///
88358838
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
8836-
fn create_blinded_path(&self) -> Result<BlindedPath, ()> {
8839+
fn create_blinded_path(&self, context: OffersContext) -> Result<BlindedPath, ()> {
88378840
let recipient = self.get_our_node_id();
88388841
let secp_ctx = &self.secp_ctx;
88398842

@@ -8846,14 +8849,14 @@ where
88468849
.collect::<Vec<_>>();
88478850

88488851
self.router
8849-
.create_blinded_paths(recipient, peers, secp_ctx)
8852+
.create_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx)
88508853
.and_then(|paths| paths.into_iter().next().ok_or(()))
88518854
}
88528855

88538856
/// Creates a blinded path by delegating to [`MessageRouter::create_compact_blinded_paths`].
88548857
///
88558858
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
8856-
fn create_compact_blinded_path(&self) -> Result<BlindedPath, ()> {
8859+
fn create_compact_blinded_path(&self, context: OffersContext) -> Result<BlindedPath, ()> {
88578860
let recipient = self.get_our_node_id();
88588861
let secp_ctx = &self.secp_ctx;
88598862

@@ -8873,7 +8876,7 @@ where
88738876
.collect::<Vec<_>>();
88748877

88758878
self.router
8876-
.create_compact_blinded_paths(recipient, peers, secp_ctx)
8879+
.create_compact_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx)
88778880
.and_then(|paths| paths.into_iter().next().ok_or(()))
88788881
}
88798882

lightning/src/ln/max_payment_path_len_tests.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use bitcoin::secp256k1::{Secp256k1, PublicKey};
1414
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode};
1515
use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, ReceiveTlvs};
16-
use crate::events::MessageSendEventsProvider;
16+
use crate::events::{Event, MessageSendEventsProvider};
1717
use crate::ln::PaymentSecret;
1818
use crate::ln::blinded_payment_tests::get_blinded_route_parameters;
1919
use crate::ln::channelmanager::PaymentId;
@@ -389,4 +389,13 @@ fn bolt12_invoice_too_large_blinded_paths() {
389389
nodes[0].onion_messenger.handle_onion_message(&nodes[1].node.get_our_node_id(), &invoice_om);
390390
// TODO: assert on the invoice error once we support replying to invoice OMs with failure info
391391
nodes[0].logger.assert_log_contains("lightning::ln::channelmanager", "Failed paying invoice: OnionPacketSizeExceeded", 1);
392+
393+
let events = nodes[0].node.get_and_clear_pending_events();
394+
assert_eq!(events.len(), 1);
395+
match events[0] {
396+
Event::PaymentFailed { payment_id: id, .. } => {
397+
assert_eq!(id, payment_id)
398+
},
399+
_ => panic!("Unexpected event"),
400+
}
392401
}

lightning/src/ln/offers_tests.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1412,6 +1412,14 @@ fn fails_sending_invoice_without_blinded_payment_paths_for_offer() {
14121412

14131413
let invoice_error = extract_invoice_error(david, &onion_message);
14141414
assert_eq!(invoice_error, InvoiceError::from(Bolt12SemanticError::MissingPaths));
1415+
1416+
// Confirm that david drops this failed payment from his pending outbound payments.
1417+
match get_event!(david, Event::InvoiceRequestFailed) {
1418+
Event::InvoiceRequestFailed { payment_id: pay_id } => {
1419+
assert_eq!(pay_id, payment_id)
1420+
},
1421+
_ => panic!("No Event::InvoiceRequestFailed"),
1422+
}
14151423
}
14161424

14171425
#[test]

0 commit comments

Comments
 (0)