Skip to content

Commit c8de6b6

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 e1c2a62 commit c8de6b6

13 files changed

+153
-85
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};
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};
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

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

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

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};
@@ -8375,7 +8375,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
83758375
let entropy = &*$self.entropy_source;
83768376
let secp_ctx = &$self.secp_ctx;
83778377

8378-
let path = $self.create_blinded_path_using_absolute_expiry(absolute_expiry)
8378+
let path = $self.create_blinded_path_using_absolute_expiry(OffersContext::Unknown {}, absolute_expiry)
83798379
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
83808380
let builder = OfferBuilder::deriving_signing_pubkey(
83818381
node_id, expanded_key, entropy, secp_ctx
@@ -8447,7 +8447,8 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
84478447
let entropy = &*$self.entropy_source;
84488448
let secp_ctx = &$self.secp_ctx;
84498449

8450-
let path = $self.create_blinded_path_using_absolute_expiry(Some(absolute_expiry))
8450+
let context = OffersContext::OutboundPayment { payment_id };
8451+
let path = $self.create_blinded_path_using_absolute_expiry(context, Some(absolute_expiry))
84518452
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
84528453
let builder = RefundBuilder::deriving_payer_id(
84538454
node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
@@ -8570,7 +8571,9 @@ where
85708571
Some(payer_note) => builder.payer_note(payer_note),
85718572
};
85728573
let invoice_request = builder.build_and_sign()?;
8573-
let reply_path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
8574+
8575+
let context = OffersContext::OutboundPayment { payment_id };
8576+
let reply_path = self.create_blinded_path(context).map_err(|_| Bolt12SemanticError::MissingPaths)?;
85748577

85758578
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
85768579

@@ -8670,7 +8673,7 @@ where
86708673
)?;
86718674
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
86728675
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
8673-
let reply_path = self.create_blinded_path()
8676+
let reply_path = self.create_blinded_path(OffersContext::Unknown {})
86748677
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
86758678

86768679
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
@@ -8803,15 +8806,15 @@ where
88038806
/// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See
88048807
/// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`].
88058808
fn create_blinded_path_using_absolute_expiry(
8806-
&self, absolute_expiry: Option<Duration>
8809+
&self, context: OffersContext, absolute_expiry: Option<Duration>,
88078810
) -> Result<BlindedPath, ()> {
88088811
let now = self.duration_since_epoch();
88098812
let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY);
88108813

88118814
if absolute_expiry.unwrap_or(Duration::MAX) <= max_short_lived_absolute_expiry {
8812-
self.create_compact_blinded_path()
8815+
self.create_compact_blinded_path(context)
88138816
} else {
8814-
self.create_blinded_path()
8817+
self.create_blinded_path(context)
88158818
}
88168819
}
88178820

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

@@ -8844,14 +8847,14 @@ where
88448847
.collect::<Vec<_>>();
88458848

88468849
self.router
8847-
.create_blinded_paths(recipient, peers, secp_ctx)
8850+
.create_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx)
88488851
.and_then(|paths| paths.into_iter().next().ok_or(()))
88498852
}
88508853

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

@@ -8871,7 +8874,7 @@ where
88718874
.collect::<Vec<_>>();
88728875

88738876
self.router
8874-
.create_compact_blinded_paths(recipient, peers, secp_ctx)
8877+
.create_compact_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx)
88758878
.and_then(|paths| paths.into_iter().next().ok_or(()))
88768879
}
88778880

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)