diff --git a/Cargo.toml b/Cargo.toml index 6a3a863..767f268 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ bitcoin-payment-instructions = { version = "0.5.0", default-features = false, fe "http", ] } # Branch: https://github.com/moneydevkit/ldk-node/commits/lsp-0.7.0_accept-underpaying-htlcs_with_timing_logs -ldk-node = { default-features = false, git = "https://github.com/moneydevkit/ldk-node.git", rev = "e935695c6ea9b33efee4cf579207ec84b40ce71f" } +ldk-node = { default-features = false, git = "https://github.com/moneydevkit/ldk-node.git", rev = "5baa1f83a13407818b069b1f990157c8761eb982" } #ldk-node = { path = "../ldk-node" } napi = { version = "2", features = ["napi4"] } diff --git a/index.d.ts b/index.d.ts index 251dc64..7159235 100644 --- a/index.d.ts +++ b/index.d.ts @@ -15,6 +15,21 @@ export declare function generateMnemonic(): string * Runs in ~1ms vs ~4s for full node construction. */ export declare function deriveNodeId(mnemonicStr: string, networkStr: string): string +export interface ScoringParamOverrides { + basePenaltyMsat?: number + basePenaltyAmountMultiplierMsat?: number + liquidityPenaltyMultiplierMsat?: number + liquidityPenaltyAmountMultiplierMsat?: number + historicalLiquidityPenaltyMultiplierMsat?: number + historicalLiquidityPenaltyAmountMultiplierMsat?: number + antiProbingPenaltyMsat?: number + consideredImpossiblePenaltyMsat?: number + linearSuccessProbability?: boolean + probingDiversityPenaltyMsat?: number + liquidityOffsetHalfLifeSecs?: number + historicalNoUpdatesHalfLifeSecs?: number + manualNodePenalties?: Record +} export interface MdkNodeOptions { network: string mdkApiKey: string @@ -24,6 +39,7 @@ export interface MdkNodeOptions { mnemonic: string lspNodeId: string lspAddress: string + scoringParamOverrides?: ScoringParamOverrides } export interface PaymentMetadata { bolt11: string diff --git a/src/lib.rs b/src/lib.rs index d5b6505..1f0a022 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,9 +28,13 @@ use napi::{ threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode}, }; +use ldk_node::lightning::routing::gossip::NodeId; +use ldk_node::lightning::routing::scoring::{ + ProbabilisticScoringDecayParameters, ProbabilisticScoringFeeParameters, +}; use ldk_node::logger::{LogLevel, LogRecord, LogWriter}; use ldk_node::{ - Builder, Event, Node, + Builder, Event, Node, ProbabilisticScoringParameters, bip39::Mnemonic, bitcoin::{ Network, @@ -263,6 +267,24 @@ fn derive_vss_identifier(mnemonic: &Mnemonic) -> String { sha256::Hash::hash(mnemonic_phrase.as_bytes()).to_string() } +#[napi(object)] +#[derive(Default)] +pub struct ScoringParamOverrides { + pub base_penalty_msat: Option, + pub base_penalty_amount_multiplier_msat: Option, + pub liquidity_penalty_multiplier_msat: Option, + pub liquidity_penalty_amount_multiplier_msat: Option, + pub historical_liquidity_penalty_multiplier_msat: Option, + pub historical_liquidity_penalty_amount_multiplier_msat: Option, + pub anti_probing_penalty_msat: Option, + pub considered_impossible_penalty_msat: Option, + pub linear_success_probability: Option, + pub probing_diversity_penalty_msat: Option, + pub liquidity_offset_half_life_secs: Option, + pub historical_no_updates_half_life_secs: Option, + pub manual_node_penalties: Option>, +} + #[napi(object)] pub struct MdkNodeOptions { pub network: String, @@ -273,6 +295,7 @@ pub struct MdkNodeOptions { pub mnemonic: String, pub lsp_node_id: String, pub lsp_address: String, + pub scoring_param_overrides: Option, } #[napi(object)] @@ -381,6 +404,63 @@ impl MdkNode { builder.set_custom_logger(logger); builder.set_liquidity_source_lsps4(lsp_node_id, lsp_address); + if let Some(scoring) = options.scoring_param_overrides { + let mut fee_params = ProbabilisticScoringFeeParameters::default(); + if let Some(v) = scoring.base_penalty_msat { + fee_params.base_penalty_msat = v as u64; + } + if let Some(v) = scoring.base_penalty_amount_multiplier_msat { + fee_params.base_penalty_amount_multiplier_msat = v as u64; + } + if let Some(v) = scoring.liquidity_penalty_multiplier_msat { + fee_params.liquidity_penalty_multiplier_msat = v as u64; + } + if let Some(v) = scoring.liquidity_penalty_amount_multiplier_msat { + fee_params.liquidity_penalty_amount_multiplier_msat = v as u64; + } + if let Some(v) = scoring.historical_liquidity_penalty_multiplier_msat { + fee_params.historical_liquidity_penalty_multiplier_msat = v as u64; + } + if let Some(v) = scoring.historical_liquidity_penalty_amount_multiplier_msat { + fee_params.historical_liquidity_penalty_amount_multiplier_msat = v as u64; + } + if let Some(v) = scoring.anti_probing_penalty_msat { + fee_params.anti_probing_penalty_msat = v as u64; + } + if let Some(v) = scoring.considered_impossible_penalty_msat { + fee_params.considered_impossible_penalty_msat = v as u64; + } + if let Some(v) = scoring.linear_success_probability { + fee_params.linear_success_probability = v; + } + if let Some(v) = scoring.probing_diversity_penalty_msat { + fee_params.probing_diversity_penalty_msat = v as u64; + } + if let Some(penalties) = scoring.manual_node_penalties { + for (node_id_str, penalty) in penalties { + let node_id = NodeId::from_str(&node_id_str).map_err(|e| { + napi::Error::from_reason(format!("Invalid node_id {}: {}", node_id_str, e)) + })?; + fee_params + .manual_node_penalties + .insert(node_id, penalty as u64); + } + } + + let mut decay_params = ProbabilisticScoringDecayParameters::default(); + if let Some(v) = scoring.liquidity_offset_half_life_secs { + decay_params.liquidity_offset_half_life = Duration::from_secs(v as u64); + } + if let Some(v) = scoring.historical_no_updates_half_life_secs { + decay_params.historical_no_updates_half_life = Duration::from_secs(v as u64); + } + + builder.set_scoring_params(ProbabilisticScoringParameters { + fee_params, + decay_params, + }); + } + let vss_headers = HashMap::from([( "Authorization".to_string(), format!("Bearer {}", options.mdk_api_key),