Skip to content

Move BlindedPayInfo into BlindedPaymentPath #3245

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use lightning::ln::msgs::{
};
use lightning::ln::script::ShutdownScript;
use lightning::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
use lightning::offers::invoice::UnsignedBolt12Invoice;
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
use lightning::routing::router::{InFlightHtlcs, Path, Route, RouteHop, RouteParameters, Router};
Expand Down Expand Up @@ -126,7 +126,7 @@ impl Router for FuzzRouter {
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, BlindedPaymentPath)>, ()> {
) -> Result<Vec<BlindedPaymentPath>, ()> {
unreachable!()
}
}
Expand Down
4 changes: 2 additions & 2 deletions fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use lightning::ln::peer_handler::{
};
use lightning::ln::script::ShutdownScript;
use lightning::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
use lightning::offers::invoice::UnsignedBolt12Invoice;
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessagePath};
use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
Expand Down Expand Up @@ -163,7 +163,7 @@ impl Router for FuzzRouter {
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, BlindedPaymentPath)>, ()> {
) -> Result<Vec<BlindedPaymentPath>, ()> {
unreachable!()
}
}
Expand Down
11 changes: 6 additions & 5 deletions fuzz/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@ use bitcoin::constants::ChainHash;
use bitcoin::script::Builder;
use bitcoin::transaction::TxOut;

use lightning::blinded_path::payment::BlindedPaymentPath;
use lightning::blinded_path::payment::{BlindedPayInfo, BlindedPaymentPath};
use lightning::blinded_path::BlindedHop;
use lightning::chain::transaction::OutPoint;
use lightning::ln::channel_state::{ChannelCounterparty, ChannelDetails, ChannelShutdownState};
use lightning::ln::channelmanager;
use lightning::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures};
use lightning::ln::msgs;
use lightning::ln::types::ChannelId;
use lightning::offers::invoice::BlindedPayInfo;
use lightning::routing::gossip::{NetworkGraph, RoutingFees};
use lightning::routing::router::{
find_route, PaymentParameters, RouteHint, RouteHintHop, RouteParameters,
Expand Down Expand Up @@ -381,7 +380,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
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, BlindedPaymentPath)> = last_hops_unblinded
let last_hops: Vec<BlindedPaymentPath> = last_hops_unblinded
.into_iter()
.map(|hint| {
let hop = &hint.0[0];
Expand All @@ -401,9 +400,11 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
encrypted_payload: Vec::new(),
});
}
(
BlindedPaymentPath::from_raw(
hop.src_node_id,
dummy_pk,
blinded_hops,
payinfo,
BlindedPaymentPath::from_raw(hop.src_node_id, dummy_pk, blinded_hops),
)
})
.collect();
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/blinded_path/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::prelude::*;
/// Onion messages and payments can be sent and received to blinded paths, which serve to hide the
/// identity of the recipient.
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct BlindedPath {
pub(crate) struct BlindedPath {
/// To send to a blinded path, the sender first finds a route to the unblinded
/// `introduction_node`, which can unblind its [`encrypted_payload`] to find out the onion
/// message or payment's next hop and forward it along.
Expand Down
122 changes: 83 additions & 39 deletions lightning/src/blinded_path/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use crate::ln::channel_state::CounterpartyForwardingInfo;
use crate::ln::features::BlindedHopFeatures;
use crate::ln::msgs::DecodeError;
use crate::ln::onion_utils;
use crate::offers::invoice::BlindedPayInfo;
use crate::offers::invoice_request::InvoiceRequestFields;
use crate::offers::offer::OfferId;
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
Expand All @@ -34,29 +33,59 @@ use core::ops::Deref;
#[allow(unused_imports)]
use crate::prelude::*;

/// A blinded path 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(super) 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 fee_base_msat: u32,

impl Writeable for BlindedPaymentPath {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
self.0.write(w)
}
/// Liquidity fee charged (in millionths of the amount transferred) for the entire blinded path
/// (i.e., 10,000 is 1%).
pub fee_proportional_millionths: u32,

/// Number of blocks subtracted from an incoming HTLC's `cltv_expiry` for the entire blinded
/// path.
pub cltv_expiry_delta: u16,

/// The minimum HTLC value (in millisatoshi) that is acceptable to all channel peers on the
/// blinded path from the introduction node to the recipient, accounting for any fees, i.e., as
/// seen by the recipient.
pub htlc_minimum_msat: u64,

/// The maximum HTLC value (in millisatoshi) that is acceptable to all channel peers on the
/// blinded path from the introduction node to the recipient, accounting for any fees, i.e., as
/// seen by the recipient.
pub htlc_maximum_msat: u64,

/// Features set in `encrypted_data_tlv` for the `encrypted_recipient_data` TLV record in an
/// onion payload.
pub features: BlindedHopFeatures,
}

impl Readable for BlindedPaymentPath {
fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
Ok(Self(BlindedPath::read(r)?))
}
impl_writeable!(BlindedPayInfo, {
fee_base_msat,
fee_proportional_millionths,
cltv_expiry_delta,
htlc_minimum_msat,
htlc_maximum_msat,
features
});

/// A blinded path 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(super) inner_path: BlindedPath,
/// The [`BlindedPayInfo`] used to pay this blinded path.
pub payinfo: BlindedPayInfo,
}

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 {
) -> Result<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();
Expand All @@ -77,7 +106,7 @@ impl BlindedPaymentPath {
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 {
) -> Result<Self, ()> where ES::Target: EntropySource {
let introduction_node = IntroductionNode::NodeId(
intermediate_nodes.first().map_or(payee_node_id, |n| n.node_id)
);
Expand All @@ -87,38 +116,41 @@ impl BlindedPaymentPath {
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(|_| ())?,
})))
Ok(Self {
inner_path: 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(|_| ())?,
},
payinfo: blinded_payinfo
})
}

