Skip to content

Commit 44956bd

Browse files
Add BlindedPaymentPath type, to disambiguate from message paths.
Next up, we'll add a BlindedMessagePath type so the API is clear which type of path is expected in each context.
1 parent 3071bbb commit 44956bd

20 files changed

+224
-227
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use bitcoin::hashes::Hash as TraitImport;
3434
use bitcoin::WPubkeyHash;
3535

3636
use lightning::blinded_path::message::MessageContext;
37-
use lightning::blinded_path::payment::ReceiveTlvs;
37+
use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
3838
use lightning::blinded_path::BlindedPath;
3939
use lightning::chain;
4040
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
@@ -126,7 +126,7 @@ impl Router for FuzzRouter {
126126
fn create_blinded_payment_paths<T: secp256k1::Signing + secp256k1::Verification>(
127127
&self, _recipient: PublicKey, _first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs,
128128
_amount_msats: u64, _secp_ctx: &Secp256k1<T>,
129-
) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
129+
) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, ()> {
130130
unreachable!()
131131
}
132132
}

fuzz/src/full_stack.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use bitcoin::hashes::Hash as _;
3131
use bitcoin::WPubkeyHash;
3232

3333
use lightning::blinded_path::message::MessageContext;
34-
use lightning::blinded_path::payment::ReceiveTlvs;
34+
use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
3535
use lightning::blinded_path::BlindedPath;
3636
use lightning::chain;
3737
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
@@ -163,7 +163,7 @@ impl Router for FuzzRouter {
163163
fn create_blinded_payment_paths<T: secp256k1::Signing + secp256k1::Verification>(
164164
&self, _recipient: PublicKey, _first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs,
165165
_amount_msats: u64, _secp_ctx: &Secp256k1<T>,
166-
) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
166+
) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, ()> {
167167
unreachable!()
168168
}
169169
}

fuzz/src/invoice_request_deser.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ use crate::utils::test_logger;
1111
use bitcoin::secp256k1::{self, Keypair, Parity, PublicKey, Secp256k1, SecretKey};
1212
use core::convert::TryFrom;
1313
use lightning::blinded_path::payment::{
14-
Bolt12OfferContext, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay,
15-
ReceiveTlvs,
14+
BlindedPaymentPath, Bolt12OfferContext, ForwardNode, ForwardTlvs, PaymentConstraints,
15+
PaymentContext, PaymentRelay, ReceiveTlvs,
1616
};
17-
use lightning::blinded_path::BlindedPath;
1817
use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA;
1918
use lightning::ln::features::BlindedHopFeatures;
2019
use lightning::ln::types::PaymentSecret;
@@ -118,7 +117,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
118117
node_id: pubkey(43),
119118
htlc_maximum_msat: 1_000_000_000_000,
120119
}];
121-
let payment_path = BlindedPath::new_for_payment(
120+
let payment_path = BlindedPaymentPath::new(
122121
&intermediate_nodes,
123122
pubkey(42),
124123
payee_tlvs,

fuzz/src/refund_deser.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ use crate::utils::test_logger;
1111
use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1, SecretKey};
1212
use core::convert::TryFrom;
1313
use lightning::blinded_path::payment::{
14-
Bolt12RefundContext, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext,
15-
PaymentRelay, ReceiveTlvs,
14+
BlindedPaymentPath, Bolt12RefundContext, ForwardNode, ForwardTlvs, PaymentConstraints,
15+
PaymentContext, PaymentRelay, ReceiveTlvs,
1616
};
17-
use lightning::blinded_path::BlindedPath;
1817
use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA;
1918
use lightning::ln::features::BlindedHopFeatures;
2019
use lightning::ln::types::PaymentSecret;
@@ -96,7 +95,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
9695
node_id: pubkey(43),
9796
htlc_maximum_msat: 1_000_000_000_000,
9897
}];
99-
let payment_path = BlindedPath::new_for_payment(
98+
let payment_path = BlindedPaymentPath::new(
10099
&intermediate_nodes,
101100
pubkey(42),
102101
payee_tlvs,

fuzz/src/router.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use bitcoin::blockdata::script::Builder;
1313
use bitcoin::blockdata::transaction::TxOut;
1414

1515
use lightning::blinded_path::{BlindedHop, BlindedPath, IntroductionNode};
16+
use lightning::blinded_path::payment::BlindedPaymentPath;
1617
use lightning::chain::transaction::OutPoint;
1718
use lightning::ln::channel_state::{ChannelCounterparty, ChannelDetails, ChannelShutdownState};
1819
use lightning::ln::channelmanager;
@@ -380,7 +381,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
380381
let mut last_hops_unblinded = Vec::new();
381382
last_hops!(last_hops_unblinded);
382383
let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
383-
let last_hops: Vec<(BlindedPayInfo, BlindedPath)> = last_hops_unblinded
384+
let last_hops: Vec<(BlindedPayInfo, BlindedPaymentPath)> = last_hops_unblinded
384385
.into_iter()
385386
.map(|hint| {
386387
let hop = &hint.0[0];
@@ -402,11 +403,11 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
402403
}
403404
(
404405
payinfo,
405-
BlindedPath {
406+
BlindedPaymentPath(BlindedPath {
406407
introduction_node: IntroductionNode::NodeId(hop.src_node_id),
407408
blinding_point: dummy_pk,
408409
blinded_hops,
409-
},
410+
}),
410411
)
411412
})
412413
.collect();

lightning/src/blinded_path/mod.rs

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use message::MessageContext;
1818
use core::ops::Deref;
1919

2020
use crate::ln::msgs::DecodeError;
21-
use crate::offers::invoice::BlindedPayInfo;
2221
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
2322
use crate::sign::EntropySource;
2423
use crate::util::ser::{Readable, Writeable, Writer};
@@ -154,52 +153,6 @@ impl BlindedPath {
154153
})
155154
}
156155

