Skip to content

Commit 156f6b5

Browse files
committed
Allow create_blinded_paths Function to Take Recipient TLVs as a Field
- Enabled `create_blinded_paths` to accept `RecipientData` TLVs as an input field. - `RecipientData` is intended to be sent along with the `reply_path` to the counterparty. - Added `RecipientData` in the `create_blinded_paths` flow, optionally appending it within the `reply_path`. - Updated tests to verify the new feature.
1 parent 46f2caf commit 156f6b5

13 files changed

+124
-71
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::RecipientData;
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, _recipient_tlvs: Option<RecipientData>,
143+
_peers: Vec<PublicKey>, _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::RecipientData;
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, _recipient_tlvs: Option<RecipientData>,
180+
_peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
179181
) -> Result<Vec<BlindedPath>, ()> {
180182
unreachable!()
181183
}

fuzz/src/invoice_request_deser.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -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+
None,
94+
&entropy_source,
95+
secp_ctx,
96+
)
97+
.unwrap(),
98+
BlindedPath::new_for_message(
99+
&intermediate_nodes[1],
100+
pubkey(42),
101+
None,
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
@@ -90,7 +90,8 @@ impl MessageRouter for TestMessageRouter {
9090
}
9191

9292
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
93-
&self, _recipient: PublicKey, _peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
93+
&self, _recipient: PublicKey, _recipient_tlvs: Option<RecipientData>,
94+
_peers: Vec<PublicKey>, _secp_ctx: &Secp256k1<T>,
9495
) -> Result<Vec<BlindedPath>, ()> {
9596
unreachable!()
9697
}

fuzz/src/refund_deser.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -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+
None,
83+
&entropy_source,
84+
secp_ctx,
85+
)
86+
.unwrap(),
87+
BlindedPath::new_for_message(
88+
&intermediate_nodes[1],
89+
pubkey(42),
90+
None,
91+
&entropy_source,
92+
secp_ctx,
93+
)
94+
.unwrap(),
8395
];
8496

8597
let payinfo = vec![

lightning/src/blinded_path/message.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl Readable for ReceiveTlvs {
171171
/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
172172
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
173173
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[ForwardNode], recipient_node_id: PublicKey,
174-
session_priv: &SecretKey
174+
recipient_tlvs: Option<RecipientData>, session_priv: &SecretKey
175175
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
176176
let pks = intermediate_nodes.iter().map(|node| &node.node_id)
177177
.chain(core::iter::once(&recipient_node_id));
@@ -183,7 +183,7 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
183183
None => NextMessageHop::NodeId(*pubkey),
184184
})
185185
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None }))
186-
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs::new(None))));
186+
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs::new(recipient_tlvs))));
187187

188188
utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
189189
}

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::RecipientData;
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, recipient_tlvs: Option<RecipientData>, 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, recipient_tlvs, 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+
recipient_tlvs: Option<RecipientData>, 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+
recipient_tlvs, &blinding_secret,
151153
).map_err(|_| ())?,
152154
})
153155
}

lightning/src/ln/channelmanager.rs

+14-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::OffersData;
34+
use crate::blinded_path::message::{OffersData, RecipientData};
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};
@@ -8335,7 +8335,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
83358335
let entropy = &*$self.entropy_source;
83368336
let secp_ctx = &$self.secp_ctx;
83378337

8338-
let path = $self.create_blinded_path_using_absolute_expiry(absolute_expiry)
8338+
let path = $self.create_blinded_path_using_absolute_expiry(absolute_expiry, None)
83398339
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
83408340
let builder = OfferBuilder::deriving_signing_pubkey(
83418341
node_id, expanded_key, entropy, secp_ctx
@@ -8407,7 +8407,8 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
84078407
let entropy = &*$self.entropy_source;
84088408
let secp_ctx = &$self.secp_ctx;
84098409

8410-
let path = $self.create_blinded_path_using_absolute_expiry(Some(absolute_expiry))
8410+
let recipient_tlvs = RecipientData::new_for_offers(Some(payment_id));
8411+
let path = $self.create_blinded_path_using_absolute_expiry(Some(absolute_expiry), Some(recipient_tlvs))
84118412
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
84128413
let builder = RefundBuilder::deriving_payer_id(
84138414
node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
@@ -8530,7 +8531,8 @@ where
85308531
Some(payer_note) => builder.payer_note(payer_note),
85318532
};
85328533
let invoice_request = builder.build_and_sign()?;
8533-
let reply_path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
8534+
let recipient_tlvs = RecipientData::new_for_offers(Some(payment_id));
8535+
let reply_path = self.create_blinded_path(Some(recipient_tlvs)).map_err(|_| Bolt12SemanticError::MissingPaths)?;
85348536

85358537
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
85368538

@@ -8630,7 +8632,7 @@ where
86308632
)?;
86318633
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
86328634
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
8633-
let reply_path = self.create_blinded_path()
8635+
let reply_path = self.create_blinded_path(None)
86348636
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
86358637

