diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 7c0edc535..0760c3e78 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -11,6 +11,8 @@ typedef dictionary ElectrumSyncConfig; typedef dictionary TorConfig; +typedef dictionary ProbabilisticScoringFeeParameters; + typedef interface NodeEntropy; typedef enum WordCount; @@ -43,6 +45,7 @@ interface Builder { void set_gossip_source_p2p(); void set_gossip_source_rgs(string rgs_server_url); void set_pathfinding_scores_source(string url); + void set_scoring_fee_parameters(ProbabilisticScoringFeeParameters scoring_fee_parameters); void add_liquidity_source(PublicKey node_id, SocketAddress address, string? token, boolean trust_peer_0conf); void set_storage_dir_path(string storage_dir_path); void set_filesystem_logger(string? log_file_path, LogLevel? max_log_level); diff --git a/src/builder.rs b/src/builder.rs index 8b575cc3f..e9f3b48f4 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -32,7 +32,6 @@ use lightning::routing::gossip::NodeAlias; use lightning::routing::router::DefaultRouter; use lightning::routing::scoring::{ CombinedScorer, ProbabilisticScorer, ProbabilisticScoringDecayParameters, - ProbabilisticScoringFeeParameters, }; use lightning::sign::{EntropySource, NodeSigner}; use lightning::util::config::HTLCInterceptionFlags; @@ -49,7 +48,8 @@ use crate::chain::ChainSource; use crate::config::{ default_user_config, may_announce_channel, AnnounceError, AsyncPaymentsRole, BitcoindRestClientConfig, Config, ElectrumSyncConfig, EsploraSyncConfig, HRNResolverConfig, - TorConfig, DEFAULT_ESPLORA_SERVER_URL, DEFAULT_LOG_FILENAME, DEFAULT_LOG_LEVEL, + ProbabilisticScoringFeeParameters, TorConfig, DEFAULT_ESPLORA_SERVER_URL, DEFAULT_LOG_FILENAME, + DEFAULT_LOG_LEVEL, }; use crate::connection::ConnectionManager; use crate::entropy::NodeEntropy; @@ -466,6 +466,14 @@ impl NodeBuilder { self } + /// Sets the scoring fee parameters used for payment pathfinding. + pub fn set_scoring_fee_parameters( + &mut self, scoring_fee_parameters: ProbabilisticScoringFeeParameters, + ) -> &mut Self { + self.config.scoring_fee_parameters = scoring_fee_parameters; + self + } + /// Configures the [`Node`] instance to source inbound liquidity from the given LSP. /// /// The node will discover the LSP's supported protocols (LSPS1/LSPS2) on startup via [bLIP-50 / LSPS0] @@ -1046,6 +1054,13 @@ impl ArcedNodeBuilder { self.inner.write().expect("lock").set_pathfinding_scores_source(url); } + /// Sets the scoring fee parameters used for payment pathfinding. + pub fn set_scoring_fee_parameters( + &self, scoring_fee_parameters: ProbabilisticScoringFeeParameters, + ) { + self.inner.write().expect("lock").set_scoring_fee_parameters(scoring_fee_parameters); + } + /// Configures the [`Node`] instance to source inbound liquidity from the given LSP. /// /// The node will discover the LSP's supported protocols (LSPS1/LSPS2) on startup via [bLIP-50 / LSPS0] @@ -1857,7 +1872,7 @@ fn build_with_store_internal( }, } - let scoring_fee_params = ProbabilisticScoringFeeParameters::default(); + let scoring_fee_params = config.scoring_fee_parameters.clone().into(); let router = Arc::new(DefaultRouter::new( Arc::clone(&network_graph), Arc::clone(&logger), diff --git a/src/config.rs b/src/config.rs index ad1b91181..e001c91ce 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,6 +7,7 @@ //! Objects for configuring the node. +use std::collections::HashMap; use std::fmt; use std::str::FromStr; use std::time::Duration; @@ -14,8 +15,9 @@ use std::time::Duration; use bitcoin::secp256k1::PublicKey; use bitcoin::Network; use lightning::ln::msgs::SocketAddress; -use lightning::routing::gossip::NodeAlias; +use lightning::routing::gossip::{NodeAlias, NodeId}; use lightning::routing::router::RouteParametersConfig; +use lightning::routing::scoring::ProbabilisticScoringFeeParameters as LdkProbabilisticScoringFeeParameters; use lightning::util::config::{ ChannelConfig as LdkChannelConfig, MaxDustHTLCExposure as LdkMaxDustHTLCExposure, UserConfig, }; @@ -128,11 +130,13 @@ pub(crate) const LNURL_AUTH_TIMEOUT_SECS: u64 = 15; /// | `probing_liquidity_limit_multiplier` | 3 | /// | `anchor_channels_config` | Some(..) | /// | `route_parameters` | None | +/// | `scoring_fee_parameters` | ProbabilisticScoringFeeParameters::default() | /// | `tor_config` | None | /// | `hrn_config` | HumanReadableNamesConfig::default() | /// -/// See [`AnchorChannelsConfig`] and [`RouteParametersConfig`] for more information regarding their -/// respective default values. +/// See [`AnchorChannelsConfig`], [`RouteParametersConfig`], and +/// [`ProbabilisticScoringFeeParameters`] for more information regarding their respective default +/// values. /// /// [`Node`]: crate::Node pub struct Config { @@ -194,6 +198,11 @@ pub struct Config { /// **Note:** If unset, default parameters will be used, and you will be able to override the /// parameters on a per-payment basis in the corresponding method calls. pub route_parameters: Option, + /// Configuration options for scoring candidate routes during pathfinding. + /// + /// These parameters configure the channel penalties applied by LDK's probabilistic scorer, + /// influencing which routes are preferred when sending payments. + pub scoring_fee_parameters: ProbabilisticScoringFeeParameters, /// Configuration options for enabling peer connections via the Tor network. /// /// Setting [`TorConfig`] enables connecting to peers with OnionV3 addresses. No other connections @@ -219,12 +228,95 @@ impl Default for Config { anchor_channels_config: Some(AnchorChannelsConfig::default()), tor_config: None, route_parameters: None, + scoring_fee_parameters: ProbabilisticScoringFeeParameters::default(), node_alias: None, hrn_config: HumanReadableNamesConfig::default(), } } } +/// Parameters for configuring channel penalties applied during payment pathfinding. +/// +/// See [`LdkProbabilisticScoringFeeParameters`] for more information on how these values affect +/// route selection. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +pub struct ProbabilisticScoringFeeParameters { + /// A fixed penalty in msats to apply to each channel. + pub base_penalty_msat: u64, + /// A multiplier used with the payment amount to calculate an additional fixed penalty. + pub base_penalty_amount_multiplier_msat: u64, + /// A multiplier used with the estimated success probability to determine the liquidity penalty. + pub liquidity_penalty_multiplier_msat: u64, + /// A multiplier used with payment amount and estimated success probability to determine the + /// liquidity amount penalty. + pub liquidity_penalty_amount_multiplier_msat: u64, + /// A multiplier used with historical liquidity estimates to determine a penalty. + pub historical_liquidity_penalty_multiplier_msat: u64, + /// A multiplier used with payment amount and historical liquidity estimates to determine a + /// penalty. + pub historical_liquidity_penalty_amount_multiplier_msat: u64, + /// Manual penalties used for the given nodes. + pub manual_node_penalties: HashMap, + /// Penalty applied when a channel's `htlc_maximum_msat` is at least half of its capacity. + pub anti_probing_penalty_msat: u64, + /// Penalty applied when the total amount flowing over a channel exceeds our current estimate of + /// the channel's available liquidity. + pub considered_impossible_penalty_msat: u64, + /// If set, a linear probability density function is used for channel liquidity. + pub linear_success_probability: bool, + /// Maximum penalty applied when choosing probing paths based on recent liquidity updates. + pub probing_diversity_penalty_msat: u64, +} + +impl Default for ProbabilisticScoringFeeParameters { + fn default() -> Self { + LdkProbabilisticScoringFeeParameters::default().into() + } +} + +impl From for ProbabilisticScoringFeeParameters { + fn from(value: LdkProbabilisticScoringFeeParameters) -> Self { + Self { + base_penalty_msat: value.base_penalty_msat, + base_penalty_amount_multiplier_msat: value.base_penalty_amount_multiplier_msat, + liquidity_penalty_multiplier_msat: value.liquidity_penalty_multiplier_msat, + liquidity_penalty_amount_multiplier_msat: value + .liquidity_penalty_amount_multiplier_msat, + historical_liquidity_penalty_multiplier_msat: value + .historical_liquidity_penalty_multiplier_msat, + historical_liquidity_penalty_amount_multiplier_msat: value + .historical_liquidity_penalty_amount_multiplier_msat, + manual_node_penalties: value.manual_node_penalties.into_iter().collect(), + anti_probing_penalty_msat: value.anti_probing_penalty_msat, + considered_impossible_penalty_msat: value.considered_impossible_penalty_msat, + linear_success_probability: value.linear_success_probability, + probing_diversity_penalty_msat: value.probing_diversity_penalty_msat, + } + } +} + +impl From for LdkProbabilisticScoringFeeParameters { + fn from(value: ProbabilisticScoringFeeParameters) -> Self { + Self { + base_penalty_msat: value.base_penalty_msat, + base_penalty_amount_multiplier_msat: value.base_penalty_amount_multiplier_msat, + liquidity_penalty_multiplier_msat: value.liquidity_penalty_multiplier_msat, + liquidity_penalty_amount_multiplier_msat: value + .liquidity_penalty_amount_multiplier_msat, + historical_liquidity_penalty_multiplier_msat: value + .historical_liquidity_penalty_multiplier_msat, + historical_liquidity_penalty_amount_multiplier_msat: value + .historical_liquidity_penalty_amount_multiplier_msat, + manual_node_penalties: value.manual_node_penalties.into_iter().collect(), + anti_probing_penalty_msat: value.anti_probing_penalty_msat, + considered_impossible_penalty_msat: value.considered_impossible_penalty_msat, + linear_success_probability: value.linear_success_probability, + probing_diversity_penalty_msat: value.probing_diversity_penalty_msat, + } + } +} + /// Configuration options for how our node resolves Human-Readable Names (BIP 353). /// /// [BIP 353]: https://github.com/bitcoin/bips/blob/master/bip-0353.mediawiki diff --git a/src/ffi/types.rs b/src/ffi/types.rs index 9bb03bb07..4c0eef77d 100644 --- a/src/ffi/types.rs +++ b/src/ffi/types.rs @@ -144,7 +144,10 @@ impl VssClientHeaderProvider for VssHeaderProviderAdapter { } use crate::builder::sanitize_alias; -pub use crate::config::{default_config, ElectrumSyncConfig, EsploraSyncConfig, TorConfig}; +pub use crate::config::{ + default_config, ElectrumSyncConfig, EsploraSyncConfig, ProbabilisticScoringFeeParameters, + TorConfig, +}; pub use crate::entropy::{generate_entropy_mnemonic, NodeEntropy, WordCount}; use crate::error::Error; pub use crate::liquidity::LSPS1OrderStatus;