157-
/// Create a one-hop blinded path for a payment.
158-
pub fn one_hop_for_payment<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
159-
payee_node_id: PublicKey, payee_tlvs: payment::ReceiveTlvs, min_final_cltv_expiry_delta: u16,
160-
entropy_source: ES, secp_ctx: &Secp256k1<T>
161-
) -> Result<(BlindedPayInfo, Self), ()> where ES::Target: EntropySource {
162-
// This value is not considered in pathfinding for 1-hop blinded paths, because it's intended to
163-
// be in relation to a specific channel.
164-
let htlc_maximum_msat = u64::max_value();
165-
Self::new_for_payment(
166-
&[], payee_node_id, payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta,
167-
entropy_source, secp_ctx
168-
)
169-
}
170-
171-
/// Create a blinded path for a payment, to be forwarded along `intermediate_nodes`.
172-
///
173-
/// Errors if:
174-
/// * a provided node id is invalid
175-
/// * [`BlindedPayInfo`] calculation results in an integer overflow
176-
/// * any unknown features are required in the provided [`ForwardTlvs`]
177-
///
178-
/// [`ForwardTlvs`]: crate::blinded_path::payment::ForwardTlvs
179-
// TODO: make all payloads the same size with padding + add dummy hops
180-
pub fn new_for_payment<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
181-
intermediate_nodes: &[payment::ForwardNode], payee_node_id: PublicKey,
182-
payee_tlvs: payment::ReceiveTlvs, htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16,
183-
entropy_source: ES, secp_ctx: &Secp256k1<T>
184-
) -> Result<(BlindedPayInfo, Self), ()> where ES::Target: EntropySource {
185-
let introduction_node = IntroductionNode::NodeId(
186-
intermediate_nodes.first().map_or(payee_node_id, |n| n.node_id)
187-
);
188-
let blinding_secret_bytes = entropy_source.get_secure_random_bytes();
189-
let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
190-
191-
let blinded_payinfo = payment::compute_payinfo(
192-
intermediate_nodes, &payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta
193-
)?;
194-
Ok((blinded_payinfo, BlindedPath {
195-
introduction_node,
196-
blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
197-
blinded_hops: payment::blinded_hops(
198-
secp_ctx, intermediate_nodes, payee_node_id, payee_tlvs, &blinding_secret
199-
).map_err(|_| ())?,
200-
}))
201-
}
202-
203156
/// Returns the introduction [`NodeId`] of the blinded path, if it is publicly reachable (i.e.,
204157
/// it is found in the network graph).
205158
pub fn public_introduction_node_id<'a>(

lightning/src/blinded_path/payment.rs

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
// You may not use this file except in accordance with one or both of these
88
// licenses.
99

10-
//! Data structures and methods for constructing [`BlindedPath`]s to send a payment over.
11-
//!
12-
//! [`BlindedPath`]: crate::blinded_path::BlindedPath
10+
//! Data structures and methods for constructing [`BlindedPaymentPath`]s to send a payment over.
1311
1412
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
1513

@@ -26,7 +24,7 @@ use crate::ln::onion_utils;
2624
use crate::offers::invoice::BlindedPayInfo;
2725
use crate::offers::invoice_request::InvoiceRequestFields;
2826
use crate::offers::offer::OfferId;
29-
use crate::sign::{NodeSigner, Recipient};
27+
use crate::sign::{EntropySource, NodeSigner, Recipient};
3028
use crate::util::ser::{FixedLengthReader, LengthReadableArgs, HighZeroBytesDroppedBigSize, Readable, Writeable, Writer};
3129

