Skip to content

Commit

Permalink
-f Explain worst-case
Browse files Browse the repository at this point in the history
  • Loading branch information
Antoine Riard committed Jul 28, 2021
1 parent 6643df5 commit 0db41f0
Showing 1 changed file with 36 additions and 20 deletions.
56 changes: 36 additions & 20 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1757,13 +1757,13 @@ impl<Signer: Sign> Channel<Signer> {
let mut holder_dusted_htlc_msat = 0;

let counterparty_dust_limit_timeout_sat = (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
let holder_dust_limit_timeout_sat = (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
let holder_dust_limit_success_sat = (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
for ref htlc in self.pending_inbound_htlcs.iter() {
htlc_inbound_value_msat += htlc.amount_msat;
if htlc.amount_msat / 1000 < counterparty_dust_limit_timeout_sat {
counterparty_dusted_htlc_msat += htlc.amount_msat + (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) * 1000;
}
if htlc.amount_msat / 1000 < holder_dust_limit_timeout_sat {
if htlc.amount_msat / 1000 < holder_dust_limit_success_sat {
holder_dusted_htlc_msat += htlc.amount_msat + (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) * 1000;
}
}
Expand All @@ -1778,14 +1778,14 @@ impl<Signer: Sign> Channel<Signer> {
let mut holder_dusted_htlc_msat = 0;

let counterparty_dust_limit_success_sat = (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.counterparty_dust_limit_satoshis;
let holder_dust_limit_success_sat = (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
let holder_dust_limit_timeout_sat = (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis;
for ref htlc in self.pending_outbound_htlcs.iter() {
htlc_outbound_value_msat += htlc.amount_msat;
if htlc.amount_msat / 1000 < counterparty_dust_limit_success_sat {
counterparty_dusted_htlc_msat += htlc.amount_msat + (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) * 1000;
}
if htlc.amount_msat / 1000 < holder_dust_limit_success_sat {
holder_dusted_htlc_msat += htlc.amount_msat + (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) * 1000;
if htlc.amount_msat / 1000 < holder_dust_limit_timeout_sat {
holder_dusted_htlc_msat += htlc.amount_msat + (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) * 1000;
}
}

Expand All @@ -1797,7 +1797,7 @@ impl<Signer: Sign> Channel<Signer> {
if *amount_msat / 1000 < counterparty_dust_limit_success_sat {
counterparty_dusted_htlc_msat += amount_msat + (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) * 1000;
}
if *amount_msat / 1000 < holder_dust_limit_success_sat {
if *amount_msat / 1000 < holder_dust_limit_timeout_sat {
holder_dusted_htlc_msat += amount_msat + (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) * 1000;
}
}
Expand Down Expand Up @@ -2032,7 +2032,7 @@ impl<Signer: Sign> Channel<Signer> {
}

let (inbound_htlc_count, htlc_inbound_value_msat, on_counterparty_tx_dust_inbound, on_holder_tx_dust_inbound) = self.get_inbound_pending_htlc_stats();
let (_, _, on_counterparty_tx_dust_outbound, on_holder_tx_dust_outbound) = self.get_outbound_pending_htlc_stats();
let (outbound_htlc_count, _, on_counterparty_tx_dust_outbound, on_holder_tx_dust_outbound) = self.get_outbound_pending_htlc_stats();
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)));
}
Expand Down Expand Up @@ -2061,20 +2061,35 @@ impl<Signer: Sign> Channel<Signer> {
}
}

#[cfg(any(test, feature = "fuzztarget"))]
{
// Holder dust balance on holder commitment transaction share the same safety
// risks though it's implictly bounded by the verification of the dust balance on
// the counterparty commitment transaction, with a delta due to the asymmetry
// of HTLC claim transaction weights.
//
// Assuming worst-case scenario of maximum number of inbound dust HTLCs,
// this delta is defined by := (N * `htlc_minimum_msat`) + (`feerate_per_kw` * HTLC_SUCCESS_TX_WEIGHT / 1000 * 1000)
// - (N * `htlc_minimum_msat`) + (`feerate_per_kw` * HTLC_TIMEOUT_TX_WEIGHT / 1000 * 1000)
//
// Where N is the number of pending inbound HTLCs. The HTLCs amounts are picked
// up to be equal to the `htlc_minimum_msat` as this is maxima of "trimmed-to-dust"
// weight difference between holder and counterparty transactions.
//
// With a default `max_balance_dust_htlc_msat`=5_000_000, N is at most 29.
//
// Assuming `feerate_per_kw`=253, solving the equation we find 344_000 millisatoshis.
assert_eq!(on_holder_tx_dust_inbound - inbound_htlc_count as u64 * (self.feerate_per_kw as u64 * (HTLC_SUCCESS_TX_WEIGHT - HTLC_TIMEOUT_TX_WEIGHT) / 1000 * 1000), on_counterparty_tx_dust_inbound);
assert_eq!(on_holder_tx_dust_outbound + outbound_htlc_count as u64 * (self.feerate_per_kw as u64 * (HTLC_SUCCESS_TX_WEIGHT - HTLC_TIMEOUT_TX_WEIGHT) / 1000 * 1000), on_counterparty_tx_dust_outbound);
}

if msg.amount_msat <= (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) * 1000 + self.counterparty_dust_limit_satoshis {
if on_counterparty_tx_dust_inbound + on_counterparty_tx_dust_outbound + msg.amount_msat + (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) * 1000 > self.get_max_balance_dust_htlc_msat() {
log_info!(logger, "Cannot accept value that would put holder dusted balance {} on counterparty commitment over limit {}", on_counterparty_tx_dust_inbound + on_counterparty_tx_dust_outbound, self.get_max_balance_dust_htlc_msat());
pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
}
}

if msg.amount_msat <= (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) + self.holder_dust_limit_satoshis {
if on_holder_tx_dust_inbound + on_holder_tx_dust_outbound + msg.amount_msat + (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) > self.get_max_balance_dust_htlc_msat() {
log_info!(logger, "Cannot accept value that would put holder dusted balance on holder commitment over limit {}", self.get_max_balance_dust_htlc_msat());
pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
}
}

let pending_value_to_self_msat =
self.value_to_self_msat + htlc_inbound_value_msat - removed_outbound_total_msat;
let pending_remote_value_msat =
Expand Down Expand Up @@ -4143,18 +4158,19 @@ impl<Signer: Sign> Channel<Signer> {
}
}

#[cfg(any(test, feature = "fuzztarget"))]
{
// See comment in `update_add_htlc()` for rational.
assert_eq!(on_holder_tx_dust_inbound - inbound_htlc_count as u64 * (self.feerate_per_kw as u64 * (HTLC_SUCCESS_TX_WEIGHT - HTLC_TIMEOUT_TX_WEIGHT) / 1000 * 1000), on_counterparty_tx_dust_inbound);
assert_eq!(on_holder_tx_dust_outbound + outbound_htlc_count as u64 * (self.feerate_per_kw as u64 * (HTLC_SUCCESS_TX_WEIGHT - HTLC_TIMEOUT_TX_WEIGHT) / 1000 * 1000), on_counterparty_tx_dust_outbound);
}

if amount_msat <= (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) * 1000 + self.counterparty_dust_limit_satoshis {
if on_counterparty_tx_dust_inbound + on_counterparty_tx_dust_outbound + amount_msat + (self.feerate_per_kw as u64 * HTLC_SUCCESS_TX_WEIGHT / 1000) * 1000 > self.get_max_balance_dust_htlc_msat() {
return Err(ChannelError::Ignore(format!("Cannot send value that would put holder dusted balance {} on counterparty commitment over limit {}", on_counterparty_tx_dust_inbound + on_counterparty_tx_dust_outbound, self.get_max_balance_dust_htlc_msat())));
}
}

if amount_msat <= (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) * 1000 + self.holder_dust_limit_satoshis {
if on_holder_tx_dust_inbound + on_holder_tx_dust_outbound + amount_msat + (self.feerate_per_kw as u64 * HTLC_TIMEOUT_TX_WEIGHT / 1000) * 1000 > self.get_max_balance_dust_htlc_msat() {
return Err(ChannelError::Ignore(format!("Cannot send value that would put holder dusted balance on holder commitment over limit {}", self.get_max_balance_dust_htlc_msat())));
}
}

let pending_value_to_self_msat = self.value_to_self_msat - htlc_outbound_value_msat;
if pending_value_to_self_msat < amount_msat {
return Err(ChannelError::Ignore(format!("Cannot send value that would overdraw remaining funds. Amount: {}, pending value to self {}", amount_msat, pending_value_to_self_msat)));
Expand Down

0 comments on commit 0db41f0

Please sign in to comment.