Skip to content

Commit f0c2e7d

Browse files
committed
Allow blinded path diversification by expanding create_blinded_paths
- The current usage of `blinded_paths` is limited because `create_blinded_path` only returns a single `BlindedPath`. - This commit expands the functionality of `create_blinded_path` by allowing it to return multiple `BlindedPaths`, as determined by the new `count` parameter. - Additionally, this commit integrates this new capability throughout the codebase by: - Allowing multiple paths in offers and refund builders. - Sending Offers Response messages, such as `InvoiceRequest` (in `pay_for_offer`) and `Invoice` (in `request_refund_payment`), using multiple reply paths. - As a proof-of-concept, this commit increases the maximum count of `create_blinded_paths` to 10, enabling the generation of more reply paths. It also increases the number of `blinded_paths` used in offer and refund builders and responders to 5, demonstrating the usage of multiple reply paths.
1 parent c57b94a commit f0c2e7d

File tree

11 files changed

+105
-81
lines changed

11 files changed

+105
-81
lines changed

fuzz/src/chanmon_consistency.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ impl MessageRouter for FuzzRouter {
120120
}
121121

122122
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
123-
&self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
123+
&self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>, count: usize,
124124
) -> Result<Vec<BlindedPath>, ()> {
125125
unreachable!()
126126
}

fuzz/src/full_stack.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ impl MessageRouter for FuzzRouter {
158158
}
159159

160160
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
161-
&self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
161+
&self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>, count: usize,
162162
) -> Result<Vec<BlindedPath>, ()> {
163163
unreachable!()
164164
}

fuzz/src/onion_message.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ impl MessageRouter for TestMessageRouter {
8989
}
9090

9191
fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
92-
&self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>,
92+
&self, _recipient: PublicKey, _peers: Vec<ForwardNode>, _secp_ctx: &Secp256k1<T>, count: usize
9393
) -> Result<Vec<BlindedPath>, ()> {
9494
unreachable!()
9595
}

lightning/src/ln/channelmanager.rs

+40-28
Original file line numberDiff line numberDiff line change
@@ -8584,12 +8584,14 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
85848584
let entropy = &*$self.entropy_source;
85858585
let secp_ctx = &$self.secp_ctx;
85868586

8587-
let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
8587+
let paths = $self.create_blinded_path(5)
8588+
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
8589+
85888590
let builder = OfferBuilder::deriving_signing_pubkey(
85898591
node_id, expanded_key, entropy, secp_ctx
85908592
)
85918593
.chain_hash($self.chain_hash)
8592-
.path(path);
8594+
.path(paths);
85938595

85948596
Ok(builder.into())
85958597
}
@@ -8651,13 +8653,15 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
86518653
let entropy = &*$self.entropy_source;
86528654
let secp_ctx = &$self.secp_ctx;
86538655

8654-
let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
8656+
let paths = $self.create_blinded_path(5)
8657+
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
8658+
86558659
let builder = RefundBuilder::deriving_payer_id(
86568660
node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
86578661
)?
86588662
.chain_hash($self.chain_hash)
86598663
.absolute_expiry(absolute_expiry)
8660-
.path(path);
8664+
.path(paths);
86618665

86628666
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop($self);
86638667

@@ -8774,7 +8778,8 @@ where
87748778
Some(payer_note) => builder.payer_note(payer_note),
87758779
};
87768780
let invoice_request = builder.build_and_sign()?;
8777-
let reply_path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
8781+
let reply_paths = self.create_blinded_path(5)
8782+
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
87788783

87798784
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
87808785

