Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 162
Add SendingParameters struct for customizable payments #336
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
5fe90d1bf4ddffd6e6ff72b85ba94822336File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Collaborator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, could we either split this in one commit per field, or add all fields at once? In any case this split of "initial" and "new" fields doesn't make too much sense, given that they are not new. :) ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that during the commit history cleanup yesterday, I accidentally included some code in the wrong commits. I’m still working on my skills with interactive rebasing 😅. But, I’ve restructured the commits so that they should make more sense now. I squashed all the fields into one commit and then implemented |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| use std::time::Duration; | ||
| use crate::payment::SendingParameters; | ||
slanesuke marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| use lightning::ln::msgs::SocketAddress; | ||
| use lightning::util::config::UserConfig; | ||
| use lightning::util::logger::Level as LogLevel; | ||
| @@ -86,6 +88,7 @@ pub(crate) const WALLET_KEYS_SEED_LEN: usize = 64; | ||
| /// | `probing_liquidity_limit_multiplier` | 3 | | ||
| /// | `log_level` | Debug | | ||
| /// | `anchor_channels_config` | Some(..) | | ||
| /// | `sending_parameters_config` | None | | ||
slanesuke marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// | ||
| /// See [`AnchorChannelsConfig`] for more information on its respective default values. | ||
| /// | ||
| @@ -147,6 +150,12 @@ pub struct Config { | ||
| /// closure. We *will* however still try to get the Anchor spending transactions confirmed | ||
| /// on-chain with the funds available. | ||
| pub anchor_channels_config: Option<AnchorChannelsConfig>, | ||
| /// Configuration options for payment routing and pathfinding. | ||
| /// | ||
| /// Setting the `SendingParameters` provides flexibility to customize how payments are routed, | ||
| /// including setting limits on routing fees, CLTV expiry, and channel utilization. | ||
| pub sending_parameters_config: Option<SendingParameters>, | ||
| } | ||
| impl Default for Config { | ||
| @@ -164,6 +173,7 @@ impl Default for Config { | ||
| probing_liquidity_limit_multiplier: DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER, | ||
| log_level: DEFAULT_LOG_LEVEL, | ||
| anchor_channels_config: Some(AnchorChannelsConfig::default()), | ||
| sending_parameters_config: None, | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -11,6 +11,7 @@ use crate::payment::store::{ | ||
| LSPFeeLimits, PaymentDetails, PaymentDetailsUpdate, PaymentDirection, PaymentKind, | ||
| PaymentStatus, PaymentStore, | ||
| }; | ||
| use crate::payment::SendingParameters; | ||
| use crate::peer_store::{PeerInfo, PeerStore}; | ||
| use crate::types::{ChannelManager, KeysManager}; | ||
| @@ -69,13 +70,20 @@ impl Bolt11Payment { | ||
| } | ||
| /// Send a payment given an invoice. | ||
| pub fn send(&self, invoice: &Bolt11Invoice) -> Result<PaymentId, Error> { | ||
| /// | ||
| /// If [`SendingParameters`] are provided they will override the node's default routing parameters | ||
| /// on a per-field basis. Each field in `SendingParameters` that is set replaces the corresponding | ||
| /// default value. Fields that are not set fall back to the node's configured defaults. If no | ||
| /// `SendingParameters` are provided, the method fully relies on these defaults. | ||
| pub fn send( | ||
| &self, invoice: &Bolt11Invoice, sending_parameters: Option<SendingParameters>, | ||
| ) -> Result<PaymentId, Error> { | ||
| let rt_lock = self.runtime.read().unwrap(); | ||
| if rt_lock.is_none() { | ||
| return Err(Error::NotRunning); | ||
| } | ||
| let (payment_hash, recipient_onion, route_params) = payment::payment_parameters_from_invoice(&invoice).map_err(|_| { | ||
| let (payment_hash, recipient_onion, mut route_params) = payment::payment_parameters_from_invoice(&invoice).map_err(|_| { | ||
| log_error!(self.logger, "Failed to send payment due to the given invoice being \"zero-amount\". Please use send_using_amount instead."); | ||
| Error::InvalidInvoice | ||
| })?; | ||
| @@ -90,6 +98,40 @@ impl Bolt11Payment { | ||
| } | ||
| } | ||
| if let Some(user_set_params) = sending_parameters { | ||
| if let Some(mut default_params) = | ||
| self.config.sending_parameters_config.as_ref().cloned() | ||
slanesuke marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| { | ||
| default_params.max_total_routing_fee_msat = user_set_params | ||
| .max_total_routing_fee_msat | ||
| .or(default_params.max_total_routing_fee_msat); | ||
| default_params.max_total_cltv_expiry_delta = user_set_params | ||
| .max_total_cltv_expiry_delta | ||
| .or(default_params.max_total_cltv_expiry_delta); | ||
| default_params.max_path_count = | ||
| user_set_params.max_path_count.or(default_params.max_path_count); | ||
| default_params.max_channel_saturation_power_of_half = user_set_params | ||
| .max_channel_saturation_power_of_half | ||
| .or(default_params.max_channel_saturation_power_of_half); | ||
| route_params.max_total_routing_fee_msat = default_params.max_total_routing_fee_msat; | ||
| route_params.payment_params.max_total_cltv_expiry_delta = | ||
| default_params.max_total_cltv_expiry_delta.unwrap_or_default(); | ||
| route_params.payment_params.max_path_count = | ||
| default_params.max_path_count.unwrap_or_default(); | ||
| route_params.payment_params.max_channel_saturation_power_of_half = | ||
| default_params.max_channel_saturation_power_of_half.unwrap_or_default(); | ||
| } | ||
| } else if let Some(default_params) = &self.config.sending_parameters_config { | ||
| route_params.max_total_routing_fee_msat = default_params.max_total_routing_fee_msat; | ||
| route_params.payment_params.max_total_cltv_expiry_delta = | ||
| default_params.max_total_cltv_expiry_delta.unwrap_or_default(); | ||
| route_params.payment_params.max_path_count = | ||
| default_params.max_path_count.unwrap_or_default(); | ||
| route_params.payment_params.max_channel_saturation_power_of_half = | ||
| default_params.max_channel_saturation_power_of_half.unwrap_or_default(); | ||
| } | ||
| let payment_secret = Some(*invoice.payment_secret()); | ||
| let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT); | ||
| @@ -148,14 +190,20 @@ impl Bolt11Payment { | ||
| } | ||
| } | ||
| /// Send a payment given an invoice and an amount in millisatoshi. | ||
| /// Send a payment given an invoice and an amount in millisatoshis. | ||
| /// | ||
| /// This will fail if the amount given is less than the value required by the given invoice. | ||
| /// | ||
| /// This can be used to pay a so-called "zero-amount" invoice, i.e., an invoice that leaves the | ||
| /// amount paid to be determined by the user. | ||
| /// | ||
| /// If [`SendingParameters`] are provided they will override the node's default routing parameters | ||
| /// on a per-field basis. Each field in `SendingParameters` that is set replaces the corresponding | ||
| /// default value. Fields that are not set fall back to the node's configured defaults. If no | ||
| /// `SendingParameters` are provided, the method fully relies on these defaults. | ||
| pub fn send_using_amount( | ||
| &self, invoice: &Bolt11Invoice, amount_msat: u64, | ||
| sending_parameters: Option<SendingParameters>, | ||
| ) -> Result<PaymentId, Error> { | ||
| let rt_lock = self.runtime.read().unwrap(); | ||
| if rt_lock.is_none() { | ||
| @@ -196,9 +244,43 @@ impl Bolt11Payment { | ||
| .with_bolt11_features(features.clone()) | ||
| .map_err(|_| Error::InvalidInvoice)?; | ||
| } | ||
| let route_params = | ||
| let mut route_params = | ||
| RouteParameters::from_payment_params_and_value(payment_params, amount_msat); | ||
| if let Some(user_set_params) = sending_parameters { | ||
| if let Some(mut default_params) = | ||
| self.config.sending_parameters_config.as_ref().cloned() | ||
| { | ||
| default_params.max_total_routing_fee_msat = user_set_params | ||
| .max_total_routing_fee_msat | ||
| .or(default_params.max_total_routing_fee_msat); | ||
| default_params.max_total_cltv_expiry_delta = user_set_params | ||
| .max_total_cltv_expiry_delta | ||
| .or(default_params.max_total_cltv_expiry_delta); | ||
| default_params.max_path_count = | ||
| user_set_params.max_path_count.or(default_params.max_path_count); | ||
| default_params.max_channel_saturation_power_of_half = user_set_params | ||
| .max_channel_saturation_power_of_half | ||
| .or(default_params.max_channel_saturation_power_of_half); | ||
| route_params.max_total_routing_fee_msat = default_params.max_total_routing_fee_msat; | ||
| route_params.payment_params.max_total_cltv_expiry_delta = | ||
| default_params.max_total_cltv_expiry_delta.unwrap_or_default(); | ||
| route_params.payment_params.max_path_count = | ||
| default_params.max_path_count.unwrap_or_default(); | ||
| route_params.payment_params.max_channel_saturation_power_of_half = | ||
| default_params.max_channel_saturation_power_of_half.unwrap_or_default(); | ||
| } | ||
| } else if let Some(default_params) = &self.config.sending_parameters_config { | ||
| route_params.max_total_routing_fee_msat = default_params.max_total_routing_fee_msat; | ||
| route_params.payment_params.max_total_cltv_expiry_delta = | ||
| default_params.max_total_cltv_expiry_delta.unwrap_or_default(); | ||
| route_params.payment_params.max_path_count = | ||
| default_params.max_path_count.unwrap_or_default(); | ||
| route_params.payment_params.max_channel_saturation_power_of_half = | ||
| default_params.max_channel_saturation_power_of_half.unwrap_or_default(); | ||
| } | ||
| let retry_strategy = Retry::Timeout(LDK_PAYMENT_RETRY_TIMEOUT); | ||
| let recipient_fields = RecipientOnionFields::secret_only(*payment_secret); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -6,6 +6,7 @@ use crate::logger::{log_error, log_info, FilesystemLogger, Logger}; | ||
| use crate::payment::store::{ | ||
| PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, PaymentStore, | ||
| }; | ||
| use crate::payment::SendingParameters; | ||
| use crate::types::{ChannelManager, KeysManager}; | ||
| use lightning::ln::channelmanager::{PaymentId, RecipientOnionFields, Retry, RetryableSendFailure}; | ||
| @@ -41,8 +42,15 @@ impl SpontaneousPayment { | ||
| Self { runtime, channel_manager, keys_manager, payment_store, config, logger } | ||
| } | ||
| /// Send a spontaneous, aka. "keysend", payment | ||
| pub fn send(&self, amount_msat: u64, node_id: PublicKey) -> Result<PaymentId, Error> { | ||
| /// Send a spontaneous aka. "keysend", payment. | ||
| /// | ||
| /// If [`SendingParameters`] are provided they will override the node's default routing parameters | ||
| /// on a per-field basis. Each field in `SendingParameters` that is set replaces the corresponding | ||
| /// default value. Fields that are not set fall back to the node's configured defaults. If no | ||
| /// `SendingParameters` are provided, the method fully relies on these defaults. | ||
| pub fn send( | ||
| &self, amount_msat: u64, node_id: PublicKey, sending_parameters: Option<SendingParameters>, | ||
| ) -> Result<PaymentId, Error> { | ||
| let rt_lock = self.runtime.read().unwrap(); | ||
| if rt_lock.is_none() { | ||
| return Err(Error::NotRunning); | ||
| @@ -61,10 +69,45 @@ impl SpontaneousPayment { | ||
| } | ||
| } | ||
| let route_params = RouteParameters::from_payment_params_and_value( | ||
| let mut route_params = RouteParameters::from_payment_params_and_value( | ||
| PaymentParameters::from_node_id(node_id, self.config.default_cltv_expiry_delta), | ||
| amount_msat, | ||
| ); | ||
| if let Some(user_set_params) = sending_parameters { | ||
| if let Some(mut default_params) = | ||
| self.config.sending_parameters_config.as_ref().cloned() | ||
| { | ||
| default_params.max_total_routing_fee_msat = user_set_params | ||
| .max_total_routing_fee_msat | ||
| .or(default_params.max_total_routing_fee_msat); | ||
| default_params.max_total_cltv_expiry_delta = user_set_params | ||
| .max_total_cltv_expiry_delta | ||
| .or(default_params.max_total_cltv_expiry_delta); | ||
| default_params.max_path_count = | ||
| user_set_params.max_path_count.or(default_params.max_path_count); | ||
| default_params.max_channel_saturation_power_of_half = user_set_params | ||
| .max_channel_saturation_power_of_half | ||
| .or(default_params.max_channel_saturation_power_of_half); | ||
| route_params.max_total_routing_fee_msat = default_params.max_total_routing_fee_msat; | ||
| route_params.payment_params.max_total_cltv_expiry_delta = | ||
| default_params.max_total_cltv_expiry_delta.unwrap_or_default(); | ||
| route_params.payment_params.max_path_count = | ||
| default_params.max_path_count.unwrap_or_default(); | ||
| route_params.payment_params.max_channel_saturation_power_of_half = | ||
| default_params.max_channel_saturation_power_of_half.unwrap_or_default(); | ||
| } | ||
| } else if let Some(default_params) = &self.config.sending_parameters_config { | ||
| route_params.max_total_routing_fee_msat = default_params.max_total_routing_fee_msat; | ||
| route_params.payment_params.max_total_cltv_expiry_delta = | ||
| default_params.max_total_cltv_expiry_delta.unwrap_or_default(); | ||
slanesuke marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| route_params.payment_params.max_path_count = | ||
| default_params.max_path_count.unwrap_or_default(); | ||
| route_params.payment_params.max_channel_saturation_power_of_half = | ||
| default_params.max_channel_saturation_power_of_half.unwrap_or_default(); | ||
| } | ||
| let recipient_fields = RecipientOnionFields::spontaneous_empty(); | ||
| match self.channel_manager.send_spontaneous_payment_with_retry( | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.