86368638
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
@@ -8763,15 +8765,15 @@ where
87638765
/// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See
87648766
/// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`].
87658767
fn create_blinded_path_using_absolute_expiry(
8766-
&self, absolute_expiry: Option<Duration>
8768+
&self, absolute_expiry: Option<Duration>, recipient_tlvs: Option<RecipientData>
87678769
) -> Result<BlindedPath, ()> {
87688770
let now = self.duration_since_epoch();
87698771
let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY);
87708772

87718773
if absolute_expiry.unwrap_or(Duration::MAX) <= max_short_lived_absolute_expiry {
8772-
self.create_compact_blinded_path()
8774+
self.create_compact_blinded_path(recipient_tlvs)
87738775
} else {
8774-
self.create_blinded_path()
8776+
self.create_blinded_path(recipient_tlvs)
87758777
}
87768778
}
87778779

@@ -8791,7 +8793,7 @@ where
87918793
/// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
87928794
///
87938795
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
8794-
fn create_blinded_path(&self) -> Result<BlindedPath, ()> {
8796+
fn create_blinded_path(&self, recipient_tlvs: Option<RecipientData>) -> Result<BlindedPath, ()> {
87958797
let recipient = self.get_our_node_id();
87968798
let secp_ctx = &self.secp_ctx;
87978799

@@ -8804,14 +8806,14 @@ where
88048806
.collect::<Vec<_>>();
88058807

88068808
self.router
8807-
.create_blinded_paths(recipient, peers, secp_ctx)
8809+
.create_blinded_paths(recipient, recipient_tlvs, peers, secp_ctx)
88088810
.and_then(|paths| paths.into_iter().next().ok_or(()))
88098811
}
88108812

88118813
/// Creates a blinded path by delegating to [`MessageRouter::create_compact_blinded_paths`].
88128814
///
88138815
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
8814-
fn create_compact_blinded_path(&self) -> Result<BlindedPath, ()> {
8816+
fn create_compact_blinded_path(&self, recipient_tlvs: Option<RecipientData>) -> Result<BlindedPath, ()> {
88158817
let recipient = self.get_our_node_id();
88168818
let secp_ctx = &self.secp_ctx;
88178819

@@ -8831,7 +8833,7 @@ where
88318833
.collect::<Vec<_>>();
88328834

88338835
self.router
8834-
.create_compact_blinded_paths(recipient, peers, secp_ctx)
8836+
.create_compact_blinded_paths(recipient, recipient_tlvs, peers, secp_ctx)
88358837
.and_then(|paths| paths.into_iter().next().ok_or(()))
88368838
}
88378839

lightning/src/ln/offers_tests.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,16 @@ fn fails_sending_invoice_without_blinded_payment_paths_for_offer() {
13321332

13331333
let invoice_error = extract_invoice_error(david, &onion_message);
13341334
assert_eq!(invoice_error, InvoiceError::from(Bolt12SemanticError::MissingPaths));
1335+
1336+
// Confirm that david drops this failed payment from his pending outbound payments.
1337+
let events = david.node.get_and_clear_pending_events();
1338+
assert_eq!(events.len(), 1);
1339+
match events[0] {
1340+
Event::InvoiceRequestFailed { payment_id: pay_id } => {
1341+
assert_eq!(pay_id, payment_id)
1342+
},
1343+
_ => panic!("Unexpected Event"),
1344+
}
13351345
}
13361346

13371347
#[test]

0 commit comments

Comments
 (0)