Skip to content

Commit 23c0ff0

Browse files
authored
Add Node::find_route accessor (#29)
Public wrapper around the previously private `_router` so callers can resolve a route to a destination without dispatching a payment. The intended consumer is mdk's max-withdrawable estimator, which needs a real route to invert per-hop fees against payout destinations. The signature takes `Option<RouteParametersConfig>`. With `None` the node-wide `Config::route_parameters` applies, matching the fallback already used by `SpontaneousPayment::send_inner`. Keeps both call sites consistent. `Error::RouteNotFound` is a new variant. This path performs lookup only and never dispatches anything, and a missing route under current liquidity is a routine outcome. The router's `&'static str` reason is logged at debug level and dropped; callers already get the typed error. `Route` and `RouteParametersConfig` are re-exported from `lib.rs` for Rust consumers. No UDL bindings in this commit: the `uniffi` build is currently broken on this branch from drift left over by the rust-lightning upgrade in e935695, so adding more UDL surface would fly blind. A follow-up that fixes the existing drift can layer `Route` bindings on top. The returned `Route` may contain multiple `Path` entries when `max_path_count > 1`, since the router is free to split the amount across MPP paths. Callers wanting a single-path response should set `max_path_count: 1` in the supplied config.
1 parent 5dce44b commit 23c0ff0

4 files changed

Lines changed: 61 additions & 2 deletions

File tree

src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ pub enum Error {
3939
InvalidCustomTlvs,
4040
/// Sending a payment probe has failed.
4141
ProbeSendingFailed,
42+
/// A route to the given destination could not be found.
43+
RouteNotFound,
4244
/// A channel could not be opened.
4345
ChannelCreationFailed,
4446
/// A channel could not be closed.
@@ -145,6 +147,7 @@ impl fmt::Display for Error {
145147
Self::PaymentSendingFailed => write!(f, "Failed to send the given payment."),
146148
Self::InvalidCustomTlvs => write!(f, "Failed to construct payment with custom TLVs."),
147149
Self::ProbeSendingFailed => write!(f, "Failed to send the given payment probe."),
150+
Self::RouteNotFound => write!(f, "Failed to find a route to the destination."),
148151
Self::ChannelCreationFailed => write!(f, "Failed to create channel."),
149152
Self::ChannelClosingFailed => write!(f, "Failed to close channel."),
150153
Self::ChannelSplicingFailed => write!(f, "Failed to splice channel."),

src/lib.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ use lightning::ln::channelmanager::PaymentId;
144144
use lightning::ln::funding::SpliceContribution;
145145
use lightning::ln::msgs::SocketAddress;
146146
use lightning::routing::gossip::NodeAlias;
147+
use lightning::routing::router::{PaymentParameters, RouteParameters};
148+
pub use lightning::routing::router::{Route, RouteParametersConfig};
147149
use lightning::util::persist::KVStoreSync;
148150
use lightning_background_processor::process_events_async;
149151
use liquidity::{LSPS1Liquidity, LiquiditySource};
@@ -152,7 +154,7 @@ use payment::asynchronous::om_mailbox::OnionMessageMailbox;
152154
use payment::asynchronous::static_invoice_store::StaticInvoiceStore;
153155
use payment::{
154156
Bolt11Payment, Bolt12Payment, OnchainPayment, PaymentDetails, SpontaneousPayment,
155-
UnifiedQrPayment,
157+
UnifiedQrPayment, LDK_DEFAULT_FINAL_CLTV_EXPIRY_DELTA,
156158
};
157159
use peer_store::{PeerInfo, PeerStore};
158160
use rand::Rng;
@@ -1888,6 +1890,59 @@ impl Node {
18881890
.to_sat_per_kwu()
18891891
}
18901892

1893+
/// Finds a route to `payee` for `amount_msat` using the node's internal router.
1894+
///
1895+
/// Intended for callers that need to introspect routing fees ahead of
1896+
/// time (e.g. computing a max-sendable estimate by inverting per-hop fees).
1897+
///
1898+
/// `params` overrides the node-wide [`RouteParametersConfig`] when `Some`; otherwise
1899+
/// the value from [`Config::route_parameters`] is used.
1900+
///
1901+
/// [`Config::route_parameters`]: crate::config::Config::route_parameters
1902+
pub fn find_route(
1903+
&self, payee: PublicKey, amount_msat: u64, params: Option<RouteParametersConfig>,
1904+
) -> Result<Route, Error> {
1905+
if !*self.is_running.read().unwrap() {
1906+
return Err(Error::NotRunning);
1907+
}
1908+
1909+
let mut route_params = RouteParameters::from_payment_params_and_value(
1910+
PaymentParameters::from_node_id(payee, LDK_DEFAULT_FINAL_CLTV_EXPIRY_DELTA),
1911+
amount_msat,
1912+
);
1913+
1914+
if let Some(RouteParametersConfig {
1915+
max_total_routing_fee_msat,
1916+
max_total_cltv_expiry_delta,
1917+
max_path_count,
1918+
max_channel_saturation_power_of_half,
1919+
}) = params.as_ref().or(self.config.route_parameters.as_ref())
1920+
{
1921+
route_params.max_total_routing_fee_msat = *max_total_routing_fee_msat;
1922+
route_params.payment_params.max_total_cltv_expiry_delta = *max_total_cltv_expiry_delta;
1923+
route_params.payment_params.max_path_count = *max_path_count;
1924+
route_params.payment_params.max_channel_saturation_power_of_half =
1925+
*max_channel_saturation_power_of_half;
1926+
}
1927+
1928+
let payer = self.channel_manager.get_our_node_id();
1929+
let first_hops = self.channel_manager.list_usable_channels();
1930+
let first_hops_refs: Vec<&LdkChannelDetails> = first_hops.iter().collect();
1931+
let inflight_htlcs = self.channel_manager.compute_inflight_htlcs();
1932+
1933+
lightning::routing::router::Router::find_route(
1934+
&*self._router,
1935+
&payer,
1936+
&route_params,
1937+
Some(&first_hops_refs),
1938+
inflight_htlcs,
1939+
)
1940+
.map_err(|e| {
1941+
log_debug!(self.logger, "Failed to find route to {}: {}", payee, e);
1942+
Error::RouteNotFound
1943+
})
1944+
}
1945+
18911946
/// Exports the current state of the scorer. The result can be shared with and merged by light nodes that only have
18921947
/// a limited view of the network.
18931948
pub fn export_pathfinding_scores(&self) -> Result<Vec<u8>, Error> {

src/payment/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub use bolt11::Bolt11Payment;
1919
pub use bolt12::Bolt12Payment;
2020
pub use onchain::OnchainPayment;
2121
pub use spontaneous::SpontaneousPayment;
22+
pub(crate) use spontaneous::LDK_DEFAULT_FINAL_CLTV_EXPIRY_DELTA;
2223
pub use store::{
2324
ConfirmationStatus, LSPFeeLimits, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus,
2425
};

src/payment/spontaneous.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::payment::store::{PaymentDetails, PaymentDirection, PaymentKind, Payme
2222
use crate::types::{ChannelManager, CustomTlvRecord, KeysManager, PaymentStore};
2323

2424
// The default `final_cltv_expiry_delta` we apply when not set.
25-
const LDK_DEFAULT_FINAL_CLTV_EXPIRY_DELTA: u32 = 144;
25+
pub(crate) const LDK_DEFAULT_FINAL_CLTV_EXPIRY_DELTA: u32 = 144;
2626

2727
/// A payment handler allowing to send spontaneous ("keysend") payments.
2828
///

0 commit comments

Comments
 (0)