Skip to content

Commit 71a4209

Browse files
committed
Consider fees and anchor in balances when checking reserve requirements
1 parent fe1deec commit 71a4209

File tree

1 file changed

+114
-45
lines changed

1 file changed

+114
-45
lines changed

lightning/src/ln/channel.rs

Lines changed: 114 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5084,26 +5084,21 @@ where
50845084
pre_balance: u64, post_balance: u64, pre_channel_value: u64, post_channel_value: u64,
50855085
dust_limit: u64,
50865086
) -> Result<(), u64> {
5087-
if post_balance == 0 {
5088-
// 0 balance is fine
5089-
return Ok(());
5090-
}
50915087
let post_channel_reserve = get_v2_channel_reserve_satoshis(post_channel_value, dust_limit);
50925088
if post_balance >= post_channel_reserve {
50935089
return Ok(());
50945090
}
5095-
// post is not OK, check pre
5096-
if pre_balance == 0 {
5097-
// pre OK, post not -> not
5098-
return Err(post_channel_reserve);
5099-
}
51005091
let pre_channel_reserve = get_v2_channel_reserve_satoshis(pre_channel_value, dust_limit);
51015092
if pre_balance >= pre_channel_reserve {
5102-
// pre OK, post not -> not
5093+
// We're not allowed to dip below the reserve once we've been above.
51035094
return Err(post_channel_reserve);
51045095
}
5105-
// post not OK, but so was pre -> OK
5106-
Ok(())
5096+
// Make sure we either remain with the same balance or move towards the reserve.
5097+
if post_balance >= pre_balance {
5098+
Ok(())
5099+
} else {
5100+
Err(post_channel_reserve)
5101+
}
51075102
}
51085103

51095104
/// Check that balances meet the channel reserve requirements or violates them (below reserve).
@@ -10916,6 +10911,71 @@ where
1091610911
})
1091710912
}
1091810913

