Skip to content

Commit 7df670d

Browse files
Update PaymentParameters::route_hints for blinded paths
1 parent 3fd9d67 commit 7df670d

File tree

3 files changed

+51
-14
lines changed

3 files changed

+51
-14
lines changed

lightning/src/blinded_path/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::prelude::*;
2929

3030
/// Onion messages and payments can be sent and received to blinded paths, which serve to hide the
3131
/// identity of the recipient.
32-
#[derive(Clone, Debug, PartialEq)]
32+
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
3333
pub struct BlindedPath {
3434
/// To send to a blinded path, the sender first finds a route to the unblinded
3535
/// `introduction_node_id`, which can unblind its [`encrypted_payload`] to find out the onion
@@ -48,7 +48,7 @@ pub struct BlindedPath {
4848

4949
/// Used to construct the blinded hops portion of a blinded path. These hops cannot be identified
5050
/// by outside observers and thus can be used to hide the identity of the recipient.
51-
#[derive(Clone, Debug, PartialEq)]
51+
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
5252
pub struct BlindedHop {
5353
/// The blinded node id of this hop in a blinded path.
5454
pub(crate) blinded_node_id: PublicKey,

lightning/src/offers/invoice.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ type BlindedPayInfoIter<'a> = core::iter::Map<
588588
>;
589589

590590
/// Information needed to route a payment across a [`BlindedPath`].
591-
#[derive(Clone, Debug, PartialEq)]
591+
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
592592
pub struct BlindedPayInfo {
593593
/// Base fee charged (in millisatoshi) for the entire blinded path.
594594
pub fee_base_msat: u32,

lightning/src/routing/router.rs

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ use bitcoin::secp256k1::PublicKey;
1313
use bitcoin::hashes::Hash;
1414
use bitcoin::hashes::sha256::Hash as Sha256;
1515

16+
use crate::blinded_path::BlindedPath;
1617
use crate::ln::PaymentHash;
1718
use crate::ln::channelmanager::{ChannelDetails, PaymentId};
1819
use crate::ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures};
1920
use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
21+
use crate::offers::invoice::BlindedPayInfo;
2022
use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees};
2123
use crate::routing::scoring::{ChannelUsage, LockableScore, Score};
2224
use crate::util::ser::{Writeable, Readable, ReadableArgs, Writer};
@@ -420,7 +422,7 @@ pub struct PaymentParameters {
420422
pub features: Option<InvoiceFeatures>,
421423

422424
/// Hints for routing to the payee, containing channels connecting the payee to public nodes.
423-
pub route_hints: Vec<RouteHint>,
425+
pub route_hints: Hints,
424426

425427
/// Expiration of a payment to the payee, in seconds relative to the UNIX epoch.
426428
pub expiry_time: Option<u64>,
@@ -459,15 +461,22 @@ pub struct PaymentParameters {
459461

460462
impl Writeable for PaymentParameters {
461463
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
464+
let mut clear_hints = &vec![];
465+
let mut blinded_hints = None;
466+
match &self.route_hints {
467+
Hints::Clear(hints) => clear_hints = hints,
468+
Hints::Blinded(hints) => blinded_hints = Some(hints),
469+
}
462470
write_tlv_fields!(writer, {
463471
(0, self.payee_pubkey, required),
464472
(1, self.max_total_cltv_expiry_delta, required),
465473
(2, self.features, option),
466474
(3, self.max_path_count, required),
467-
(4, self.route_hints, vec_type),
475+
(4, *clear_hints, vec_type),
468476
(5, self.max_channel_saturation_power_of_half, required),
469477
(6, self.expiry_time, option),
470478
(7, self.previously_failed_channels, vec_type),
479+
(8, blinded_hints, option),
471480
(9, self.final_cltv_expiry_delta, required),
472481
});
473482
Ok(())
@@ -485,14 +494,23 @@ impl ReadableArgs<u32> for PaymentParameters {
485494
(5, max_channel_saturation_power_of_half, (default_value, 2)),
486495
(6, expiry_time, option),
487496
(7, previously_failed_channels, vec_type),
497+
(8, blinded_route_hints, vec_type),
488498
(9, final_cltv_expiry_delta, (default_value, default_final_cltv_expiry_delta)),
489499
});
500+
let clear_route_hints = route_hints.unwrap_or(vec![]);
501+
let blinded_route_hints = blinded_route_hints.unwrap_or(vec![]);
502+
let route_hints = if blinded_route_hints.len() != 0 {
503+
if clear_route_hints.len() != 0 { return Err(DecodeError::InvalidValue) }
504+
Hints::Blinded(blinded_route_hints)
505+
} else {
506+
Hints::Clear(clear_route_hints)
507+
};
490508
Ok(Self {
491509
payee_pubkey: _init_tlv_based_struct_field!(payee_pubkey, required),
492510
max_total_cltv_expiry_delta: _init_tlv_based_struct_field!(max_total_cltv_expiry_delta, (default_value, unused)),
493511
features,
494512
max_path_count: _init_tlv_based_struct_field!(max_path_count, (default_value, unused)),
495-
route_hints: route_hints.unwrap_or(Vec::new()),
513+
route_hints,
496514
max_channel_saturation_power_of_half: _init_tlv_based_struct_field!(max_channel_saturation_power_of_half, (default_value, unused)),
497515
expiry_time,
498516
previously_failed_channels: previously_failed_channels.unwrap_or(Vec::new()),
@@ -511,7 +529,7 @@ impl PaymentParameters {
511529
Self {
512530
payee_pubkey,
513531
features: None,
514-
route_hints: vec![],
532+
route_hints: Hints::Clear(vec![]),
515533
expiry_time: None,
516534
max_total_cltv_expiry_delta: DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA,
517535
max_path_count: DEFAULT_MAX_PATH_COUNT,
@@ -540,7 +558,7 @@ impl PaymentParameters {
540558
///
541559
/// (C-not exported) since bindings don't support move semantics
542560
pub fn with_route_hints(self, route_hints: Vec<RouteHint>) -> Self {
543-
Self { route_hints, ..self }
561+
Self { route_hints: Hints::Clear(route_hints), ..self }
544562
}
545563

546564
/// Includes a payment expiration in seconds relative to the UNIX epoch.
@@ -572,6 +590,16 @@ impl PaymentParameters {
572590
}
573591
}
574592

593+
/// Routing hints for the tail of the route.
594+
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
595+
pub enum Hints {
596+
/// The recipient provided blinded paths and payinfo to reach them. The blinded paths themselves
597+
/// will be included in the final [`Route`].
598+
Blinded(Vec<(BlindedPayInfo, BlindedPath)>),
599+
/// The recipient included these route hints in their BOLT11 invoice.
600+
Clear(Vec<RouteHint>),
601+
}
602+
575603
/// A list of hops along a payment path terminating with a channel to the recipient.
576604
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
577605
pub struct RouteHint(pub Vec<RouteHintHop>);
@@ -1021,12 +1049,17 @@ where L::Target: Logger {
10211049
return Err(LightningError{err: "Cannot send a payment of 0 msat".to_owned(), action: ErrorAction::IgnoreError});
10221050
}
10231051

1024-
for route in payment_params.route_hints.iter() {
1025-
for hop in &route.0 {
1026-
if hop.src_node_id == payment_params.payee_pubkey {
1027-
return Err(LightningError{err: "Route hint cannot have the payee as the source.".to_owned(), action: ErrorAction::IgnoreError});
1052+
match &payment_params.route_hints {
1053+
Hints::Clear(hints) => {
1054+
for route in hints.iter() {
1055+
for hop in &route.0 {
1056+
if hop.src_node_id == payment_params.payee_pubkey {
1057+
return Err(LightningError{err: "Route hint cannot have the payee as the source.".to_owned(), action: ErrorAction::IgnoreError});
1058+
}
1059+
}
10281060
}
1029-
}
1061+
},
1062+
_ => todo!()
10301063
}
10311064
if payment_params.max_total_cltv_expiry_delta <= final_cltv_expiry_delta {
10321065
return Err(LightningError{err: "Can't find a route where the maximum total CLTV expiry delta is below the final CLTV expiry.".to_owned(), action: ErrorAction::IgnoreError});
@@ -1551,7 +1584,11 @@ where L::Target: Logger {
15511584
// If a caller provided us with last hops, add them to routing targets. Since this happens
15521585
// earlier than general path finding, they will be somewhat prioritized, although currently
15531586
// it matters only if the fees are exactly the same.
1554-
for route in payment_params.route_hints.iter().filter(|route| !route.0.is_empty()) {
1587+
let route_hints = match &payment_params.route_hints {
1588+
Hints::Clear(hints) => hints,
1589+
_ => todo!()
1590+
};
1591+
for route in route_hints.iter().filter(|route| !route.0.is_empty()) {
15551592
let first_hop_in_route = &(route.0)[0];
15561593
let have_hop_src_in_graph =
15571594
// Only add the hops in this route to our candidate set if either

0 commit comments

Comments
 (0)