/// 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>(
&self, network_graph: &'a ReadOnlyNetworkGraph
) -> Option<&'a NodeId> {
self.0.public_introduction_node_id(network_graph)
self.inner_path.public_introduction_node_id(network_graph)
}

/// The [`IntroductionNode`] of the blinded path.
pub fn introduction_node(&self) -> &IntroductionNode {
&self.0.introduction_node
&self.inner_path.introduction_node
}

/// Used by the [`IntroductionNode`] to decrypt its [`encrypted_payload`] to forward the payment.
///
/// [`encrypted_payload`]: BlindedHop::encrypted_payload
pub fn blinding_point(&self) -> PublicKey {
self.0.blinding_point
self.inner_path.blinding_point
}

/// The [`BlindedHop`]s within the blinded path.
pub fn blinded_hops(&self) -> &[BlindedHop] {
&self.0.blinded_hops
&self.inner_path.blinded_hops
}

/// Advance the blinded onion payment path by one hop, making the second hop into the new
Expand All @@ -133,9 +165,9 @@ impl BlindedPaymentPath {
NL::Target: NodeIdLookUp,
T: secp256k1::Signing + secp256k1::Verification,
{
let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.0.blinding_point, None)?;
let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.inner_path.blinding_point, None)?;
let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
let encrypted_control_tlvs = &self.0.blinded_hops.get(0).ok_or(())?.encrypted_payload;
let encrypted_control_tlvs = &self.inner_path.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) {
Expand All @@ -147,31 +179,43 @@ impl BlindedPaymentPath {
None => return Err(()),
};
let mut new_blinding_point = onion_utils::next_hop_pubkey(
secp_ctx, self.0.blinding_point, control_tlvs_ss.as_ref()
secp_ctx, self.inner_path.blinding_point, control_tlvs_ss.as_ref()
).map_err(|_| ())?;
mem::swap(&mut self.0.blinding_point, &mut new_blinding_point);
self.0.introduction_node = IntroductionNode::NodeId(next_node_id);
self.0.blinded_hops.remove(0);
mem::swap(&mut self.inner_path.blinding_point, &mut new_blinding_point);
self.inner_path.introduction_node = IntroductionNode::NodeId(next_node_id);
self.inner_path.blinded_hops.remove(0);
Ok(())
},
_ => Err(())
}
}

pub(crate) fn inner_blinded_path(&self) -> &BlindedPath {
&self.inner_path
}

pub(crate) fn from_parts(inner_path: BlindedPath, payinfo: BlindedPayInfo) -> Self {
Self { inner_path, payinfo }
}

