use bitcoin::WPubkeyHash;
use lightning::blinded_path::message::MessageContext;
-use lightning::blinded_path::payment::ReceiveTlvs;
+use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
use lightning::blinded_path::BlindedPath;
use lightning::chain;
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
fn create_blinded_payment_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs,
_amount_msats: u64, _secp_ctx: &Secp256k1<T>,
- ) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
+ ) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, ()> {
unreachable!()
}
}
use bitcoin::WPubkeyHash;
use lightning::blinded_path::message::MessageContext;
-use lightning::blinded_path::payment::ReceiveTlvs;
+use lightning::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
use lightning::blinded_path::BlindedPath;
use lightning::chain;
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
fn create_blinded_payment_paths<T: secp256k1::Signing + secp256k1::Verification>(
&self, _recipient: PublicKey, _first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs,
_amount_msats: u64, _secp_ctx: &Secp256k1<T>,
- ) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
+ ) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, ()> {
unreachable!()
}
}
use bitcoin::secp256k1::{self, Keypair, Parity, PublicKey, Secp256k1, SecretKey};
use core::convert::TryFrom;
use lightning::blinded_path::payment::{
- Bolt12OfferContext, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay,
- ReceiveTlvs,
+ BlindedPaymentPath, Bolt12OfferContext, ForwardNode, ForwardTlvs, PaymentConstraints,
+ PaymentContext, PaymentRelay, ReceiveTlvs,
};
-use lightning::blinded_path::BlindedPath;
use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA;
use lightning::ln::features::BlindedHopFeatures;
use lightning::ln::types::PaymentSecret;
node_id: pubkey(43),
htlc_maximum_msat: 1_000_000_000_000,
}];
- let payment_path = BlindedPath::new_for_payment(
+ let payment_path = BlindedPaymentPath::new(
&intermediate_nodes,
pubkey(42),
payee_tlvs,
use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1, SecretKey};
use core::convert::TryFrom;
use lightning::blinded_path::payment::{
- Bolt12RefundContext, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext,
- PaymentRelay, ReceiveTlvs,
+ BlindedPaymentPath, Bolt12RefundContext, ForwardNode, ForwardTlvs, PaymentConstraints,
+ PaymentContext, PaymentRelay, ReceiveTlvs,
};
-use lightning::blinded_path::BlindedPath;
use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA;
use lightning::ln::features::BlindedHopFeatures;
use lightning::ln::types::PaymentSecret;
node_id: pubkey(43),
htlc_maximum_msat: 1_000_000_000_000,
}];
- let payment_path = BlindedPath::new_for_payment(
+ let payment_path = BlindedPaymentPath::new(
&intermediate_nodes,
pubkey(42),
payee_tlvs,
use bitcoin::script::Builder;
use bitcoin::transaction::TxOut;
+use lightning::blinded_path::payment::BlindedPaymentPath;
use lightning::blinded_path::{BlindedHop, BlindedPath, IntroductionNode};
use lightning::chain::transaction::OutPoint;
use lightning::ln::channel_state::{ChannelCounterparty, ChannelDetails, ChannelShutdownState};
let mut last_hops_unblinded = Vec::new();
last_hops!(last_hops_unblinded);
let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
- let last_hops: Vec<(BlindedPayInfo, BlindedPath)> = last_hops_unblinded
+ let last_hops: Vec<(BlindedPayInfo, BlindedPaymentPath)> = last_hops_unblinded
.into_iter()
.map(|hint| {
let hop = &hint.0[0];
}
(
payinfo,
- BlindedPath {
+ BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(hop.src_node_id),
blinding_point: dummy_pk,
blinded_hops,
- },
+ }),
)
})
.collect();
use core::ops::Deref;
use crate::ln::msgs::DecodeError;
-use crate::offers::invoice::BlindedPayInfo;
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
use crate::sign::EntropySource;
use crate::util::ser::{Readable, Writeable, Writer};
})
}
- /// Create a one-hop blinded path for a payment.
- pub fn one_hop_for_payment<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
- payee_node_id: PublicKey, payee_tlvs: payment::ReceiveTlvs, min_final_cltv_expiry_delta: u16,
- entropy_source: ES, secp_ctx: &Secp256k1<T>
- ) -> Result<(BlindedPayInfo, Self), ()> where ES::Target: EntropySource {
- // This value is not considered in pathfinding for 1-hop blinded paths, because it's intended to
- // be in relation to a specific channel.
- let htlc_maximum_msat = u64::max_value();
- Self::new_for_payment(
- &[], payee_node_id, payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta,
- entropy_source, secp_ctx
- )
- }
-
- /// Create a blinded path for a payment, to be forwarded along `intermediate_nodes`.
- ///
- /// Errors if:
- /// * a provided node id is invalid
- /// * [`BlindedPayInfo`] calculation results in an integer overflow
- /// * any unknown features are required in the provided [`ForwardTlvs`]
- ///
- /// [`ForwardTlvs`]: crate::blinded_path::payment::ForwardTlvs
- // TODO: make all payloads the same size with padding + add dummy hops
- pub fn new_for_payment<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
- intermediate_nodes: &[payment::ForwardNode], payee_node_id: PublicKey,
- payee_tlvs: payment::ReceiveTlvs, htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16,
- entropy_source: ES, secp_ctx: &Secp256k1<T>
- ) -> Result<(BlindedPayInfo, Self), ()> where ES::Target: EntropySource {
- let introduction_node = IntroductionNode::NodeId(
- intermediate_nodes.first().map_or(payee_node_id, |n| n.node_id)
- );
- let blinding_secret_bytes = entropy_source.get_secure_random_bytes();
- let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
-
- let blinded_payinfo = payment::compute_payinfo(
- intermediate_nodes, &payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta
- )?;
- Ok((blinded_payinfo, BlindedPath {
- introduction_node,
- blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
- blinded_hops: payment::blinded_hops(
- secp_ctx, intermediate_nodes, payee_node_id, payee_tlvs, &blinding_secret
- ).map_err(|_| ())?,
- }))
- }
-
/// Returns the introduction [`NodeId`] of the blinded path, if it is publicly reachable (i.e.,
/// it is found in the network graph).
pub fn public_introduction_node_id<'a>(
// You may not use this file except in accordance with one or both of these
// licenses.
-//! Data structures and methods for constructing [`BlindedPath`]s to send a payment over.
-//!
-//! [`BlindedPath`]: crate::blinded_path::BlindedPath
+//! Data structures and methods for constructing [`BlindedPaymentPath`]s to send a payment over.
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
use crate::offers::invoice::BlindedPayInfo;
use crate::offers::invoice_request::InvoiceRequestFields;
use crate::offers::offer::OfferId;
-use crate::sign::{NodeSigner, Recipient};
+use crate::sign::{EntropySource, NodeSigner, Recipient};
use crate::util::ser::{FixedLengthReader, LengthReadableArgs, HighZeroBytesDroppedBigSize, Readable, Writeable, Writer};
use core::mem;
#[allow(unused_imports)]
use crate::prelude::*;
+/// A [`BlindedPath`] to be used for sending or receiving a payment, hiding the identity of the
+/// recipient.
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct BlindedPaymentPath(pub BlindedPath);
+
+impl Writeable for BlindedPaymentPath {
+ fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+ self.0.write(w)
+ }
+}
+
+impl Readable for BlindedPaymentPath {
+ fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
+ Ok(Self(BlindedPath::read(r)?))
+ }
+}
+
+impl BlindedPaymentPath {
+ /// Create a one-hop blinded path for a payment.
+ pub fn one_hop<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
+ payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, min_final_cltv_expiry_delta: u16,
+ entropy_source: ES, secp_ctx: &Secp256k1<T>
+ ) -> Result<(BlindedPayInfo, Self), ()> where ES::Target: EntropySource {
+ // This value is not considered in pathfinding for 1-hop blinded paths, because it's intended to
+ // be in relation to a specific channel.
+ let htlc_maximum_msat = u64::max_value();
+ Self::new(
+ &[], payee_node_id, payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta,
+ entropy_source, secp_ctx
+ )
+ }
+
+ /// Create a blinded path for a payment, to be forwarded along `intermediate_nodes`.
+ ///
+ /// Errors if:
+ /// * a provided node id is invalid
+ /// * [`BlindedPayInfo`] calculation results in an integer overflow
+ /// * any unknown features are required in the provided [`ForwardTlvs`]
+ // TODO: make all payloads the same size with padding + add dummy hops
+ pub fn new<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
+ intermediate_nodes: &[ForwardNode], payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs,
+ htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16, entropy_source: ES,
+ secp_ctx: &Secp256k1<T>
+ ) -> Result<(BlindedPayInfo, Self), ()> where ES::Target: EntropySource {
+ let introduction_node = IntroductionNode::NodeId(
+ intermediate_nodes.first().map_or(payee_node_id, |n| n.node_id)
+ );
+ let blinding_secret_bytes = entropy_source.get_secure_random_bytes();
+ let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
+
+ let blinded_payinfo = compute_payinfo(
+ intermediate_nodes, &payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta
+ )?;
+ Ok((blinded_payinfo, Self(BlindedPath {
+ introduction_node,
+ blinding_point: PublicKey::from_secret_key(secp_ctx, &blinding_secret),
+ blinded_hops: blinded_hops(
+ secp_ctx, intermediate_nodes, payee_node_id, payee_tlvs, &blinding_secret
+ ).map_err(|_| ())?,
+ })))
+ }
+}
+
/// An intermediate node, its outbound channel, and relay parameters.
#[derive(Clone, Debug)]
pub struct ForwardNode {
pub htlc_minimum_msat: u64,
}
-/// The context of an inbound payment, which is included in a [`BlindedPath`] via [`ReceiveTlvs`]
-/// and surfaced in [`PaymentPurpose`].
+/// The context of an inbound payment, which is included in a [`BlindedPaymentPath`] via
+/// [`ReceiveTlvs`] and surfaced in [`PaymentPurpose`].
///
-/// [`BlindedPath`]: crate::blinded_path::BlindedPath
/// [`PaymentPurpose`]: crate::events::PaymentPurpose
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PaymentContext {
//
// Will only modify `path` when returning `Ok`.
pub(crate) fn advance_path_by_one<NS: Deref, NL: Deref, T>(
- path: &mut BlindedPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1<T>
+ path: &mut BlindedPaymentPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1<T>
) -> Result<(), ()>
where
NS::Target: NodeSigner,
NL::Target: NodeIdLookUp,
T: secp256k1::Signing + secp256k1::Verification,
{
- let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.blinding_point, None)?;
+ let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.0.blinding_point, None)?;
let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
- let encrypted_control_tlvs = &path.blinded_hops.get(0).ok_or(())?.encrypted_payload;
+ let encrypted_control_tlvs = &path.0.blinded_hops.get(0).ok_or(())?.encrypted_payload;
let mut s = Cursor::new(encrypted_control_tlvs);
let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
match ChaChaPolyReadAdapter::read(&mut reader, rho) {
None => return Err(()),
};
let mut new_blinding_point = onion_utils::next_hop_pubkey(
- secp_ctx, path.blinding_point, control_tlvs_ss.as_ref()
+ secp_ctx, path.0.blinding_point, control_tlvs_ss.as_ref()
).map_err(|_| ())?;
- mem::swap(&mut path.blinding_point, &mut new_blinding_point);
- path.introduction_node = IntroductionNode::NodeId(next_node_id);
- path.blinded_hops.remove(0);
+ mem::swap(&mut path.0.blinding_point, &mut new_blinding_point);
+ path.0.introduction_node = IntroductionNode::NodeId(next_node_id);
+ path.0.blinded_hops.remove(0);
Ok(())
},
_ => Err(())
// licenses.
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
-use crate::blinded_path::BlindedPath;
-use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, ReceiveTlvs};
+use crate::blinded_path::payment::{BlindedPaymentPath, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, ReceiveTlvs};
use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PaymentFailureReason};
use crate::ln::types::PaymentSecret;
use crate::ln::channelmanager;
payment_secret: PaymentSecret, intro_node_min_htlc: u64, intro_node_max_htlc: u64,
node_ids: Vec<PublicKey>, channel_upds: &[&msgs::UnsignedChannelUpdate],
keys_manager: &test_utils::TestKeysInterface
-) -> (BlindedPayInfo, BlindedPath) {
+) -> (BlindedPayInfo, BlindedPaymentPath) {
let mut intermediate_nodes = Vec::new();
let mut intro_node_min_htlc_opt = Some(intro_node_min_htlc);
let mut intro_node_max_htlc_opt = Some(intro_node_max_htlc);
payment_context: PaymentContext::unknown(),
};
let mut secp_ctx = Secp256k1::new();
- BlindedPath::new_for_payment(
+ BlindedPaymentPath::new(
&intermediate_nodes[..], *node_ids.last().unwrap(), payee_tlvs,
intro_node_max_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_maximum_msat),
TEST_FINAL_CLTV as u16, keys_manager, &secp_ctx
payment_context: PaymentContext::unknown(),
};
let mut secp_ctx = Secp256k1::new();
- let blinded_path = BlindedPath::one_hop_for_payment(
- nodes[1].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16,
+ let blinded_path = BlindedPaymentPath::new(
+ &[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&chanmon_cfgs[1].keys_manager, &secp_ctx
).unwrap();
},
payment_context: PaymentContext::unknown(),
};
- let blinded_path = BlindedPath::one_hop_for_payment(
- nodes[3].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16,
+ let blinded_path = BlindedPaymentPath::new(
+ &[], nodes[3].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&chanmon_cfgs[3].keys_manager, &secp_ctx
).unwrap();
payment_context: PaymentContext::unknown(),
};
let mut secp_ctx = Secp256k1::new();
- let blinded_path = BlindedPath::one_hop_for_payment(
- nodes[1].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16,
+ let blinded_path = BlindedPaymentPath::new(
+ &[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&chanmon_cfgs[1].keys_manager, &secp_ctx
).unwrap();
use crate::blinded_path::message::{MessageContext, OffersContext};
use crate::blinded_path::{BlindedPath, NodeIdLookUp};
use crate::blinded_path::message::ForwardNode;
-use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs};
+use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs};
use crate::chain;
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
/// message.
///
/// The resulting invoice uses a [`PaymentHash`] recognized by the [`ChannelManager`] and a
- /// [`BlindedPath`] containing the [`PaymentSecret`] needed to reconstruct the corresponding
- /// [`PaymentPreimage`]. It is returned purely for informational purposes.
+ /// [`BlindedPaymentPath`] containing the [`PaymentSecret`] needed to reconstruct the
+ /// corresponding [`PaymentPreimage`]. It is returned purely for informational purposes.
///
/// # Limitations
///
/// [`Router::create_blinded_payment_paths`].
fn create_blinded_payment_paths(
&self, amount_msats: u64, payment_secret: PaymentSecret, payment_context: PaymentContext
- ) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
+ ) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, ()> {
let secp_ctx = &self.secp_ctx;
let first_hops = self.list_usable_channels();
use bitcoin::secp256k1::{Secp256k1, PublicKey};
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode};
-use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, ReceiveTlvs};
+use crate::blinded_path::payment::{BlindedPaymentPath, PaymentConstraints, PaymentContext, ReceiveTlvs};
use crate::events::{Event, MessageSendEventsProvider};
use crate::ln::PaymentSecret;
use crate::ln::blinded_payment_tests::get_blinded_route_parameters;
payment_context: PaymentContext::unknown(),
};
let mut secp_ctx = Secp256k1::new();
- let blinded_path = BlindedPath::one_hop_for_payment(
- nodes[2].node.get_our_node_id(), payee_tlvs, TEST_FINAL_CLTV as u16,
+ let blinded_path = BlindedPaymentPath::new(
+ &[], nodes[2].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
&chanmon_cfgs[2].keys_manager, &secp_ctx
).unwrap();
let route_params = RouteParameters::from_payment_params_and_value(
sender_intended_htlc_amt_msat: MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY,
total_msat: MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY,
cltv_expiry_height: nodes[0].best_block_info().1 + DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA,
- encrypted_tlvs: &blinded_path.1.blinded_hops[0].encrypted_payload,
- intro_node_blinding_point: Some(blinded_path.1.blinding_point),
+ encrypted_tlvs: &blinded_path.1.0.blinded_hops[0].encrypted_payload,
+ intro_node_blinding_point: Some(blinded_path.1.0.blinding_point),
keysend_preimage: None,
custom_tlvs: &Vec::new()
}.serialized_length();
htlc_maximum_msat: 42_000_000,
features: BlindedHopFeatures::empty(),
},
- BlindedPath {
+ BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(PublicKey::from_slice(&[2; 33]).unwrap()),
blinding_point: PublicKey::from_slice(&[2; 33]).unwrap(),
blinded_hops: vec![
encrypted_payload: vec![42; 1300],
},
],
- }
+ })
)]);
let offer = nodes[1].node.create_offer_builder(None).unwrap().build().unwrap();
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for (_, path) in invoice.payment_paths() {
- assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
+ assert_eq!(path.0.introduction_node, IntroductionNode::NodeId(bob_id));
}
route_bolt12_payment(david, &[charlie, bob, alice], &invoice);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for (_, path) in invoice.payment_paths() {
- assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
+ assert_eq!(path.0.introduction_node, IntroductionNode::NodeId(bob_id));
}
route_bolt12_payment(david, &[charlie, bob, alice], &invoice);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for (_, path) in invoice.payment_paths() {
- assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id));
+ assert_eq!(path.0.introduction_node, IntroductionNode::NodeId(alice_id));
}
route_bolt12_payment(bob, &[alice], &invoice);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for (_, path) in invoice.payment_paths() {
- assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id));
+ assert_eq!(path.0.introduction_node, IntroductionNode::NodeId(alice_id));
}
route_bolt12_payment(bob, &[alice], &invoice);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for (_, path) in invoice.payment_paths() {
- assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id));
+ assert_eq!(path.0.introduction_node, IntroductionNode::NodeId(alice_id));
}
assert!(bob.node.send_payment_for_bolt12_invoice(&invoice, context.as_ref()).is_ok());
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for (_, path) in invoice.payment_paths() {
- assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
+ assert_eq!(path.0.introduction_node, IntroductionNode::NodeId(bob_id));
}
route_bolt12_payment(bob, &[alice], &invoice);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for (_, path) in invoice.payment_paths() {
- assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
+ assert_eq!(path.0.introduction_node, IntroductionNode::NodeId(bob_id));
}
}
.map(|(_, path)| path)
.max_by_key(|path| path.serialized_length())
.map(|largest_path| BlindedTailHopIter {
- hops: largest_path.blinded_hops.iter(),
- blinding_point: largest_path.blinding_point,
+ hops: largest_path.0.blinded_hops.iter(),
+ blinding_point: largest_path.0.blinding_point,
final_value_msat: final_value_msat_with_overpay_buffer,
excess_final_cltv_expiry_delta: 0,
});
/// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
DuplicatePayment,
/// The [`RecipientOnionFields::payment_metadata`], [`RecipientOnionFields::custom_tlvs`], or
- /// [`BlindedPath`]s provided are too large and caused us to exceed the maximum onion packet size
- /// of 1300 bytes.
+ /// [`BlindedPaymentPath`]s provided are too large and caused us to exceed the maximum onion
+ /// packet size of 1300 bytes.
///
- /// [`BlindedPath`]: crate::blinded_path::BlindedPath
+ /// [`BlindedPaymentPath`]: crate::blinded_path::payment::BlindedPaymentPath
OnionPacketSizeExceeded,
}
// Advance any blinded path where the introduction node is our node.
if let Ok(our_node_id) = node_signer.get_node_id(Recipient::Node) {
for (_, path) in payment_params.payee.blinded_route_hints_mut().iter_mut() {
- let introduction_node_id = match path.introduction_node {
+ let introduction_node_id = match path.0.introduction_node {
IntroductionNode::NodeId(pubkey) => pubkey,
IntroductionNode::DirectedShortChannelId(direction, scid) => {
match node_id_lookup.next_node_id(scid) {
//! then sends the invoice to the intended payer, who will then pay it.
//!
//! The payment recipient must include a [`PaymentHash`], so as to reveal the preimage upon payment
-//! receipt, and one or more [`BlindedPath`]s for the payer to use when sending the payment.
+//! receipt, and one or more [`BlindedPaymentPath`]s for the payer to use when sending the payment.
//!
//! ```
//! extern crate bitcoin;
//!
//! # use lightning::ln::types::PaymentHash;
//! # use lightning::offers::invoice::{BlindedPayInfo, ExplicitSigningPubkey, InvoiceBuilder};
-//! # use lightning::blinded_path::BlindedPath;
+//! # use lightning::blinded_path::payment::BlindedPaymentPath;
//! #
-//! # fn create_payment_paths() -> Vec<(BlindedPayInfo, BlindedPath)> { unimplemented!() }
+//! # fn create_payment_paths() -> Vec<(BlindedPayInfo, BlindedPaymentPath)> { unimplemented!() }
//! # fn create_payment_hash() -> PaymentHash { unimplemented!() }
//! #
//! # fn parse_invoice_request(bytes: Vec<u8>) -> Result<(), lightning::offers::parse::Bolt12ParseError> {
use core::hash::{Hash, Hasher};
use crate::io;
use crate::blinded_path::BlindedPath;
+use crate::blinded_path::payment::BlindedPaymentPath;
use crate::ln::types::PaymentHash;
use crate::ln::channelmanager::PaymentId;
use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures};
macro_rules! invoice_explicit_signing_pubkey_builder_methods { ($self: ident, $self_type: ty) => {
#[cfg_attr(c_bindings, allow(dead_code))]
pub(super) fn for_offer(
- invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
+ invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>,
created_at: Duration, payment_hash: PaymentHash, signing_pubkey: PublicKey
) -> Result<Self, Bolt12SemanticError> {
let amount_msats = Self::amount_msats(invoice_request)?;
#[cfg_attr(c_bindings, allow(dead_code))]
pub(super) fn for_refund(
- refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration,
+ refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration,
payment_hash: PaymentHash, signing_pubkey: PublicKey
) -> Result<Self, Bolt12SemanticError> {
let amount_msats = refund.amount_msats();
macro_rules! invoice_derived_signing_pubkey_builder_methods { ($self: ident, $self_type: ty) => {
#[cfg_attr(c_bindings, allow(dead_code))]
pub(super) fn for_offer_using_keys(
- invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
+ invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>,
created_at: Duration, payment_hash: PaymentHash, keys: Keypair
) -> Result<Self, Bolt12SemanticError> {
let amount_msats = Self::amount_msats(invoice_request)?;
#[cfg_attr(c_bindings, allow(dead_code))]
pub(super) fn for_refund_using_keys(
- refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration,
+ refund: &'a Refund, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration,
payment_hash: PaymentHash, keys: Keypair,
) -> Result<Self, Bolt12SemanticError> {
let amount_msats = refund.amount_msats();
#[cfg_attr(c_bindings, allow(dead_code))]
fn fields(
- payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, created_at: Duration,
+ payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, created_at: Duration,
payment_hash: PaymentHash, amount_msats: u64, signing_pubkey: PublicKey
) -> InvoiceFields {
InvoiceFields {
/// Invoice-specific fields for an `invoice` message.
#[derive(Clone, Debug, PartialEq)]
struct InvoiceFields {
- payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
+ payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>,
created_at: Duration,
relative_expiry: Option<Duration>,
payment_hash: PaymentHash,
}
}
- fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPath)] {
+ fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPaymentPath)] {
&self.fields().payment_paths[..]
}
}
tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef, 160..240, {
- (160, paths: (Vec<BlindedPath>, WithoutLength, Iterable<'a, BlindedPathIter<'a>, BlindedPath>)),
+ (160, paths: (Vec<BlindedPaymentPath>, WithoutLength, Iterable<'a, BlindedPathIter<'a>, BlindedPaymentPath>)),
(162, blindedpay: (Vec<BlindedPayInfo>, WithoutLength, Iterable<'a, BlindedPayInfoIter<'a>, BlindedPayInfo>)),
(164, created_at: (u64, HighZeroBytesDroppedBigSize)),
(166, relative_expiry: (u32, HighZeroBytesDroppedBigSize)),
});
pub(super) type BlindedPathIter<'a> = core::iter::Map<
- core::slice::Iter<'a, (BlindedPayInfo, BlindedPath)>,
- for<'r> fn(&'r (BlindedPayInfo, BlindedPath)) -> &'r BlindedPath,
+ core::slice::Iter<'a, (BlindedPayInfo, BlindedPaymentPath)>,
+ for<'r> fn(&'r (BlindedPayInfo, BlindedPaymentPath)) -> &'r BlindedPaymentPath,
>;
pub(super) type BlindedPayInfoIter<'a> = core::iter::Map<
- core::slice::Iter<'a, (BlindedPayInfo, BlindedPath)>,
- for<'r> fn(&'r (BlindedPayInfo, BlindedPath)) -> &'r BlindedPayInfo,
+ core::slice::Iter<'a, (BlindedPayInfo, BlindedPaymentPath)>,
+ for<'r> fn(&'r (BlindedPayInfo, BlindedPaymentPath)) -> &'r BlindedPayInfo,
>;
-/// Information needed to route a payment across a [`BlindedPath`].
+/// Information needed to route a payment across a [`BlindedPaymentPath`].
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct BlindedPayInfo {
/// Base fee charged (in millisatoshi) for the entire blinded path.
}
pub(super) fn construct_payment_paths(
- blinded_payinfos: Option<Vec<BlindedPayInfo>>, blinded_paths: Option<Vec<BlindedPath>>
-) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, Bolt12SemanticError> {
+ blinded_payinfos: Option<Vec<BlindedPayInfo>>, blinded_paths: Option<Vec<BlindedPaymentPath>>
+) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, Bolt12SemanticError> {
match (blinded_payinfos, blinded_paths) {
(_, None) => Err(Bolt12SemanticError::MissingPaths),
(None, _) => Err(Bolt12SemanticError::InvalidPayInfo),
///
/// This is not exported to bindings users as slices with non-reference types cannot be ABI
/// matched in another language.
- pub fn payment_paths(&$self) -> &[(BlindedPayInfo, BlindedPath)] {
+ pub fn payment_paths(&$self) -> &[(BlindedPayInfo, BlindedPaymentPath)] {
$contents.payment_paths()
}
use bitcoin::secp256k1::schnorr::Signature;
use crate::io;
use crate::blinded_path::BlindedPath;
+use crate::blinded_path::payment::BlindedPaymentPath;
use crate::ln::types::PaymentHash;
use crate::ln::channelmanager::PaymentId;
use crate::ln::features::InvoiceRequestFeatures;
/// [`Duration`]: core::time::Duration
#[cfg(feature = "std")]
pub fn respond_with(
- &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash
+ &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash
) -> Result<$builder, Bolt12SemanticError> {
let created_at = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
/// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at
/// [`OfferBuilder::deriving_signing_pubkey`]: crate::offers::offer::OfferBuilder::deriving_signing_pubkey
pub fn respond_with_no_std(
- &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
+ &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash,
created_at: core::time::Duration
) -> Result<$builder, Bolt12SemanticError> {
if $contents.invoice_request_features().requires_unknown_bits() {
#[cfg(test)]
#[allow(dead_code)]
pub(super) fn respond_with_no_std_using_signing_pubkey(
- &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
+ &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash,
created_at: core::time::Duration, signing_pubkey: PublicKey
) -> Result<$builder, Bolt12SemanticError> {
debug_assert!($contents.contents.inner.offer.signing_pubkey().is_none());
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
#[cfg(feature = "std")]
pub fn respond_using_derived_keys(
- &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash
+ &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash
) -> Result<$builder, Bolt12SemanticError> {
let created_at = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
///
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
pub fn respond_using_derived_keys_no_std(
- &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
+ &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash,
created_at: core::time::Duration
) -> Result<$builder, Bolt12SemanticError> {
if $self.inner.invoice_request_features().requires_unknown_bits() {
use crate::sign::EntropySource;
use crate::io;
use crate::blinded_path::BlindedPath;
+use crate::blinded_path::payment::BlindedPaymentPath;
use crate::ln::types::PaymentHash;
use crate::ln::channelmanager::PaymentId;
use crate::ln::features::InvoiceRequestFeatures;
/// [`Duration`]: core::time::Duration
#[cfg(feature = "std")]
pub fn respond_with(
- &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
+ &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash,
signing_pubkey: PublicKey,
) -> Result<$builder, Bolt12SemanticError> {
let created_at = std::time::SystemTime::now()
///
/// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at
pub fn respond_with_no_std(
- &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
+ &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash,
signing_pubkey: PublicKey, created_at: Duration
) -> Result<$builder, Bolt12SemanticError> {
if $self.features().requires_unknown_bits() {
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
#[cfg(feature = "std")]
pub fn respond_using_derived_keys<ES: Deref>(
- &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
+ &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash,
expanded_key: &ExpandedKey, entropy_source: ES
) -> Result<$builder, Bolt12SemanticError>
where
///
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
pub fn respond_using_derived_keys_no_std<ES: Deref>(
- &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
+ &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>, payment_hash: PaymentHash,
created_at: core::time::Duration, expanded_key: &ExpandedKey, entropy_source: ES
) -> Result<$builder, Bolt12SemanticError>
where
//! Data structures and encoding for static BOLT 12 invoices.
+use crate::blinded_path::payment::BlindedPaymentPath;
use crate::blinded_path::BlindedPath;
use crate::io;
use crate::ln::features::{Bolt12InvoiceFeatures, OfferFeatures};
#[derive(Clone, Debug)]
struct InvoiceContents {
offer: OfferContents,
- payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
+ payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>,
created_at: Duration,
relative_expiry: Option<Duration>,
fallbacks: Option<Vec<FallbackAddress>>,
/// Unless [`StaticInvoiceBuilder::relative_expiry`] is set, the invoice will expire 24 hours
/// after `created_at`.
pub fn for_offer_using_derived_keys<T: secp256k1::Signing>(
- offer: &'a Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
+ offer: &'a Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>,
message_paths: Vec<BlindedPath>, created_at: Duration, expanded_key: &ExpandedKey,
nonce: Nonce, secp_ctx: &Secp256k1<T>,
) -> Result<Self, Bolt12SemanticError> {
}
fn new(
- offer: &Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
+ offer: &Offer, payment_paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>,
message_paths: Vec<BlindedPath>, created_at: Duration, signing_pubkey: PublicKey,
) -> Self {
Self {
self.offer.supported_quantity()
}
- fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPath)] {
+ fn payment_paths(&self) -> &[(BlindedPayInfo, BlindedPaymentPath)] {
&self.payment_paths[..]
}
use core::time::Duration;
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode};
+use crate::blinded_path::payment::BlindedPaymentPath;
use crate::sign::EntropySource;
use crate::ln::types::PaymentHash;
use crate::ln::features::BlindedHopFeatures;
SecretKey::from_slice(&[byte; 32]).unwrap()
}
-pub(crate) fn payment_paths() -> Vec<(BlindedPayInfo, BlindedPath)> {
+pub(crate) fn payment_paths() -> Vec<(BlindedPayInfo, BlindedPaymentPath)> {
let paths = vec![
- BlindedPath {
+ BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(pubkey(40)),
blinding_point: pubkey(41),
blinded_hops: vec![
BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 43] },
BlindedHop { blinded_node_id: pubkey(44), encrypted_payload: vec![0; 44] },
],
- },
- BlindedPath {
+ }),
+ BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(pubkey(40)),
blinding_point: pubkey(41),
blinded_hops: vec![
BlindedHop { blinded_node_id: pubkey(45), encrypted_payload: vec![0; 45] },
BlindedHop { blinded_node_id: pubkey(46), encrypted_payload: vec![0; 46] },
],
- },
+ }),
];
let payinfo = vec![
use crate::blinded_path::{BlindedHop, BlindedPath, Direction, IntroductionNode};
use crate::blinded_path::message::{self, MessageContext};
-use crate::blinded_path::payment::{ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs, self};
+use crate::blinded_path::payment::{BlindedPaymentPath, ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs, self};
use crate::ln::{PaymentHash, PaymentPreimage};
use crate::ln::channel_state::ChannelDetails;
use crate::ln::channelmanager::{PaymentId, MIN_FINAL_CLTV_EXPIRY_DELTA, RecipientOnionFields};
> (
&self, recipient: PublicKey, first_hops: Vec<ChannelDetails>, tlvs: ReceiveTlvs,
amount_msats: u64, secp_ctx: &Secp256k1<T>
- ) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
+ ) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, ()> {
// Limit the number of blinded paths that are computed.
const MAX_PAYMENT_PATHS: usize = 3;
})
})
.map(|forward_node| {
- BlindedPath::new_for_payment(
+ BlindedPaymentPath::new(
&[forward_node], recipient, tlvs.clone(), u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA,
&*self.entropy_source, secp_ctx
)
Ok(paths) if !paths.is_empty() => Ok(paths),
_ => {
if network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient)) {
- BlindedPath::one_hop_for_payment(
- recipient, tlvs, MIN_FINAL_CLTV_EXPIRY_DELTA, &*self.entropy_source, secp_ctx
+ BlindedPaymentPath::new(
+ &[], recipient, tlvs, u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, &*self.entropy_source,
+ secp_ctx
).map(|path| vec![path])
} else {
Err(())
self.find_route(payer, route_params, first_hops, inflight_htlcs)
}
- /// Creates [`BlindedPath`]s for payment to the `recipient` node. The channels in `first_hops`
+ /// Creates [`BlindedPaymentPath`]s for payment to the `recipient` node. The channels in `first_hops`
/// are assumed to be with the `recipient`'s peers. The payment secret and any constraints are
/// given in `tlvs`.
fn create_blinded_payment_paths<
> (
&self, recipient: PublicKey, first_hops: Vec<ChannelDetails>, tlvs: ReceiveTlvs,
amount_msats: u64, secp_ctx: &Secp256k1<T>
- ) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()>;
+ ) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, ()>;
}
/// [`ScoreLookUp`] implementation that factors in in-flight HTLC liquidity.
pub channel_features: ChannelFeatures,
/// The fee taken on this hop (for paying for the use of the *next* channel in the path).
/// If this is the last hop in [`Path::hops`]:
- /// * if we're sending to a [`BlindedPath`], this is the fee paid for use of the entire blinded path
+ /// * if we're sending to a [`BlindedPaymentPath`], this is the fee paid for use of the entire
+ /// blinded path
/// * otherwise, this is the full value of this [`Path`]'s part of the payment
- ///
- /// [`BlindedPath`]: crate::blinded_path::BlindedPath
pub fee_msat: u64,
/// The CLTV delta added for this hop.
/// If this is the last hop in [`Path::hops`]:
- /// * if we're sending to a [`BlindedPath`], this is the CLTV delta for the entire blinded path
+ /// * if we're sending to a [`BlindedPaymentPath`], this is the CLTV delta for the entire blinded
+ /// path
/// * otherwise, this is the CLTV delta expected at the destination
- ///
- /// [`BlindedPath`]: crate::blinded_path::BlindedPath
pub cltv_expiry_delta: u32,
/// Indicates whether this hop is possibly announced in the public network graph.
///
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct BlindedTail {
- /// The hops of the [`BlindedPath`] provided by the recipient.
- ///
- /// [`BlindedPath`]: crate::blinded_path::BlindedPath
+ /// The hops of the [`BlindedPaymentPath`] provided by the recipient.
pub hops: Vec<BlindedHop>,
- /// The blinding point of the [`BlindedPath`] provided by the recipient.
- ///
- /// [`BlindedPath`]: crate::blinded_path::BlindedPath
+ /// The blinding point of the [`BlindedPaymentPath`] provided by the recipient.
pub blinding_point: PublicKey,
/// Excess CLTV delta added to the recipient's CLTV expiry to deter intermediate nodes from
/// inferring the destination. May be 0.
}
/// Creates parameters for paying to a blinded payee from the provided blinded route hints.
- pub fn blinded(blinded_route_hints: Vec<(BlindedPayInfo, BlindedPath)>) -> Self {
+ pub fn blinded(blinded_route_hints: Vec<(BlindedPayInfo, BlindedPaymentPath)>) -> Self {
Self {
payee: Payee::Blinded { route_hints: blinded_route_hints, features: None },
expiry_time: None,
pub(crate) fn insert_previously_failed_blinded_path(&mut self, failed_blinded_tail: &BlindedTail) {
let mut found_blinded_tail = false;
for (idx, (_, path)) in self.payee.blinded_route_hints().iter().enumerate() {
- if failed_blinded_tail.hops == path.blinded_hops &&
- failed_blinded_tail.blinding_point == path.blinding_point
+ if failed_blinded_tail.hops == path.0.blinded_hops &&
+ failed_blinded_tail.blinding_point == path.0.blinding_point
{
self.previously_failed_blinded_path_idxs.push(idx as u64);
found_blinded_tail = true;
Blinded {
/// Aggregated routing info and blinded paths, for routing to the payee without knowing their
/// node id.
- route_hints: Vec<(BlindedPayInfo, BlindedPath)>,
+ route_hints: Vec<(BlindedPayInfo, BlindedPaymentPath)>,
/// Features supported by the payee.
///
/// May be set from the payee's invoice. May be `None` if the invoice does not contain any
_ => None,
}
}
- pub(crate) fn blinded_route_hints(&self) -> &[(BlindedPayInfo, BlindedPath)] {
+ pub(crate) fn blinded_route_hints(&self) -> &[(BlindedPayInfo, BlindedPaymentPath)] {
match self {
Self::Blinded { route_hints, .. } => &route_hints[..],
Self::Clear { .. } => &[]
}
}
- pub(crate) fn blinded_route_hints_mut(&mut self) -> &mut [(BlindedPayInfo, BlindedPath)] {
+ pub(crate) fn blinded_route_hints_mut(&mut self) -> &mut [(BlindedPayInfo, BlindedPaymentPath)] {
match self {
Self::Blinded { route_hints, .. } => &mut route_hints[..],
Self::Clear { .. } => &mut []
/// cryptographic material required to build an HTLC through the given path.
///
/// This is not exported to bindings users as lifetimes are not expressible in most languages.
- pub hint: &'a (BlindedPayInfo, BlindedPath),
+ pub hint: &'a (BlindedPayInfo, BlindedPaymentPath),
/// Index of the hint in the original list of blinded hints.
///
/// This is used to cheaply uniquely identify this blinded path, even though we don't have
/// Note that the [`BlindedPayInfo`] is ignored here.
///
/// This is not exported to bindings users as lifetimes are not expressible in most languages.
- pub hint: &'a (BlindedPayInfo, BlindedPath),
+ pub hint: &'a (BlindedPayInfo, BlindedPaymentPath),
/// Index of the hint in the original list of blinded hints.
///
/// This is used to cheaply uniquely identify this blinded path, even though we don't have
_ => CandidateHopId::Clear((self.short_channel_id().unwrap(), self.source() < self.target().unwrap())),
}
}
- fn blinded_path(&self) -> Option<&'a BlindedPath> {
+ fn blinded_path(&self) -> Option<&'a BlindedPaymentPath> {
match self {
CandidateRouteHop::Blinded(BlindedPathCandidate { hint, .. }) | CandidateRouteHop::OneHopBlinded(OneHopBlindedPathCandidate { hint, .. }) => {
Some(&hint.1)
where L::Target: Logger {
let introduction_node_id_cache = payment_params.payee.blinded_route_hints().iter()
.map(|(_, path)| {
- match &path.introduction_node {
+ match &path.0.introduction_node {
IntroductionNode::NodeId(pubkey) => {
// Note that this will only return `Some` if the `pubkey` is somehow known to
// us (i.e. a channel counterparty or in the network graph).
node_counters.node_counter_from_id(&NodeId::from_pubkey(&pubkey))
},
IntroductionNode::DirectedShortChannelId(direction, scid) => {
- path.public_introduction_node_id(network_graph)
+ path.0.public_introduction_node_id(network_graph)
.map(|node_id_ref| *node_id_ref)
.or_else(|| {
first_hop_targets.iter().find(|(_, (channels, _))|
return Err(LightningError{err: "Cannot generate a route to blinded paths if we are the introduction node to all of them".to_owned(), action: ErrorAction::IgnoreError});
}
for ((_, blinded_path), info_opt) in route_hints.iter().zip(introduction_node_id_cache.iter()) {
- if blinded_path.blinded_hops.len() == 0 {
+ if blinded_path.0.blinded_hops.len() == 0 {
return Err(LightningError{err: "0-hop blinded path provided".to_owned(), action: ErrorAction::IgnoreError});
}
let introduction_node_id = match info_opt {
};
if *introduction_node_id == our_node_id {
log_info!(logger, "Got blinded path with ourselves as the introduction node, ignoring");
- } else if blinded_path.blinded_hops.len() == 1 &&
+ } else if blinded_path.0.blinded_hops.len() == 1 &&
route_hints
.iter().zip(introduction_node_id_cache.iter())
- .filter(|((_, p), _)| p.blinded_hops.len() == 1)
+ .filter(|((_, p), _)| p.0.blinded_hops.len() == 1)
.any(|(_, iter_info_opt)| iter_info_opt.is_some() && iter_info_opt != info_opt)
{
return Err(LightningError{err: format!("1-hop blinded paths must all have matching introduction node ids"), action: ErrorAction::IgnoreError});
match self.0 {
CandidateRouteHop::Blinded(BlindedPathCandidate { hint, .. }) | CandidateRouteHop::OneHopBlinded(OneHopBlindedPathCandidate { hint, .. }) => {
"blinded route hint with introduction node ".fmt(f)?;
- match &hint.1.introduction_node {
+ match &hint.1.0.introduction_node {
IntroductionNode::NodeId(pubkey) => write!(f, "id {}", pubkey)?,
IntroductionNode::DirectedShortChannelId(direction, scid) => {
match direction {
}
}
" and blinding point ".fmt(f)?;
- hint.1.blinding_point.fmt(f)
+ hint.1.0.blinding_point.fmt(f)
},
CandidateRouteHop::FirstHop(_) => {
"first hop with SCID ".fmt(f)?;
let source_node_opt = introduction_node_id_cache[hint_idx];
let (source_node_id, source_node_counter) = if let Some(v) = source_node_opt { v } else { continue };
if our_node_id == *source_node_id { continue }
- let candidate = if hint.1.blinded_hops.len() == 1 {
+ let candidate = if hint.1.0.blinded_hops.len() == 1 {
CandidateRouteHop::OneHopBlinded(
OneHopBlindedPathCandidate { source_node_counter, source_node_id, hint, hint_idx }
)
if let Some(blinded_path) = h.candidate.blinded_path() {
final_cltv_delta = h.candidate.cltv_expiry_delta();
Some(BlindedTail {
- hops: blinded_path.blinded_hops.clone(),
- blinding_point: blinded_path.blinding_point,
+ hops: blinded_path.0.blinded_hops.clone(),
+ blinding_point: blinded_path.0.blinding_point,
excess_final_cltv_expiry_delta: 0,
final_value_msat: h.fee_msat,
})
#[cfg(test)]
mod tests {
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode};
+ use crate::blinded_path::payment::BlindedPaymentPath;
use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, EffectiveCapacity};
use crate::routing::utxo::UtxoResult;
use crate::routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features,
// MPP to a 1-hop blinded path for nodes[2]
let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config);
- let blinded_path = BlindedPath {
+ let blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(nodes[2]),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }],
- };
+ });
let blinded_payinfo = BlindedPayInfo { // These fields are ignored for 1-hop blinded paths
fee_base_msat: 0,
fee_proportional_millionths: 0,
// MPP to 3 2-hop blinded paths
let mut blinded_path_node_0 = blinded_path.clone();
- blinded_path_node_0.introduction_node = IntroductionNode::NodeId(nodes[0]);
- blinded_path_node_0.blinded_hops.push(blinded_path.blinded_hops[0].clone());
+ blinded_path_node_0.0.introduction_node = IntroductionNode::NodeId(nodes[0]);
+ blinded_path_node_0.0.blinded_hops.push(blinded_path.0.blinded_hops[0].clone());
let mut node_0_payinfo = blinded_payinfo.clone();
node_0_payinfo.htlc_maximum_msat = 50_000;
let mut blinded_path_node_7 = blinded_path_node_0.clone();
- blinded_path_node_7.introduction_node = IntroductionNode::NodeId(nodes[7]);
+ blinded_path_node_7.0.introduction_node = IntroductionNode::NodeId(nodes[7]);
let mut node_7_payinfo = blinded_payinfo.clone();
node_7_payinfo.htlc_maximum_msat = 60_000;
let mut blinded_path_node_1 = blinded_path_node_0.clone();
- blinded_path_node_1.introduction_node = IntroductionNode::NodeId(nodes[1]);
+ blinded_path_node_1.0.introduction_node = IntroductionNode::NodeId(nodes[1]);
let mut node_1_payinfo = blinded_payinfo.clone();
node_1_payinfo.htlc_maximum_msat = 180_000;
NodeId::from_pubkey(&path.hops.last().unwrap().pubkey),
payment_params.payee.blinded_route_hints().iter()
.find(|(p, _)| p.htlc_maximum_msat == path.final_value_msat())
- .and_then(|(_, p)| p.public_introduction_node_id(&network_graph))
+ .and_then(|(_, p)| p.0.public_introduction_node_id(&network_graph))
.copied()
.unwrap()
);
assert_eq!(route.get_total_amount(), amt_msat);
// Make sure this works for blinded route hints.
- let blinded_path = BlindedPath {
+ let blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(intermed_node_id),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42), encrypted_payload: vec![] },
BlindedHop { blinded_node_id: ln_test_utils::pubkey(43), encrypted_payload: vec![] },
],
- };
+ });
let blinded_payinfo = BlindedPayInfo {
fee_base_msat: 100,
fee_proportional_millionths: 0,
let scorer = ln_test_utils::TestScorer::new();
let random_seed_bytes = [42; 32];
- let mut blinded_path = BlindedPath {
+ let mut blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(nodes[2]),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: Vec::with_capacity(num_blinded_hops),
- };
+ });
for i in 0..num_blinded_hops {
- blinded_path.blinded_hops.push(
+ blinded_path.0.blinded_hops.push(
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 + i as u8), encrypted_payload: Vec::new() },
);
}
assert_eq!(route.paths[0].hops.len(), 2);
let tail = route.paths[0].blinded_tail.as_ref().unwrap();
- assert_eq!(tail.hops, blinded_path.blinded_hops);
+ assert_eq!(tail.hops, blinded_path.0.blinded_hops);
assert_eq!(tail.excess_final_cltv_expiry_delta, 0);
assert_eq!(tail.final_value_msat, 1001);
let final_hop = route.paths[0].hops.last().unwrap();
assert_eq!(
NodeId::from_pubkey(&final_hop.pubkey),
- *blinded_path.public_introduction_node_id(&network_graph).unwrap()
+ *blinded_path.0.public_introduction_node_id(&network_graph).unwrap()
);
if tail.hops.len() > 1 {
assert_eq!(final_hop.fee_msat,
let scorer = ln_test_utils::TestScorer::new();
let random_seed_bytes = [42; 32];
- let mut invalid_blinded_path = BlindedPath {
+ let mut invalid_blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(nodes[2]),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(43), encrypted_payload: vec![0; 43] },
],
- };
+ });
let blinded_payinfo = BlindedPayInfo {
fee_base_msat: 100,
fee_proportional_millionths: 500,
};
let mut invalid_blinded_path_2 = invalid_blinded_path.clone();
- invalid_blinded_path_2.introduction_node = IntroductionNode::NodeId(nodes[3]);
+ invalid_blinded_path_2.0.introduction_node = IntroductionNode::NodeId(nodes[3]);
let payment_params = PaymentParameters::blinded(vec![
(blinded_payinfo.clone(), invalid_blinded_path.clone()),
(blinded_payinfo.clone(), invalid_blinded_path_2)]);
_ => panic!("Expected error")
}
- invalid_blinded_path.introduction_node = IntroductionNode::NodeId(our_id);
+ invalid_blinded_path.0.introduction_node = IntroductionNode::NodeId(our_id);
let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo.clone(), invalid_blinded_path.clone())]);
let route_params = RouteParameters::from_payment_params_and_value(payment_params, 1001);
match get_route(&our_id, &route_params, &network_graph, None, Arc::clone(&logger), &scorer,
_ => panic!("Expected error")
}
- invalid_blinded_path.introduction_node = IntroductionNode::NodeId(ln_test_utils::pubkey(46));
- invalid_blinded_path.blinded_hops.clear();
+ invalid_blinded_path.0.introduction_node = IntroductionNode::NodeId(ln_test_utils::pubkey(46));
+ invalid_blinded_path.0.blinded_hops.clear();
let payment_params = PaymentParameters::blinded(vec![(blinded_payinfo, invalid_blinded_path)]);
let route_params = RouteParameters::from_payment_params_and_value(payment_params, 1001);
match get_route(&our_id, &route_params, &network_graph, None, Arc::clone(&logger), &scorer,
let config = UserConfig::default();
let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config);
- let blinded_path_1 = BlindedPath {
+ let blinded_path_1 = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(nodes[2]),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
],
- };
+ });
let blinded_payinfo_1 = BlindedPayInfo {
fee_base_msat: 0,
fee_proportional_millionths: 0,
};
let mut blinded_path_2 = blinded_path_1.clone();
- blinded_path_2.blinding_point = ln_test_utils::pubkey(43);
+ blinded_path_2.0.blinding_point = ln_test_utils::pubkey(43);
let mut blinded_payinfo_2 = blinded_payinfo_1.clone();
blinded_payinfo_2.htlc_maximum_msat = 70_000;
if let Some(bt) = &path.blinded_tail {
assert_eq!(bt.blinding_point,
blinded_hints.iter().find(|(p, _)| p.htlc_maximum_msat == path.final_value_msat())
- .map(|(_, bp)| bp.blinding_point).unwrap());
+ .map(|(_, bp)| bp.0.blinding_point).unwrap());
} else { panic!(); }
total_amount_paid_msat += path.final_value_msat();
}
let first_hops = vec![
get_channel_details(Some(1), nodes[1], InitFeatures::from_le_bytes(vec![0b11]), 10_000_000)];
- let blinded_path = BlindedPath {
+ let blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(nodes[1]),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
],
- };
+ });
let blinded_payinfo = BlindedPayInfo {
fee_base_msat: 1000,
fee_proportional_millionths: 0,
get_channel_details(Some(1), nodes[1], channelmanager::provided_init_features(&config),
18446744073709551615)];
- let blinded_path = BlindedPath {
+ let blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(nodes[1]),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
],
- };
+ });
let blinded_payinfo = BlindedPayInfo {
fee_base_msat: 5046_2720,
fee_proportional_millionths: 0,
// Values are taken from the fuzz input that uncovered this panic.
let amt_msat = 21_7020_5185_1423_0019;
- let blinded_path = BlindedPath {
+ let blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(our_id),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
],
- };
+ });
let blinded_payinfo = BlindedPayInfo {
fee_base_msat: 5052_9027,
fee_proportional_millionths: 0,
(blinded_payinfo.clone(), blinded_path.clone()),
(blinded_payinfo.clone(), blinded_path.clone()),
];
- blinded_hints[1].1.introduction_node = IntroductionNode::NodeId(nodes[6]);
+ blinded_hints[1].1.0.introduction_node = IntroductionNode::NodeId(nodes[6]);
let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config);
let payment_params = PaymentParameters::blinded(blinded_hints.clone())
// Values are taken from the fuzz input that uncovered this panic.
let amt_msat = 21_7020_5185_1423_0019;
- let blinded_path = BlindedPath {
+ let blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(our_id),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
],
- };
+ });
let blinded_payinfo = BlindedPayInfo {
fee_base_msat: 10_4425_1395,
fee_proportional_millionths: 0,
blinded_hints[1].0.htlc_minimum_msat = 21_7020_5185_1423_0019;
blinded_hints[1].0.htlc_maximum_msat = 1844_6744_0737_0955_1615;
- blinded_hints[2].1.introduction_node = IntroductionNode::NodeId(nodes[6]);
+ blinded_hints[2].1.0.introduction_node = IntroductionNode::NodeId(nodes[6]);
let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config);
let payment_params = PaymentParameters::blinded(blinded_hints.clone())
let base_fee = 1_6778_3453;
let htlc_min = 2_5165_8240;
let payment_params = if blinded_payee {
- let blinded_path = BlindedPath {
+ let blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(nodes[0]),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
],
- };
+ });
let blinded_payinfo = BlindedPayInfo {
fee_base_msat: base_fee,
fee_proportional_millionths: 0,
let base_fees = [0, 425_9840, 0, 0];
let htlc_mins = [1_4392, 19_7401, 1027, 6_5535];
let payment_params = if blinded_payee {
- let blinded_path = BlindedPath {
+ let blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(nodes[0]),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
],
- };
+ });
let mut blinded_hints = Vec::new();
for (base_fee, htlc_min) in base_fees.iter().zip(htlc_mins.iter()) {
blinded_hints.push((BlindedPayInfo {
htlc_maximum_msat: htlc_min * 100,
cltv_expiry_delta: 10,
features: BlindedHopFeatures::empty(),
- }, BlindedPath {
+ }, BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(nodes[0]),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
],
- })
+ }))
];
let bolt12_features = channelmanager::provided_bolt12_invoice_features(&config);
let payment_params = PaymentParameters::blinded(blinded_hints.clone())
let htlc_mins = [49_0000, 1125_0000];
let payment_params = {
- let blinded_path = BlindedPath {
+ let blinded_path = BlindedPaymentPath(BlindedPath {
introduction_node: IntroductionNode::NodeId(nodes[0]),
blinding_point: ln_test_utils::pubkey(42),
blinded_hops: vec![
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() },
BlindedHop { blinded_node_id: ln_test_utils::pubkey(42 as u8), encrypted_payload: Vec::new() }
],
- };
+ });
let mut blinded_hints = Vec::new();
for htlc_min in htlc_mins.iter() {
blinded_hints.push((BlindedPayInfo {
use crate::blinded_path::message::MessageContext;
use crate::blinded_path::BlindedPath;
use crate::blinded_path::message::ForwardNode;
-use crate::blinded_path::payment::ReceiveTlvs;
+use crate::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs};
use crate::chain;
use crate::chain::WatchedOutput;
use crate::chain::chaininterface;
>,
pub network_graph: Arc<NetworkGraph<&'a TestLogger>>,
pub next_routes: Mutex<VecDeque<(RouteParameters, Option<Result<Route, LightningError>>)>>,
- pub next_blinded_payment_paths: Mutex<Vec<(BlindedPayInfo, BlindedPath)>>,
+ pub next_blinded_payment_paths: Mutex<Vec<(BlindedPayInfo, BlindedPaymentPath)>>,
pub scorer: &'a RwLock<TestScorer>,
}
expected_routes.push_back((query, None));
}
- pub fn expect_blinded_payment_paths(&self, mut paths: Vec<(BlindedPayInfo, BlindedPath)>) {
+ pub fn expect_blinded_payment_paths(&self, mut paths: Vec<(BlindedPayInfo, BlindedPaymentPath)>) {
let mut expected_paths = self.next_blinded_payment_paths.lock().unwrap();
core::mem::swap(&mut *expected_paths, &mut paths);
}
>(
&self, recipient: PublicKey, first_hops: Vec<ChannelDetails>, tlvs: ReceiveTlvs,
amount_msats: u64, secp_ctx: &Secp256k1<T>,
- ) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
+ ) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, ()> {
let mut expected_paths = self.next_blinded_payment_paths.lock().unwrap();
if expected_paths.is_empty() {
self.router.create_blinded_payment_paths(