3230
use core::mem;
@@ -35,6 +33,55 @@ use core::ops::Deref;
3533
#[allow(unused_imports)]
3634
use crate::prelude::*;
3735

36+
/// A [`BlindedPath`] to be used for sending or receiving a payment, hiding the identity of the
37+
/// recipient.
38+
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
39+
pub struct BlindedPaymentPath(pub BlindedPath);
40+
41+
impl Writeable for BlindedPaymentPath {
42+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
43+
self.0.write(w)
44+
}
45+
}
46+
47+
impl Readable for BlindedPaymentPath {
48+
fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
49+
Ok(Self(BlindedPath::read(r)?))
50+
}
51+
}
52+
53+
impl BlindedPaymentPath {
54+
/// Create a blinded path for a payment, to be forwarded along `intermediate_nodes`.
55+
///
56+
/// Errors if:
57+
/// * a provided node id is invalid
58+
/// * [`BlindedPayInfo`] calculation results in an integer overflow
59+
/// * any unknown features are required in the provided [`ForwardTlvs`]
60+
// TODO: make all payloads the same size with padding + add dummy hops
61+
pub fn new<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
62+
intermediate_nodes: &[ForwardNode], payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs,
63+
htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16, entropy_source: ES,
64+
secp_ctx: &Secp256k1<T>
65+
) -> Result<(BlindedPayInfo, Self), ()> where ES::Target: EntropySource {
66+
let introduction_node = IntroductionNode::NodeId(
67+
intermediate_nodes.first().map_or(payee_node_id, |n| n.node_id)
68+
);
69+
let blinding_secret_bytes = entropy_source.get_secure_random_bytes();
70+
let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
71+
72+
let blinded_payinfo = compute_payinfo(
73+
intermediate_nodes, &payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta
74+
)?;
75+
Ok((blinded_payinfo, Self(BlindedPath {
76+
introduction_node,
77+
blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
78+
blinded_hops: blinded_hops(
79+
secp_ctx, intermediate_nodes, payee_node_id, payee_tlvs, &blinding_secret
80+
).map_err(|_| ())?,
81+
})))
82+
}
83+
}
84+
3885
/// An intermediate node, its outbound channel, and relay parameters.
3986
#[derive(Clone, Debug)]
4087
pub struct ForwardNode {
@@ -117,10 +164,9 @@ pub struct PaymentConstraints {
117164
pub htlc_minimum_msat: u64,
118165
}
119166

120-
/// The context of an inbound payment, which is included in a [`BlindedPath`] via [`ReceiveTlvs`]
121-
/// and surfaced in [`PaymentPurpose`].
167+
/// The context of an inbound payment, which is included in a [`BlindedPaymentPath`] via
168+
/// [`ReceiveTlvs`] and surfaced in [`PaymentPurpose`].
122169
///
123-
/// [`BlindedPath`]: crate::blinded_path::BlindedPath
124170
/// [`PaymentPurpose`]: crate::events::PaymentPurpose
125171
#[derive(Clone, Debug, Eq, PartialEq)]
126172
pub enum PaymentContext {
@@ -286,16 +332,16 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
286332
//
287333
// Will only modify `path` when returning `Ok`.
288334
pub(crate) fn advance_path_by_one<NS: Deref, NL: Deref, T>(
289-
path: &mut BlindedPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1<T>
335+
path: &mut BlindedPaymentPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1<T>
290336
) -> Result<(), ()>
291337
where
292338
NS::Target: NodeSigner,
293339
NL::Target: NodeIdLookUp,
294340
T: secp256k1::Signing + secp256k1::Verification,
295341
{
296-
let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.blinding_point, None)?;
342+
let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.0.blinding_point, None)?;
297343
let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
298-
let encrypted_control_tlvs = &path.blinded_hops.get(0).ok_or(())?.encrypted_payload;
344+
let encrypted_control_tlvs = &path.0.blinded_hops.get(0).ok_or(())?.encrypted_payload;
299345
let mut s = Cursor::new(encrypted_control_tlvs);
300346
let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
301347
match ChaChaPolyReadAdapter::read(&mut reader, rho) {
@@ -307,11 +353,11 @@ where
307353
None => return Err(()),
308354
};
309355
let mut new_blinding_point = onion_utils::next_hop_pubkey(
310-
secp_ctx, path.blinding_point, control_tlvs_ss.as_ref()
356+
secp_ctx, path.0.blinding_point, control_tlvs_ss.as_ref()
311357
).map_err(|_| ())?;
312-
mem::swap(&mut path.blinding_point, &mut new_blinding_point);
313-
path.introduction_node = IntroductionNode::NodeId(next_node_id);
314-
path.blinded_hops.remove(0);
358+
mem::swap(&mut path.0.blinding_point, &mut new_blinding_point);
359+
path.0.introduction_node = IntroductionNode::NodeId(next_node_id);
360+
path.0.blinded_hops.remove(0);
315361
Ok(())
316362
},
317363
_ => Err(())

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
// licenses.
99

