mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-01-19 05:43:55 +01:00
Add create_blinded_payment_paths to Router
The Router trait is used to find a Route for paying a node. Expand the interface with a create_blinded_payment paths method for creating such paths to a recipient node. Provide an implementation for DefaultRouter that creates two-hop blinded paths where the recipient's peers serve as the introduction nodes.
This commit is contained in:
parent
edb5892030
commit
62f8669654
@ -31,6 +31,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
|
||||
use bitcoin::hash_types::{BlockHash, WPubkeyHash};
|
||||
|
||||
use lightning::blinded_path::BlindedPath;
|
||||
use lightning::blinded_path::payment::ReceiveTlvs;
|
||||
use lightning::chain;
|
||||
use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, chainmonitor, channelmonitor, Confirm, Watch};
|
||||
use lightning::chain::channelmonitor::{ChannelMonitor, MonitorEvent};
|
||||
@ -45,7 +46,7 @@ use lightning::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE;
|
||||
use lightning::ln::msgs::{self, CommitmentUpdate, ChannelMessageHandler, DecodeError, UpdateAddHTLC, Init};
|
||||
use lightning::ln::script::ShutdownScript;
|
||||
use lightning::ln::functional_test_utils::*;
|
||||
use lightning::offers::invoice::UnsignedBolt12Invoice;
|
||||
use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
|
||||
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
|
||||
use lightning::onion_message::{Destination, MessageRouter, OnionMessagePath};
|
||||
use lightning::util::test_channel_signer::{TestChannelSigner, EnforcementState};
|
||||
@ -101,6 +102,15 @@ impl Router for FuzzRouter {
|
||||
action: msgs::ErrorAction::IgnoreError
|
||||
})
|
||||
}
|
||||
|
||||
fn create_blinded_payment_paths<
|
||||
ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
|
||||
>(
|
||||
&self, _recipient: PublicKey, _first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs,
|
||||
_amount_msats: u64, _entropy_source: &ES, _secp_ctx: &Secp256k1<T>
|
||||
) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageRouter for FuzzRouter {
|
||||
|
@ -29,6 +29,7 @@ use bitcoin::hashes::sha256d::Hash as Sha256dHash;
|
||||
use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
|
||||
|
||||
use lightning::blinded_path::BlindedPath;
|
||||
use lightning::blinded_path::payment::ReceiveTlvs;
|
||||
use lightning::chain;
|
||||
use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen};
|
||||
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
|
||||
@ -42,7 +43,7 @@ use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor,Ig
|
||||
use lightning::ln::msgs::{self, DecodeError};
|
||||
use lightning::ln::script::ShutdownScript;
|
||||
use lightning::ln::functional_test_utils::*;
|
||||
use lightning::offers::invoice::UnsignedBolt12Invoice;
|
||||
use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
|
||||
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
|
||||
use lightning::onion_message::{Destination, MessageRouter, OnionMessagePath};
|
||||
use lightning::routing::gossip::{P2PGossipSync, NetworkGraph};
|
||||
@ -144,6 +145,15 @@ impl Router for FuzzRouter {
|
||||
action: msgs::ErrorAction::IgnoreError
|
||||
})
|
||||
}
|
||||
|
||||
fn create_blinded_payment_paths<
|
||||
ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
|
||||
>(
|
||||
&self, _recipient: PublicKey, _first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs,
|
||||
_amount_msats: u64, _entropy_source: &ES, _secp_ctx: &Secp256k1<T>
|
||||
) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageRouter for FuzzRouter {
|
||||
|
@ -14,9 +14,10 @@ use bitcoin::hashes::Hash;
|
||||
use bitcoin::hashes::sha256::Hash as Sha256;
|
||||
|
||||
use crate::blinded_path::{BlindedHop, BlindedPath};
|
||||
use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs};
|
||||
use crate::ln::PaymentHash;
|
||||
use crate::ln::channelmanager::{ChannelDetails, PaymentId};
|
||||
use crate::ln::features::{Bolt11InvoiceFeatures, Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures};
|
||||
use crate::ln::features::{BlindedHopFeatures, Bolt11InvoiceFeatures, Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures};
|
||||
use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
|
||||
use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice};
|
||||
use crate::onion_message::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath};
|
||||
@ -82,6 +83,81 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized,
|
||||
&random_seed_bytes
|
||||
)
|
||||
}
|
||||
|
||||
fn create_blinded_payment_paths<
|
||||
ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
|
||||
>(
|
||||
&self, recipient: PublicKey, first_hops: Vec<ChannelDetails>, tlvs: ReceiveTlvs,
|
||||
amount_msats: u64, entropy_source: &ES, secp_ctx: &Secp256k1<T>
|
||||
) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
|
||||
// Limit the number of blinded paths that are computed.
|
||||
const MAX_PAYMENT_PATHS: usize = 3;
|
||||
|
||||
// Ensure peers have at least three channels so that it is more difficult to infer the
|
||||
// recipient's node_id.
|
||||
const MIN_PEER_CHANNELS: usize = 3;
|
||||
|
||||
let network_graph = self.network_graph.deref().read_only();
|
||||
let paths = first_hops.into_iter()
|
||||
.filter(|details| details.counterparty.features.supports_route_blinding())
|
||||
.filter(|details| amount_msats <= details.inbound_capacity_msat)
|
||||
.filter(|details| amount_msats >= details.inbound_htlc_minimum_msat.unwrap_or(0))
|
||||
.filter(|details| amount_msats <= details.inbound_htlc_maximum_msat.unwrap_or(0))
|
||||
.filter(|details| network_graph
|
||||
.node(&NodeId::from_pubkey(&details.counterparty.node_id))
|
||||
.map(|node_info| node_info.channels.len() >= MIN_PEER_CHANNELS)
|
||||
.unwrap_or(false)
|
||||
)
|
||||
.filter_map(|details| {
|
||||
let short_channel_id = match details.get_inbound_payment_scid() {
|
||||
Some(short_channel_id) => short_channel_id,
|
||||
None => return None,
|
||||
};
|
||||
let payment_relay: PaymentRelay = match details.counterparty.forwarding_info {
|
||||
Some(forwarding_info) => forwarding_info.into(),
|
||||
None => return None,
|
||||
};
|
||||
|
||||
// Avoid exposing esoteric CLTV expiry deltas
|
||||
let cltv_expiry_delta = match payment_relay.cltv_expiry_delta {
|
||||
0..=40 => 40u32,
|
||||
41..=80 => 80u32,
|
||||
81..=144 => 144u32,
|
||||
145..=216 => 216u32,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let payment_constraints = PaymentConstraints {
|
||||
max_cltv_expiry: tlvs.payment_constraints.max_cltv_expiry + cltv_expiry_delta,
|
||||
htlc_minimum_msat: details.inbound_htlc_minimum_msat.unwrap_or(0),
|
||||
};
|
||||
Some(ForwardNode {
|
||||
tlvs: ForwardTlvs {
|
||||
short_channel_id,
|
||||
payment_relay,
|
||||
payment_constraints,
|
||||
features: BlindedHopFeatures::empty(),
|
||||
},
|
||||
node_id: details.counterparty.node_id,
|
||||
htlc_maximum_msat: details.inbound_htlc_maximum_msat.unwrap_or(0),
|
||||
})
|
||||
})
|
||||
.map(|forward_node| {
|
||||
BlindedPath::new_for_payment(
|
||||
&[forward_node], recipient, tlvs.clone(), u64::MAX, entropy_source, secp_ctx
|
||||
)
|
||||
})
|
||||
.take(MAX_PAYMENT_PATHS)
|
||||
.collect::<Result<Vec<_>, _>>();
|
||||
|
||||
match paths {
|
||||
Ok(paths) if !paths.is_empty() => Ok(paths),
|
||||
_ => {
|
||||
BlindedPath::one_hop_for_payment(recipient, tlvs, entropy_source, secp_ctx)
|
||||
.map(|path| vec![path])
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl< G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp<ScoreParams = SP>> MessageRouter for DefaultRouter<G, L, S, SP, Sc> where
|
||||
@ -129,6 +205,16 @@ pub trait Router: MessageRouter {
|
||||
) -> Result<Route, LightningError> {
|
||||
self.find_route(payer, route_params, first_hops, inflight_htlcs)
|
||||
}
|
||||
|
||||
/// Creates [`BlindedPath`]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<
|
||||
ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
|
||||
>(
|
||||
&self, recipient: PublicKey, first_hops: Vec<ChannelDetails>, tlvs: ReceiveTlvs,
|
||||
amount_msats: u64, entropy_source: &ES, secp_ctx: &Secp256k1<T>
|
||||
) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()>;
|
||||
}
|
||||
|
||||
/// [`ScoreLookUp`] implementation that factors in in-flight HTLC liquidity.
|
||||
|
@ -8,6 +8,7 @@
|
||||
// licenses.
|
||||
|
||||
use crate::blinded_path::BlindedPath;
|
||||
use crate::blinded_path::payment::ReceiveTlvs;
|
||||
use crate::chain;
|
||||
use crate::chain::WatchedOutput;
|
||||
use crate::chain::chaininterface;
|
||||
@ -23,13 +24,13 @@ use crate::sign;
|
||||
use crate::events;
|
||||
use crate::events::bump_transaction::{WalletSource, Utxo};
|
||||
use crate::ln::ChannelId;
|
||||
use crate::ln::channelmanager;
|
||||
use crate::ln::channelmanager::{ChannelDetails, self};
|
||||
use crate::ln::chan_utils::CommitmentTransaction;
|
||||
use crate::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
|
||||
use crate::ln::{msgs, wire};
|
||||
use crate::ln::msgs::LightningError;
|
||||
use crate::ln::script::ShutdownScript;
|
||||
use crate::offers::invoice::UnsignedBolt12Invoice;
|
||||
use crate::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
|
||||
use crate::offers::invoice_request::UnsignedInvoiceRequest;
|
||||
use crate::onion_message::{Destination, MessageRouter, OnionMessagePath};
|
||||
use crate::routing::gossip::{EffectiveCapacity, NetworkGraph, NodeId, RoutingFees};
|
||||
@ -121,7 +122,7 @@ impl<'a> TestRouter<'a> {
|
||||
|
||||
impl<'a> Router for TestRouter<'a> {
|
||||
fn find_route(
|
||||
&self, payer: &PublicKey, params: &RouteParameters, first_hops: Option<&[&channelmanager::ChannelDetails]>,
|
||||
&self, payer: &PublicKey, params: &RouteParameters, first_hops: Option<&[&ChannelDetails]>,
|
||||
inflight_htlcs: InFlightHtlcs
|
||||
) -> Result<Route, msgs::LightningError> {
|
||||
if let Some((find_route_query, find_route_res)) = self.next_routes.lock().unwrap().pop_front() {
|
||||
@ -191,6 +192,15 @@ impl<'a> Router for TestRouter<'a> {
|
||||
&[42; 32]
|
||||
)
|
||||
}
|
||||
|
||||
fn create_blinded_payment_paths<
|
||||
ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification
|
||||
>(
|
||||
&self, _recipient: PublicKey, _first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs,
|
||||
_amount_msats: u64, _entropy_source: &ES, _secp_ctx: &Secp256k1<T>
|
||||
) -> Result<Vec<(BlindedPayInfo, BlindedPath)>, ()> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MessageRouter for TestRouter<'a> {
|
||||
|
Loading…
Reference in New Issue
Block a user