10914+
/// Compute the channel balances (local & remote) by taking into account fees, anchor values, and dust limits.
10915+
/// Pending HTLCs are not taken into account, this method should be used when there is no such,
10916+
/// e.g. in quiscence state
10917+
#[cfg(splicing)]
10918+
fn compute_balances_less_fees(
10919+
&self, channel_value_sats: u64, value_to_self_msat: u64, is_local: bool,
10920+
) -> (u64, u64) {
10921+
// We should get here only when there are no pending HTLCs, as they are not taken into account
10922+
debug_assert!(self.context.pending_inbound_htlcs.is_empty());
10923+
debug_assert!(self.context.pending_outbound_htlcs.is_empty());
10924+
10925+
let feerate_per_kw = self.context.feerate_per_kw;
10926+
10927+
// compute 'raw' counterparty balance
10928+
let value_to_remote_msat: i64 =
10929+
((channel_value_sats * 1000) as i64).saturating_sub(value_to_self_msat as i64);
10930+
debug_assert!(value_to_remote_msat >= 0);
10931+
10932+
let total_fee_sat = SpecTxBuilder {}.commit_tx_fee_sat(
10933+
feerate_per_kw,
10934+
0,
10935+
&self.funding.channel_transaction_parameters.channel_type_features,
10936+
);
10937+
let anchors_val = if self
10938+
.funding
10939+
.channel_transaction_parameters
10940+
.channel_type_features
10941+
.supports_anchors_zero_fee_htlc_tx()
10942+
{
10943+
ANCHOR_OUTPUT_VALUE_SATOSHI * 2
10944+
} else {
10945+
0
10946+
} as i64;
10947+
10948+
// consider fees and anchor values
10949+
let (mut value_to_self, mut value_to_remote) = if self.funding.is_outbound() {
10950+
(
10951+
(value_to_self_msat as i64) / 1000 - anchors_val - total_fee_sat as i64,
10952+
value_to_remote_msat / 1000,
10953+
)
10954+
} else {
10955+
(
10956+
(value_to_self_msat as i64) / 1000,
10957+
value_to_remote_msat / 1000 - anchors_val - total_fee_sat as i64,
10958+
)
10959+
};
10960+
10961+
// consider dust limit
10962+
let broadcaster_dust_limit_satoshis = if is_local {
10963+
self.context.holder_dust_limit_satoshis
10964+
} else {
10965+
self.context.counterparty_dust_limit_satoshis
10966+
} as i64;
10967+
if value_to_self < broadcaster_dust_limit_satoshis {
10968+
value_to_self = 0;
10969+
}
10970+
debug_assert!(value_to_self >= 0);
10971+
if value_to_remote < broadcaster_dust_limit_satoshis {
10972+
value_to_remote = 0;
10973+
}
10974+
debug_assert!(value_to_remote >= 0);
10975+
10976+
(value_to_self as u64, value_to_remote as u64)
10977+
}
10978+
1091910979
/// Handle splice_ack
1092010980
#[cfg(splicing)]
1092110981
pub(crate) fn splice_ack<ES: Deref, L: Deref>(
@@ -10926,35 +10986,37 @@ where
1092610986
ES::Target: EntropySource,
1092710987
L::Target: Logger,
1092810988
{
10929-
let pending_splice = if let Some(ref mut pending_splice) = &mut self.pending_splice {
10930-
pending_splice
10931-
} else {
10932-
return Err(ChannelError::Ignore(format!("Channel is not in pending splice")));
10933-
};
10989+
let funding_negotiation_context = {
10990+
let pending_splice = if let Some(ref mut pending_splice) = &mut self.pending_splice {
10991+
pending_splice
10992+
} else {
10993+
return Err(ChannelError::Ignore(format!("Channel is not in pending splice")));
10994+
};
1093410995

10935-
// TODO(splicing): Add check that we are the splice (quiescence) initiator
10996+
// TODO(splicing): Add check that we are the splice (quiescence) initiator
1093610997

10937-
let funding_negotiation_context = match pending_splice.funding_negotiation.take() {
10938-
Some(FundingNegotiation::AwaitingAck(context)) => context,
10939-
Some(FundingNegotiation::ConstructingTransaction(funding, constructor)) => {
10940-
pending_splice.funding_negotiation =
10941-
Some(FundingNegotiation::ConstructingTransaction(funding, constructor));
10942-
return Err(ChannelError::WarnAndDisconnect(format!(
10943-
"Got unexpected splice_ack; splice negotiation already in progress"
10944-
)));
10945-
},
10946-
Some(FundingNegotiation::AwaitingSignatures(funding)) => {
10947-
pending_splice.funding_negotiation =
10948-
Some(FundingNegotiation::AwaitingSignatures(funding));
10949-
return Err(ChannelError::WarnAndDisconnect(format!(
10950-
"Got unexpected splice_ack; splice negotiation already in progress"
10951-
)));
10952-
},
10953-
None => {
10954-
return Err(ChannelError::Ignore(format!(
10955-
"Got unexpected splice_ack; no splice negotiation in progress"
10956-
)));
10957-
},
10998+
match pending_splice.funding_negotiation.take() {
10999+
Some(FundingNegotiation::AwaitingAck(context)) => context,
11000+
Some(FundingNegotiation::ConstructingTransaction(funding, constructor)) => {
11001+
pending_splice.funding_negotiation =
11002+
Some(FundingNegotiation::ConstructingTransaction(funding, constructor));
11003+
return Err(ChannelError::WarnAndDisconnect(format!(
11004+
"Got unexpected splice_ack; splice negotiation already in progress"
11005+
)));
11006+
},
11007+
Some(FundingNegotiation::AwaitingSignatures(funding)) => {
11008+
pending_splice.funding_negotiation =
11009+
Some(FundingNegotiation::AwaitingSignatures(funding));
11010+
return Err(ChannelError::WarnAndDisconnect(format!(
11011+
"Got unexpected splice_ack; splice negotiation already in progress"
11012+
)));
11013+
},
11014+
None => {
11015+
return Err(ChannelError::Ignore(format!(
11016+
"Got unexpected splice_ack; no splice negotiation in progress"
11017+
)));
11018+
},
11019+
}
1095811020
};
1095911021

1096011022
let our_funding_contribution_satoshis =
@@ -10979,15 +11041,17 @@ where
1097911041
let pre_balance_self = self.funding.value_to_self_msat;
1098011042
let post_balance_self =
1098111043
PendingSplice::add_checked(pre_balance_self, our_funding_contribution_satoshis);
10982-
let pre_balance_counterparty = pre_channel_value.saturating_sub(pre_balance_self);
10983-
let post_balance_counterparty = post_channel_value.saturating_sub(post_balance_self);
11044+
let (pre_balance_self_less_fees, pre_balance_counterparty_less_fees) =
11045+
self.compute_balances_less_fees(pre_channel_value, pre_balance_self, true);
11046+
let (post_balance_self_less_fees, post_balance_counterparty_less_fees) =
11047+
self.compute_balances_less_fees(post_channel_value, post_balance_self, true);
1098411048
// Pre-check for reserve requirement
1098511049
// This will also be checked later at tx_complete
1098611050
let _res = self.context.check_splice_balances_meet_v2_reserve_requirements(
10987-
pre_balance_self,
10988-
post_balance_self,
10989-
pre_balance_counterparty,
10990-
post_balance_counterparty,
11051+
pre_balance_self_less_fees,
11052+
post_balance_self_less_fees,
11053+
pre_balance_counterparty_less_fees,
11054+
post_balance_counterparty_less_fees,
1099111055
pre_channel_value,
1099211056
post_channel_value,
1099311057
)?;
@@ -11017,6 +11081,11 @@ where
1101711081
let tx_msg_opt = interactive_tx_constructor.take_initiator_first_message();
1101811082

1101911083
debug_assert!(self.interactive_tx_signing_session.is_none());
11084+
let pending_splice = if let Some(ref mut pending_splice) = &mut self.pending_splice {
11085+
pending_splice
11086+
} else {
11087+
return Err(ChannelError::Ignore(format!("Channel is not in pending splice")));
11088+
};
1102011089
pending_splice.funding_negotiation = Some(FundingNegotiation::ConstructingTransaction(
1102111090
splice_funding,
1102211091
interactive_tx_constructor,

0 commit comments

Comments
 (0)