1010
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
11-
use crate::blinded_path::BlindedPath;
12-
use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, ReceiveTlvs};
11+
use crate::blinded_path::payment::{BlindedPaymentPath, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, ReceiveTlvs};
1312
use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PaymentFailureReason};
1413
use crate::ln::types::PaymentSecret;
1514
use crate::ln::channelmanager;
@@ -31,7 +30,7 @@ fn blinded_payment_path(
3130
payment_secret: PaymentSecret, intro_node_min_htlc: u64, intro_node_max_htlc: u64,
3231
node_ids: Vec<PublicKey>, channel_upds: &[&msgs::UnsignedChannelUpdate],
3332
keys_manager: &test_utils::TestKeysInterface
34-
) -> (BlindedPayInfo, BlindedPath) {
33+
) -> (BlindedPayInfo, BlindedPaymentPath) {
3534
let mut intermediate_nodes = Vec::new();
3635
let mut intro_node_min_htlc_opt = Some(intro_node_min_htlc);
3736
let mut intro_node_max_htlc_opt = Some(intro_node_max_htlc);
@@ -66,7 +65,7 @@ fn blinded_payment_path(
6665
payment_context: PaymentContext::unknown(),
6766
};
6867
let mut secp_ctx = Secp256k1::new();
69-
BlindedPath::new_for_payment(
68+
BlindedPaymentPath::new(
7069
&intermediate_nodes[..], *node_ids.last().unwrap(), payee_tlvs,
7170
intro_node_max_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_maximum_msat),
7271
TEST_FINAL_CLTV as u16, keys_manager, &secp_ctx
@@ -112,8 +111,8 @@ fn do_one_hop_blinded_path(success: bool) {
112111
payment_context: PaymentContext::unknown(),
113112
};
114113
let mut secp_ctx = Secp256k1::new();
115-
let blinded_path = BlindedPath::one_hop_for_payment(
116-
nodes[1].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16,
114+
let blinded_path = BlindedPaymentPath::new(
115+
&[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
117116
&chanmon_cfgs[1].keys_manager, &secp_ctx
118117
).unwrap();
119118

@@ -155,8 +154,8 @@ fn mpp_to_one_hop_blinded_path() {
155154
},
156155
payment_context: PaymentContext::unknown(),
157156
};
158-
let blinded_path = BlindedPath::one_hop_for_payment(
159-
nodes[3].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16,
157+
let blinded_path = BlindedPaymentPath::new(
158+
&[], nodes[3].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
160159
&chanmon_cfgs[3].keys_manager, &secp_ctx
161160
).unwrap();
162161

@@ -1301,8 +1300,8 @@ fn custom_tlvs_to_blinded_path() {
13011300
payment_context: PaymentContext::unknown(),
13021301
};
13031302
let mut secp_ctx = Secp256k1::new();
1304-
let blinded_path = BlindedPath::one_hop_for_payment(
1305-
nodes[1].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16,
1303+
let blinded_path = BlindedPaymentPath::new(
1304+
&[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
13061305
&chanmon_cfgs[1].keys_manager, &secp_ctx
13071306
).unwrap();
13081307

lightning/src/ln/channelmanager.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use bitcoin::{secp256k1, Sequence};
3434
use crate::blinded_path::message::{MessageContext, OffersContext};
3535
use crate::blinded_path::{BlindedPath, NodeIdLookUp};
3636
use crate::blinded_path::message::ForwardNode;
37-
use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs};
37+
use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs};
3838
use crate::chain;
3939
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
4040
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
@@ -9069,8 +9069,8 @@ where
90699069
/// message.
90709070
///
90719071
/// The resulting invoice uses a [`PaymentHash`] recognized by the [`ChannelManager`] and a
9072-
/// [`BlindedPath`] containing the [`PaymentSecret`] needed to reconstruct the corresponding
9073-
/// [`PaymentPreimage`]. It is returned purely for informational purposes.
9072+
/// [`BlindedPaymentPath`] containing the [`PaymentSecret`] needed to reconstruct the
9073+
/// corresponding [`PaymentPreimage`]. It is returned purely for informational purposes.
90749074
///
90759075
/// # Limitations
90769076
///
@@ -9346,7 +9346,7 @@ where
93469346
/// [`Router::create_blinded_payment_paths`].
93479347
fn create_blinded_payment_paths(
93489348
&self, amount_msats: u64, payment_secret: PaymentSecret, payment_context: PaymentContext
9349-
) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
9349+
) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, ()> {
93509350
let secp_ctx = &self.secp_ctx;
93519351

93529352
let first_hops = self.list_usable_channels();

0 commit comments

Comments
 (0)