@@ -8792,20 +8797,24 @@ where
87928797
// one invoice for a given payment id will be paid, even if more than one is received.
87938798
const REQUEST_LIMIT: usize = 10;
87948799
for path in offer.paths().into_iter().take(REQUEST_LIMIT) {
8800+
for reply_path in reply_paths.clone() {
8801+
let message = new_pending_onion_message(
8802+
OffersMessage::InvoiceRequest(invoice_request.clone()),
8803+
Destination::BlindedPath(path.clone()),
8804+
Some(reply_path.clone()),
8805+
);
8806+
pending_offers_messages.push(message);
8807+
}
8808+
}
8809+
} else if let Some(signing_pubkey) = offer.signing_pubkey() {
8810+
for reply_path in reply_paths {
87958811
let message = new_pending_onion_message(
87968812
OffersMessage::InvoiceRequest(invoice_request.clone()),
8797-
Destination::BlindedPath(path.clone()),
8798-
Some(reply_path.clone()),
8813+
Destination::Node(signing_pubkey),
8814+
Some(reply_path),
87998815
);
88008816
pending_offers_messages.push(message);
88018817
}
8802-
} else if let Some(signing_pubkey) = offer.signing_pubkey() {
8803-
let message = new_pending_onion_message(
8804-
OffersMessage::InvoiceRequest(invoice_request),
8805-
Destination::Node(signing_pubkey),
8806-
Some(reply_path),
8807-
);
8808-
pending_offers_messages.push(message);
88098818
} else {
88108819
debug_assert!(false);
88118820
return Err(Bolt12SemanticError::MissingSigningPubkey);
@@ -8874,26 +8883,30 @@ where
88748883
)?;
88758884
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
88768885
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
8877-
let reply_path = self.create_blinded_path()
8886+
let reply_paths = self.create_blinded_path(5)
88788887
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
88798888