#[cfg(any(test, fuzzing))]
pub fn from_raw(
introduction_node_id: PublicKey, blinding_point: PublicKey, blinded_hops: Vec<BlindedHop>
introduction_node_id: PublicKey, blinding_point: PublicKey, blinded_hops: Vec<BlindedHop>,
payinfo: BlindedPayInfo
) -> Self {
Self(BlindedPath {
introduction_node: IntroductionNode::NodeId(introduction_node_id),
blinding_point,
blinded_hops,
})
Self {
inner_path: BlindedPath {
introduction_node: IntroductionNode::NodeId(introduction_node_id),
blinding_point,
blinded_hops,
},
payinfo
}
}

#[cfg(test)]
pub fn clear_blinded_hops(&mut self) {
self.0.blinded_hops.clear()
self.inner_path.blinded_hops.clear()
}
}

Expand Down
13 changes: 7 additions & 6 deletions lightning/src/ln/blinded_payment_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::ln::onion_payment;
use crate::ln::onion_utils;
use crate::ln::onion_utils::INVALID_ONION_BLINDING;
use crate::ln::outbound_payment::{Retry, IDEMPOTENCY_TIMEOUT_TICKS};
use crate::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
use crate::offers::invoice::UnsignedBolt12Invoice;
use crate::offers::invoice_request::UnsignedInvoiceRequest;
use crate::prelude::*;
use crate::routing::router::{BlindedTail, Path, Payee, PaymentParameters, RouteHop, RouteParameters};
Expand All @@ -39,7 +39,7 @@ fn blinded_payment_path(
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, BlindedPaymentPath) {
) -> 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);
Expand Down Expand Up @@ -839,11 +839,12 @@ fn do_multi_hop_receiver_fail(check: ReceiveCheckFail) {
nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(), &[&high_htlc_minimum_upd],
&chanmon_cfgs[2].keys_manager);
if let Payee::Blinded { route_hints, .. } = high_htlc_min_params.payment_params.payee {
route_hints[0].1.clone()
route_hints[0].clone()
} else { panic!() }
};
if let Payee::Blinded { ref mut route_hints, .. } = route_params.payment_params.payee {
route_hints[0].1 = high_htlc_min_bp;
route_hints[0] = high_htlc_min_bp;
route_hints[0].payinfo.htlc_minimum_msat = amt_msat;
} else { panic!() }
find_route(&nodes[0], &route_params).unwrap()
} else {
Expand Down Expand Up @@ -1121,7 +1122,7 @@ fn min_htlc() {
nodes[2].node.get_our_node_id(), nodes[3].node.get_our_node_id()],
&[&chan_1_2.0.contents, &chan_2_3.0.contents], &chanmon_cfgs[3].keys_manager);
assert_eq!(min_htlc_msat,
route_params.payment_params.payee.blinded_route_hints()[0].0.htlc_minimum_msat);
route_params.payment_params.payee.blinded_route_hints()[0].payinfo.htlc_minimum_msat);

nodes[0].node.send_payment(payment_hash, RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0), route_params.clone(), Retry::Attempts(0)).unwrap();
check_added_monitors(&nodes[0], 1);
Expand All @@ -1133,7 +1134,7 @@ fn min_htlc() {
nodes[0].node.timer_tick_occurred();
}
if let Payee::Blinded { ref mut route_hints, .. } = route_params.payment_params.payee {
route_hints[0].0.htlc_minimum_msat -= 1;
route_hints[0].payinfo.htlc_minimum_msat -= 1;
} else { panic!() }
route_params.final_value_msat -= 1;
nodes[0].node.send_payment(payment_hash, RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap();
Expand Down
4 changes: 2 additions & 2 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
use crate::ln::outbound_payment;
use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment, SendAlongPathArgs, StaleExpiration};
use crate::ln::wire::Encode;
use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
use crate::offers::invoice::{Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
use crate::offers::invoice_error::InvoiceError;
use crate::offers::invoice_request::{DerivedPayerId, InvoiceRequestBuilder};
use crate::offers::nonce::Nonce;
Expand Down Expand Up @@ -9373,7 +9373,7 @@ where
/// [`Router::create_blinded_payment_paths`].
fn create_blinded_payment_paths(
&self, amount_msats: u64, payment_secret: PaymentSecret, payment_context: PaymentContext
) -> Result<Vec<(BlindedPayInfo, BlindedPaymentPath)>, ()> {
) -> Result<Vec<BlindedPaymentPath>, ()> {
let secp_ctx = &self.secp_ctx;

let first_hops = self.list_usable_channels();
Expand Down
Loading
Loading