-
Notifications
You must be signed in to change notification settings - Fork 411
WIP: Configure holder max htlc value in flight function of channel value #868
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -389,7 +389,7 @@ pub(super) struct Channel<Signer: Sign> { | |
pub(super) counterparty_max_htlc_value_in_flight_msat: u64, | ||
#[cfg(not(test))] | ||
counterparty_max_htlc_value_in_flight_msat: u64, | ||
//get_holder_max_htlc_value_in_flight_msat(): u64, | ||
holder_max_htlc_value_percentage: u64, | ||
/// minimum channel reserve for self to maintain - set by them. | ||
counterparty_selected_channel_reserve_satoshis: u64, | ||
// get_holder_selected_channel_reserve_satoshis(channel_value_sats: u64): u64 | ||
|
@@ -483,8 +483,8 @@ macro_rules! secp_check { | |
|
||
impl<Signer: Sign> Channel<Signer> { | ||
// Convert constants + channel value to limits: | ||
fn get_holder_max_htlc_value_in_flight_msat(channel_value_satoshis: u64) -> u64 { | ||
channel_value_satoshis * 1000 / 10 //TODO | ||
fn get_holder_max_htlc_value_in_flight_msat(&self) -> u64 { | ||
self.channel_value_satoshis * 1000 * self.holder_max_htlc_value_percentage / 100 | ||
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. Should we bound by min(max(setting, 1), 90) (and update documentation to match)? 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. Make sense. In #850 @TheBlueMatt mentioned sthing regarding an absolute value which we did not understand:
Do we need to dig further or can we forget it ? 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. I think its fine to skip it, I was just generally trying to say "maybe just a % isn't a sufficiently flexible knob, so we may need more options", but in hindsight, I'm not sure it matters, I think just the way it is is fine. |
||
} | ||
|
||
/// Returns a minimum channel reserve value the remote needs to maintain, | ||
|
@@ -582,6 +582,7 @@ impl<Signer: Sign> Channel<Signer> { | |
counterparty_max_htlc_value_in_flight_msat: 0, | ||
counterparty_selected_channel_reserve_satoshis: 0, | ||
counterparty_htlc_minimum_msat: 0, | ||
holder_max_htlc_value_percentage: config.own_channel_config.our_htlc_max_in_flight_percentage, | ||
holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat }, | ||
counterparty_max_accepted_htlcs: 0, | ||
minimum_depth: 0, // Filled in in accept_channel | ||
|
@@ -820,6 +821,7 @@ impl<Signer: Sign> Channel<Signer> { | |
counterparty_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000), | ||
counterparty_selected_channel_reserve_satoshis: msg.channel_reserve_satoshis, | ||
counterparty_htlc_minimum_msat: msg.htlc_minimum_msat, | ||
holder_max_htlc_value_percentage: config.own_channel_config.our_htlc_max_in_flight_percentage, | ||
holder_htlc_minimum_msat: if config.own_channel_config.our_htlc_minimum_msat == 0 { 1 } else { config.own_channel_config.our_htlc_minimum_msat }, | ||
counterparty_max_accepted_htlcs: msg.max_accepted_htlcs, | ||
minimum_depth: config.own_channel_config.minimum_depth, | ||
|
@@ -1941,7 +1943,7 @@ impl<Signer: Sign> Channel<Signer> { | |
if inbound_htlc_count + 1 > OUR_MAX_HTLCS as u32 { | ||
return Err(ChannelError::Close(format!("Remote tried to push more than our max accepted HTLCs ({})", OUR_MAX_HTLCS))); | ||
} | ||
let holder_max_htlc_value_in_flight_msat = Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis); | ||
let holder_max_htlc_value_in_flight_msat = self.get_holder_max_htlc_value_in_flight_msat(); | ||
if htlc_inbound_value_msat + msg.amount_msat > holder_max_htlc_value_in_flight_msat { | ||
return Err(ChannelError::Close(format!("Remote HTLC add would put them over our max HTLC value ({})", holder_max_htlc_value_in_flight_msat))); | ||
} | ||
|
@@ -3328,14 +3330,7 @@ impl<Signer: Sign> Channel<Signer> { | |
|
||
/// Allowed in any state (including after shutdown) | ||
pub fn get_announced_htlc_max_msat(&self) -> u64 { | ||
return cmp::min( | ||
// Upper bound by capacity. We make it a bit less than full capacity to prevent attempts | ||
// to use full capacity. This is an effort to reduce routing failures, because in many cases | ||
// channel might have been used to route very small values (either by honest users or as DoS). | ||
self.channel_value_satoshis * 1000 * 9 / 10, | ||
|
||
Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis) | ||
); | ||
self.get_holder_max_htlc_value_in_flight_msat() | ||
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. Can we deprecate this method and instead make |
||
} | ||
|
||
/// Allowed in any state (including after shutdown) | ||
|
@@ -3699,7 +3694,7 @@ impl<Signer: Sign> Channel<Signer> { | |
funding_satoshis: self.channel_value_satoshis, | ||
push_msat: self.channel_value_satoshis * 1000 - self.value_to_self_msat, | ||
dust_limit_satoshis: self.holder_dust_limit_satoshis, | ||
max_htlc_value_in_flight_msat: Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis), | ||
max_htlc_value_in_flight_msat: self.get_holder_max_htlc_value_in_flight_msat(), | ||
channel_reserve_satoshis: Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis), | ||
htlc_minimum_msat: self.holder_htlc_minimum_msat, | ||
feerate_per_kw: self.feerate_per_kw as u32, | ||
|
@@ -3733,7 +3728,7 @@ impl<Signer: Sign> Channel<Signer> { | |
msgs::AcceptChannel { | ||
temporary_channel_id: self.channel_id, | ||
dust_limit_satoshis: self.holder_dust_limit_satoshis, | ||
max_htlc_value_in_flight_msat: Channel::<Signer>::get_holder_max_htlc_value_in_flight_msat(self.channel_value_satoshis), | ||
max_htlc_value_in_flight_msat: self.get_holder_max_htlc_value_in_flight_msat(), | ||
channel_reserve_satoshis: Channel::<Signer>::get_holder_selected_channel_reserve_satoshis(self.channel_value_satoshis), | ||
htlc_minimum_msat: self.holder_htlc_minimum_msat, | ||
minimum_depth: self.minimum_depth, | ||
|
@@ -4502,6 +4497,7 @@ impl<Signer: Sign> Writeable for Channel<Signer> { | |
self.counterparty_dust_limit_satoshis.write(writer)?; | ||
self.holder_dust_limit_satoshis.write(writer)?; | ||
self.counterparty_max_htlc_value_in_flight_msat.write(writer)?; | ||
self.holder_max_htlc_value_percentage.write(writer)?; | ||
self.counterparty_selected_channel_reserve_satoshis.write(writer)?; | ||
self.counterparty_htlc_minimum_msat.write(writer)?; | ||
self.holder_htlc_minimum_msat.write(writer)?; | ||
|
@@ -4672,6 +4668,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer> | |
let counterparty_dust_limit_satoshis = Readable::read(reader)?; | ||
let holder_dust_limit_satoshis = Readable::read(reader)?; | ||
let counterparty_max_htlc_value_in_flight_msat = Readable::read(reader)?; | ||
let holder_max_htlc_value_percentage = Readable::read(reader)?; | ||
let counterparty_selected_channel_reserve_satoshis = Readable::read(reader)?; | ||
let counterparty_htlc_minimum_msat = Readable::read(reader)?; | ||
let holder_htlc_minimum_msat = Readable::read(reader)?; | ||
|
@@ -4752,6 +4749,7 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer> | |
counterparty_dust_limit_satoshis, | ||
holder_dust_limit_satoshis, | ||
counterparty_max_htlc_value_in_flight_msat, | ||
holder_max_htlc_value_percentage, | ||
counterparty_selected_channel_reserve_satoshis, | ||
counterparty_htlc_minimum_msat, | ||
holder_htlc_minimum_msat, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,8 @@ pub struct ChannelHandshakeConfig { | |
/// Default value: 1. If the value is less than 1, it is ignored and set to 1, as is required | ||
/// by the protocol. | ||
pub our_htlc_minimum_msat: u64, | ||
/// Set to percentage of channel value used to control the channel maximum htlc value | ||
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. This could be a bit more specific and should include some guidance on how to set it. Something like "The maximum amount we will accept for any single incoming HTLC on our channels, expressed as a percentage of the value of the channel. Payments to or routed through us above this value will be rejected before even reaching us. If this value is too large and we are a routing node, a malicious third-party could tie up our entire channel balance in a single HTLC which they refuse to resolve quickly." This should also mention the current default value. 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. Note, I don't think this comment is accurate on the last part. IIRC, "htlc_max_value_in_flight_msat" is the global inbound HTLC balance, not a single HTLC. Setting a low-percentage doesn't prevent to tie up the entire channel balance in a single HTLC. Also I think it should say inbound liquidity instead of channel balance, our channel balance is the outbound liquidity ? W.r.t to the default value, I would be more generous like 15% or 20%. Let say you want to preserve liquidity equilibrium in both direction. If you reach 35/75 in one direction, you trigger a rebalancing action like a circular loop to another one of your channel. A max_htlc_value of 15% means even at 35, you still have 20% of inbound liquidity buffer to keep the channel operational, assuming the in-flight 15% settled before the rebalance operation succeed. Or what's your thinking on how a user should selection this value ? Otherwise, if you want to limit security risk, just open a smaller channel to avoid wasting almost-never used liquidity. 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. Oops! You're totally right. As to guidance, that's a much tougher question if I read the variable name correctly :). I'm not sure its right to focus on DoS here, its more about the 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.
Yep, csv_delay vs cltv expiry delta sounds a good rational for guidance.
I think unbalancing can be provoked as well due to multiple payments than a single one and "htlc_max_value_in_flight_msat" scope either but i would say such rebalancing concern should be noted there as we indirectly set hltc_maximum_msat in function of htlc_max_value_in_flight_msat (see |
||
pub our_htlc_max_in_flight_percentage: u64, | ||
} | ||
|
||
impl Default for ChannelHandshakeConfig { | ||
|
@@ -55,6 +57,7 @@ impl Default for ChannelHandshakeConfig { | |
minimum_depth: 6, | ||
our_to_self_delay: BREAKDOWN_TIMEOUT, | ||
our_htlc_minimum_msat: 1, | ||
our_htlc_max_in_flight_percentage: 10, | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment about this method "Returns a max in-flight inbound htlc value the remote can't overbid, required by us" ?