88808889
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
88818890
if refund.paths().is_empty() {
8882-
let message = new_pending_onion_message(
8883-
OffersMessage::Invoice(invoice.clone()),
8884-
Destination::Node(refund.payer_id()),
8885-
Some(reply_path),
8886-
);
8887-
pending_offers_messages.push(message);
8888-
} else {
8889-
for path in refund.paths() {
8891+
for reply_path in reply_paths {
88908892
let message = new_pending_onion_message(
88918893
OffersMessage::Invoice(invoice.clone()),
8892-
Destination::BlindedPath(path.clone()),
8893-
Some(reply_path.clone()),
8894+
Destination::Node(refund.payer_id()),
8895+
Some(reply_path),
88948896
);
88958897
pending_offers_messages.push(message);
88968898
}
8899+
} else {
8900+
for path in refund.paths() {
8901+
for reply_path in reply_paths.clone() {
8902+
let message = new_pending_onion_message(
8903+
OffersMessage::Invoice(invoice.clone()),
8904+
Destination::BlindedPath(path.clone()),
8905+
Some(reply_path.clone()),
8906+
);
8907+
pending_offers_messages.push(message);
8908+
}
8909+
}
88978910
}
88988911

88998912
Ok(invoice)
@@ -9003,7 +9016,7 @@ where
90039016
/// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
90049017
///
90059018
/// Errors if the `MessageRouter` errors or returns an empty `Vec`.
9006-
fn create_blinded_path(&self) -> Result<BlindedPath, ()> {
9019+
fn create_blinded_path(&self, count: usize) -> Result<Vec<BlindedPath>, ()> {
90079020
let recipient = self.get_our_node_id();
90089021
let secp_ctx = &self.secp_ctx;
90099022

@@ -9022,8 +9035,7 @@ where
90229035
.collect::<Vec<_>>();
90239036

90249037
self.router
9025-
.create_blinded_paths(recipient, peers, secp_ctx)
9026-
.and_then(|paths| paths.into_iter().next().ok_or(()))
9038+
.create_blinded_paths(recipient, peers, secp_ctx, count)
90279039
}
90289040

90299041
/// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to

lightning/src/ln/offers_tests.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -345,11 +345,17 @@ fn prefers_more_connected_nodes_in_blinded_paths() {
345345
.amount_msats(10_000_000)
346346
.build().unwrap();
347347
assert_ne!(offer.signing_pubkey(), Some(bob_id));
348-
assert!(!offer.paths().is_empty());
349-
for path in offer.paths() {
350-
let introduction_node_id = resolve_introduction_node(david, &path);
351-
assert_eq!(introduction_node_id, nodes[4].node.get_our_node_id());
352-
}
348+
349+
// Ensure both potential paths are calculated for the offer.
350+
assert_eq!(offer.paths().len(), 2);
351+
352+
// Verify that the most connected introduction node is chosen first.
353+
let introduction_node_id_1 = resolve_introduction_node(david, &offer.paths()[0]);
354+
assert_eq!(introduction_node_id_1, nodes[4].node.get_our_node_id());
355+
356+
// Verify that the next most connected introduction node is chosen second.
357+
let introduction_node_id_2 = resolve_introduction_node(david, &offer.paths()[1]);
358+
assert_eq!(introduction_node_id_2, charlie.node.get_our_node_id());
353359
}
354360

355361
/// Checks that an offer can be paid through blinded paths and that ephemeral pubkeys are used

lightning/src/offers/invoice.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -1833,14 +1833,14 @@ mod tests {
18331833
let entropy = FixedEntropy {};
18341834
let secp_ctx = Secp256k1::new();
18351835

1836-
let blinded_path = BlindedPath {
1836+
let blinded_path = vec![BlindedPath {
18371837
introduction_node: IntroductionNode::NodeId(pubkey(40)),
18381838
blinding_point: pubkey(41),
18391839
blinded_hops: vec![
18401840
BlindedHop { blinded_node_id: pubkey(42), encrypted_payload: vec![0; 43] },
18411841
BlindedHop { blinded_node_id: node_id, encrypted_payload: vec![0; 44] },
18421842
],
1843-
};
1843+
}];
18441844

18451845
#[cfg(c_bindings)]
18461846
use crate::offers::offer::OfferWithDerivedMetadataBuilder as OfferBuilder;
@@ -2409,8 +2409,7 @@ mod tests {
24092409
let invoice = OfferBuilder::new(recipient_pubkey())
24102410
.clear_signing_pubkey()
24112411
.amount_msats(1000)
2412-
.path(paths[0].clone())
2413-
.path(paths[1].clone())
2412+
.path(paths.clone())
24142413
.build().unwrap()
24152414
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
24162415
.build().unwrap()
@@ -2431,8 +2430,7 @@ mod tests {
24312430
let invoice = OfferBuilder::new(recipient_pubkey())
24322431
.clear_signing_pubkey()
24332432
.amount_msats(1000)
2434-
.path(paths[0].clone())
2435-
.path(paths[1].clone())
2433+
.path(paths.clone())
24362434
.build().unwrap()
24372435
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
24382436
.build().unwrap()

lightning/src/offers/offer.rs

+17-16
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
//! # #[cfg(feature = "std")]
3434
//! # use std::time::SystemTime;
3535
//! #
36-
//! # fn create_blinded_path() -> BlindedPath { unimplemented!() }
37-
//! # fn create_another_blinded_path() -> BlindedPath { unimplemented!() }
36+
//! # fn create_blinded_path(count: usize) -> Vec<BlindedPath> { unimplemented!() }
37+
//! # fn create_another_blinded_path(count: usize) -> Vec<BlindedPath> { unimplemented!() }
3838
//! #
3939
//! # #[cfg(feature = "std")]
4040
//! # fn build() -> Result<(), Bolt12ParseError> {
@@ -49,8 +49,8 @@
4949
//! .supported_quantity(Quantity::Unbounded)
5050
//! .absolute_expiry(expiration.duration_since(SystemTime::UNIX_EPOCH).unwrap())
5151
//! .issuer("Foo Bar".to_string())
52-
//! .path(create_blinded_path())
53-
//! .path(create_another_blinded_path())
52+
//! .path(create_blinded_path(1))
53+
//! .path(create_another_blinded_path(1))
5454
//! .build()?;
5555
//!
5656
//! // Encode as a bech32 string for use in a QR code.
@@ -344,8 +344,11 @@ macro_rules! offer_builder_methods { (
344344
///
345345
/// Successive calls to this method will add another blinded path. Caller is responsible for not
346346
/// adding duplicate paths.
347-
pub fn path($($self_mut)* $self: $self_type, path: BlindedPath) -> $return_type {
348-
$self.offer.paths.get_or_insert_with(Vec::new).push(path);
347+
pub fn path($($self_mut)* $self: $self_type, paths: Vec<BlindedPath>) -> $return_type {
348+
let entry = $self.offer.paths.get_or_insert_with(Vec::new);
349+
for path in paths {
350+
entry.push(path)
351+
}
349352
$return_value
350353
}
351354

@@ -1316,14 +1319,14 @@ mod tests {
13161319
let entropy = FixedEntropy {};
13171320
let secp_ctx = Secp256k1::new();
13181321

1319-
let blinded_path = BlindedPath {
1322+
let blinded_path = vec![BlindedPath {
13201323
introduction_node: IntroductionNode::NodeId(pubkey(40)),
13211324
blinding_point: pubkey(41),
13221325
blinded_hops: vec![
13231326
BlindedHop { blinded_node_id: pubkey(42), encrypted_payload: vec![0; 43] },
13241327
BlindedHop { blinded_node_id: node_id, encrypted_payload: vec![0; 44] },
13251328
],
1326-
};
1329+
}];
13271330

13281331
#[cfg(c_bindings)]
13291332
use super::OfferWithDerivedMetadataBuilder as OfferBuilder;
@@ -1509,8 +1512,7 @@ mod tests {
15091512
];
15101513

15111514
let offer = OfferBuilder::new(pubkey(42))
1512-
.path(paths[0].clone())
1513-
.path(paths[1].clone())
1515+
.path(paths.clone())
15141516
.build()
15151517
.unwrap();
15161518
let tlv_stream = offer.as_tlv_stream();
@@ -1693,37 +1695,36 @@ mod tests {
16931695
#[test]
16941696
fn parses_offer_with_paths() {
16951697
let offer = OfferBuilder::new(pubkey(42))
1696-
.path(BlindedPath {
1698+
.path(vec![BlindedPath {
16971699
introduction_node: IntroductionNode::NodeId(pubkey(40)),
16981700
blinding_point: pubkey(41),
16991701
blinded_hops: vec![
17001702
BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 43] },
17011703
BlindedHop { blinded_node_id: pubkey(44), encrypted_payload: vec![0; 44] },
17021704
],
1703-
})
1704-
.path(BlindedPath {
1705+
}, BlindedPath {
17051706
introduction_node: IntroductionNode::NodeId(pubkey(40)),
17061707
blinding_point: pubkey(41),
17071708
blinded_hops: vec![
17081709
BlindedHop { blinded_node_id: pubkey(45), encrypted_payload: vec![0; 45] },
17091710
BlindedHop { blinded_node_id: pubkey(46), encrypted_payload: vec![0; 46] },
17101711
],
1711-
})
1712+
}])
17121713
.build()
17131714
.unwrap();
17141715
if let Err(e) = offer.to_string().parse::<Offer>() {
17151716
panic!("error parsing offer: {:?}", e);
17161717
}
17171718

17181719
let offer = OfferBuilder::new(pubkey(42))
1719-
.path(BlindedPath {
1720+
.path(vec![BlindedPath {
17201721
introduction_node: IntroductionNode::NodeId(pubkey(40)),
17211722
blinding_point: pubkey(41),
17221723
blinded_hops: vec![
17231724
BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 43] },
17241725
BlindedHop { blinded_node_id: pubkey(44), encrypted_payload: vec![0; 44] },
17251726
],
1726-
})
1727+
}])
17271728
.clear_signing_pubkey()
17281729
.build()
17291730
.unwrap();

0 commit comments

Comments
 (0)