//! Various user-configurable channel limits and settings which ChannelManager
//! applies for you.
-use ln::channel::MAX_FUNDING_SATOSHIS_NO_WUMBO;
-use ln::channelmanager::{BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT};
+use crate::ln::channel::MAX_FUNDING_SATOSHIS_NO_WUMBO;
+use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, MAX_LOCAL_BREAKDOWN_TIMEOUT};
/// Configuration we set when applicable.
///
/// any attacker who is able to take control of a channel can just as easily send the funds via
/// lightning payments, so we never require that our counterparties support this option.
///
- /// The upfront key committed is provided from [`KeysInterface::get_shutdown_scriptpubkey`].
+ /// The upfront key committed is provided from [`SignerProvider::get_shutdown_scriptpubkey`].
///
/// Default value: true.
///
- /// [`KeysInterface::get_shutdown_scriptpubkey`]: crate::chain::keysinterface::KeysInterface::get_shutdown_scriptpubkey
+ /// [`SignerProvider::get_shutdown_scriptpubkey`]: crate::sign::SignerProvider::get_shutdown_scriptpubkey
pub commit_upfront_shutdown_pubkey: bool,
+ /// The Proportion of the channel value to configure as counterparty's channel reserve,
+ /// i.e., `their_channel_reserve_satoshis` for both outbound and inbound channels.
+ ///
+ /// `their_channel_reserve_satoshis` is the minimum balance that the other node has to maintain
+ /// on their side, at all times.
+ /// This ensures that if our counterparty broadcasts a revoked state, we can punish them by
+ /// claiming at least this value on chain.
+ ///
+ /// Channel reserve values greater than 30% could be considered highly unreasonable, since that
+ /// amount can never be used for payments.
+ /// Also, if our selected channel reserve for counterparty and counterparty's selected
+ /// channel reserve for us sum up to equal or greater than channel value, channel negotiations
+ /// will fail.
+ ///
+ /// Note: Versions of LDK earlier than v0.0.104 will fail to read channels with any channel reserve
+ /// other than the default value.
+ ///
+ /// Default value: 1% of channel value, i.e., configured as 10,000 millionths.
+ /// Minimum value: If the calculated proportional value is less than 1000 sats, it will be treated
+ /// as 1000 sats instead, which is a safe implementation-specific lower bound.
+ /// Maximum value: 1,000,000, any values larger than 1 Million will be treated as 1 Million (or 100%)
+ /// instead, although channel negotiations will fail in that case.
+ pub their_channel_reserve_proportional_millionths: u32,
+ #[cfg(anchors)]
+ /// If set, we attempt to negotiate the `anchors_zero_fee_htlc_tx`option for outbound channels.
+ ///
+ /// If this option is set, channels may be created that will not be readable by LDK versions
+ /// prior to 0.0.114, causing [`ChannelManager`]'s read method to return a
+ /// [`DecodeError::InvalidValue`].
+ ///
+ /// Note that setting this to true does *not* prevent us from opening channels with
+ /// counterparties that do not support the `anchors_zero_fee_htlc_tx` option; we will simply
+ /// fall back to a `static_remote_key` channel.
+ ///
+ /// LDK will not support the legacy `option_anchors` commitment version due to a discovered
+ /// vulnerability after its deployment. For more context, see the [`SIGHASH_SINGLE + update_fee
+ /// Considered Harmful`] mailing list post.
+ ///
+ /// Default value: false. This value is likely to change to true in the future.
+ ///
+ /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+ /// [`DecodeError::InvalidValue`]: crate::ln::msgs::DecodeError::InvalidValue
+ /// [`SIGHASH_SINGLE + update_fee Considered Harmful`]: https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-September/002796.html
+ pub negotiate_anchors_zero_fee_htlc_tx: bool,
+
+ /// The maximum number of HTLCs in-flight from our counterparty towards us at the same time.
+ ///
+ /// Increasing the value can help improve liquidity and stability in
+ /// routing at the cost of higher long term disk / DB usage.
+ ///
+ /// Note: Versions of LDK earlier than v0.0.115 will fail to read channels with a configuration
+ /// other than the default value.
+ ///
+ /// Default value: 50
+ /// Maximum value: 483, any values larger will be treated as 483.
+ /// This is the BOLT #2 spec limit on `max_accepted_htlcs`.
+ pub our_max_accepted_htlcs: u16,
}
impl Default for ChannelHandshakeConfig {
negotiate_scid_privacy: false,
announced_channel: false,
commit_upfront_shutdown_pubkey: true,
+ their_channel_reserve_proportional_millionths: 10_000,
+ #[cfg(anchors)]
+ negotiate_anchors_zero_fee_htlc_tx: false,
+ our_max_accepted_htlcs: 50,
}
}
}
///
/// These limits are only applied to our counterparty's limits, not our own.
///
-/// Use 0/<type>::max_value() as appropriate to skip checking.
+/// Use 0/`<type>::max_value()` as appropriate to skip checking.
///
/// Provides sane defaults for most configurations.
///
/// Options which apply on a per-channel basis and may change at runtime or based on negotiation
/// with our counterparty.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ChannelConfig {
/// Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound
/// over the channel.
/// to such payments may be sustantial if there are many dust HTLCs present when the
/// channel is force-closed.
///
+ /// The dust threshold for each HTLC is based on the `dust_limit_satoshis` for each party in a
+ /// channel negotiated throughout the channel open process, along with the fees required to have
+ /// a broadcastable HTLC spending transaction. When a channel supports anchor outputs
+ /// (specifically the zero fee HTLC transaction variant), this threshold no longer takes into
+ /// account the HTLC transaction fee as it is zero.
+ ///
/// This limit is applied for sent, forwarded, and received HTLCs and limits the total
/// exposure across all three types per-channel. Setting this too low may prevent the
/// sending or receipt of low-value HTLCs on high-traffic nodes, and this limit is very
/// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
/// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
pub force_close_avoidance_max_fee_satoshis: u64,
+ /// If set, allows this channel's counterparty to skim an additional fee off this node's inbound
+ /// HTLCs. Useful for liquidity providers to offload on-chain channel costs to end users.
+ ///
+ /// Usage:
+ /// - The payee will set this option and set its invoice route hints to use [intercept scids]
+ /// generated by this channel's counterparty.
+ /// - The counterparty will get an [`HTLCIntercepted`] event upon payment forward, and call
+ /// [`forward_intercepted_htlc`] with less than the amount provided in
+ /// [`HTLCIntercepted::expected_outbound_amount_msat`]. The difference between the expected and
+ /// actual forward amounts is their fee.
+ // TODO: link to LSP JIT channel invoice generation spec when it's merged
+ ///
+ /// # Note
+ /// It's important for payee wallet software to verify that [`PaymentClaimable::amount_msat`] is
+ /// as-expected if this feature is activated, otherwise they may lose money!
+ ///
+ /// # Note
+ /// Switching this config flag on may break compatibility with versions of LDK prior to 0.0.116.
+ ///
+ /// Default value: false.
+ ///
+ /// [intercept scids]: crate::ln::channelmanager::ChannelManager::get_intercept_scid
+ /// [`forward_intercepted_htlc`]: crate::ln::channelmanager::ChannelManager::forward_intercepted_htlc
+ /// [`HTLCIntercepted`]: crate::events::Event::HTLCIntercepted
+ /// [`HTLCIntercepted::expected_outbound_amount_msat`]: crate::events::Event::HTLCIntercepted::expected_outbound_amount_msat
+ /// [`PaymentClaimable::amount_msat`]: crate::events::Event::PaymentClaimable::amount_msat
+ // TODO: link to bLIP when it's merged
+ pub accept_underpaying_htlcs: bool,
+}
+
+impl ChannelConfig {
+ /// Applies the given [`ChannelConfigUpdate`] as a partial update to the [`ChannelConfig`].
+ pub fn apply(&mut self, update: &ChannelConfigUpdate) {
+ if let Some(forwarding_fee_proportional_millionths) = update.forwarding_fee_proportional_millionths {
+ self.forwarding_fee_proportional_millionths = forwarding_fee_proportional_millionths;
+ }
+ if let Some(forwarding_fee_base_msat) = update.forwarding_fee_base_msat {
+ self.forwarding_fee_base_msat = forwarding_fee_base_msat;
+ }
+ if let Some(cltv_expiry_delta) = update.cltv_expiry_delta {
+ self.cltv_expiry_delta = cltv_expiry_delta;
+ }
+ if let Some(max_dust_htlc_exposure_msat) = update.max_dust_htlc_exposure_msat {
+ self.max_dust_htlc_exposure_msat = max_dust_htlc_exposure_msat;
+ }
+ if let Some(force_close_avoidance_max_fee_satoshis) = update.force_close_avoidance_max_fee_satoshis {
+ self.force_close_avoidance_max_fee_satoshis = force_close_avoidance_max_fee_satoshis;
+ }
+ }
}
impl Default for ChannelConfig {
cltv_expiry_delta: 6 * 12, // 6 blocks/hour * 12 hours
max_dust_htlc_exposure_msat: 5_000_000,
force_close_avoidance_max_fee_satoshis: 1000,
+ accept_underpaying_htlcs: false,
+ }
+ }
+}
+
+impl_writeable_tlv_based!(ChannelConfig, {
+ (0, forwarding_fee_proportional_millionths, required),
+ (1, accept_underpaying_htlcs, (default_value, false)),
+ (2, forwarding_fee_base_msat, required),
+ (4, cltv_expiry_delta, required),
+ (6, max_dust_htlc_exposure_msat, required),
+ // ChannelConfig serialized this field with a required type of 8 prior to the introduction of
+ // LegacyChannelConfig. To make sure that serialization is not compatible with this one, we use
+ // the next required type of 10, which if seen by the old serialization will always fail.
+ (10, force_close_avoidance_max_fee_satoshis, required),
+});
+
+/// A parallel struct to [`ChannelConfig`] to define partial updates.
+#[allow(missing_docs)]
+pub struct ChannelConfigUpdate {
+ pub forwarding_fee_proportional_millionths: Option<u32>,
+ pub forwarding_fee_base_msat: Option<u32>,
+ pub cltv_expiry_delta: Option<u16>,
+ pub max_dust_htlc_exposure_msat: Option<u64>,
+ pub force_close_avoidance_max_fee_satoshis: Option<u64>,
+}
+
+impl Default for ChannelConfigUpdate {
+ fn default() -> ChannelConfigUpdate {
+ ChannelConfigUpdate {
+ forwarding_fee_proportional_millionths: None,
+ forwarding_fee_base_msat: None,
+ cltv_expiry_delta: None,
+ max_dust_htlc_exposure_msat: None,
+ force_close_avoidance_max_fee_satoshis: None,
+ }
+ }
+}
+
+impl From<ChannelConfig> for ChannelConfigUpdate {
+ fn from(config: ChannelConfig) -> ChannelConfigUpdate {
+ ChannelConfigUpdate {
+ forwarding_fee_proportional_millionths: Some(config.forwarding_fee_proportional_millionths),
+ forwarding_fee_base_msat: Some(config.forwarding_fee_base_msat),
+ cltv_expiry_delta: Some(config.cltv_expiry_delta),
+ max_dust_htlc_exposure_msat: Some(config.max_dust_htlc_exposure_msat),
+ force_close_avoidance_max_fee_satoshis: Some(config.force_close_avoidance_max_fee_satoshis),
}
}
}
/// [`ChannelHandshakeConfig::commit_upfront_shutdown_pubkey`] fields.
#[derive(Copy, Clone, Debug)]
pub(crate) struct LegacyChannelConfig {
- pub(crate) mutable: ChannelConfig,
+ pub(crate) options: ChannelConfig,
/// Deprecated but may still be read from. See [`ChannelHandshakeConfig::announced_channel`] to
/// set this when opening/accepting a channel.
pub(crate) announced_channel: bool,
impl Default for LegacyChannelConfig {
fn default() -> Self {
Self {
- mutable: ChannelConfig::default(),
+ options: ChannelConfig::default(),
announced_channel: false,
commit_upfront_shutdown_pubkey: true,
}
}
}
-impl ::util::ser::Writeable for LegacyChannelConfig {
- fn write<W: ::util::ser::Writer>(&self, writer: &mut W) -> Result<(), ::io::Error> {
+impl crate::util::ser::Writeable for LegacyChannelConfig {
+ fn write<W: crate::util::ser::Writer>(&self, writer: &mut W) -> Result<(), crate::io::Error> {
write_tlv_fields!(writer, {
- (0, self.mutable.forwarding_fee_proportional_millionths, required),
- (1, self.mutable.max_dust_htlc_exposure_msat, (default_value, 5_000_000)),
- (2, self.mutable.cltv_expiry_delta, required),
- (3, self.mutable.force_close_avoidance_max_fee_satoshis, (default_value, 1000)),
+ (0, self.options.forwarding_fee_proportional_millionths, required),
+ (1, self.options.max_dust_htlc_exposure_msat, (default_value, 5_000_000)),
+ (2, self.options.cltv_expiry_delta, required),
+ (3, self.options.force_close_avoidance_max_fee_satoshis, (default_value, 1000)),
(4, self.announced_channel, required),
(6, self.commit_upfront_shutdown_pubkey, required),
- (8, self.mutable.forwarding_fee_base_msat, required),
+ (8, self.options.forwarding_fee_base_msat, required),
});
Ok(())
}
}
-impl ::util::ser::Readable for LegacyChannelConfig {
- fn read<R: ::io::Read>(reader: &mut R) -> Result<Self, ::ln::msgs::DecodeError> {
+impl crate::util::ser::Readable for LegacyChannelConfig {
+ fn read<R: crate::io::Read>(reader: &mut R) -> Result<Self, crate::ln::msgs::DecodeError> {
let mut forwarding_fee_proportional_millionths = 0;
let mut max_dust_htlc_exposure_msat = 5_000_000;
let mut cltv_expiry_delta = 0;
let mut forwarding_fee_base_msat = 0;
read_tlv_fields!(reader, {
(0, forwarding_fee_proportional_millionths, required),
- (1, max_dust_htlc_exposure_msat, (default_value, 5_000_000)),
+ (1, max_dust_htlc_exposure_msat, (default_value, 5_000_000u64)),
(2, cltv_expiry_delta, required),
- (3, force_close_avoidance_max_fee_satoshis, (default_value, 1000)),
+ (3, force_close_avoidance_max_fee_satoshis, (default_value, 1000u64)),
(4, announced_channel, required),
(6, commit_upfront_shutdown_pubkey, required),
(8, forwarding_fee_base_msat, required),
});
Ok(Self {
- mutable: ChannelConfig {
+ options: ChannelConfig {
forwarding_fee_proportional_millionths,
max_dust_htlc_exposure_msat,
cltv_expiry_delta,
force_close_avoidance_max_fee_satoshis,
forwarding_fee_base_msat,
+ accept_underpaying_htlcs: false,
},
announced_channel,
commit_upfront_shutdown_pubkey,
/// (but currently with 0 relay fees!)
#[derive(Copy, Clone, Debug)]
pub struct UserConfig {
- /// Channel config that we propose to our counterparty.
- pub own_channel_config: ChannelHandshakeConfig,
- /// Limits applied to our counterparty's proposed channel config settings.
- pub peer_channel_config_limits: ChannelHandshakeLimits,
+ /// Channel handshake config that we propose to our counterparty.
+ pub channel_handshake_config: ChannelHandshakeConfig,
+ /// Limits applied to our counterparty's proposed channel handshake config settings.
+ pub channel_handshake_limits: ChannelHandshakeLimits,
/// Channel config which affects behavior during channel lifetime.
- pub channel_options: ChannelConfig,
+ pub channel_config: ChannelConfig,
/// If this is set to false, we will reject any HTLCs which were to be forwarded over private
/// channels. This prevents us from taking on HTLC-forwarding risk when we intend to run as a
/// node which is not online reliably.
///
/// Default value: false.
///
- /// [`Event::OpenChannelRequest`]: crate::util::events::Event::OpenChannelRequest
+ /// [`Event::OpenChannelRequest`]: crate::events::Event::OpenChannelRequest
/// [`msgs::OpenChannel`]: crate::ln::msgs::OpenChannel
/// [`msgs::AcceptChannel`]: crate::ln::msgs::AcceptChannel
pub manually_accept_inbound_channels: bool,
+ /// If this is set to true, LDK will intercept HTLCs that are attempting to be forwarded over
+ /// fake short channel ids generated via [`ChannelManager::get_intercept_scid`]. Upon HTLC
+ /// intercept, LDK will generate an [`Event::HTLCIntercepted`] which MUST be handled by the user.
+ ///
+ /// Setting this to true may break backwards compatibility with LDK versions < 0.0.113.
+ ///
+ /// Default value: false.
+ ///
+ /// [`ChannelManager::get_intercept_scid`]: crate::ln::channelmanager::ChannelManager::get_intercept_scid
+ /// [`Event::HTLCIntercepted`]: crate::events::Event::HTLCIntercepted
+ pub accept_intercept_htlcs: bool,
+ /// If this is set to false, when receiving a keysend payment we'll fail it if it has multiple
+ /// parts. If this is set to true, we'll accept the payment.
+ ///
+ /// Setting this to true will break backwards compatibility upon downgrading to an LDK
+ /// version < 0.0.116 while receiving an MPP keysend. If we have already received an MPP
+ /// keysend, downgrading will cause us to fail to deserialize [`ChannelManager`].
+ ///
+ /// Default value: false.
+ ///
+ /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+ pub accept_mpp_keysend: bool,
}
impl Default for UserConfig {
fn default() -> Self {
UserConfig {
- own_channel_config: ChannelHandshakeConfig::default(),
- peer_channel_config_limits: ChannelHandshakeLimits::default(),
- channel_options: ChannelConfig::default(),
+ channel_handshake_config: ChannelHandshakeConfig::default(),
+ channel_handshake_limits: ChannelHandshakeLimits::default(),
+ channel_config: ChannelConfig::default(),
accept_forwards_to_priv_channels: false,
accept_inbound_channels: true,
manually_accept_inbound_channels: false,
+ accept_intercept_htlcs: false,
+ accept_mpp_keysend: false,
}
}
}