Skip to content

Commit 4d5665c

Browse files
committed
Validate negative splice_ack.funding_contribution_satoshis
From BOLT #2: ``` - If `funding_contribution_satoshis` is negative and its absolute value is greater than the sending node's current channel balance: - MUST send a `warning` and close the connection or send an `error` and fail the channel. ``` We allow the remote to be below the new reserve as long as their funding contribution is not negative; we don't care whether they were above or below the previous funding reserve.
1 parent 1edbe7e commit 4d5665c

File tree

1 file changed

+42
-2
lines changed

1 file changed

+42
-2
lines changed

lightning/src/ln/channel.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10914,12 +10914,52 @@ where
1091410914
msg.funding_pubkey,
1091510915
)?;
1091610916

10917-
// TODO(splicing): Pre-check for reserve requirement
10918-
// (Note: It should also be checked later at tx_complete)
10917+
if their_funding_contribution_satoshis.is_negative() {
10918+
self.validate_their_negative_funding_contribution(&splice_funding)?;
10919+
}
1091910920

1092010921
Ok(splice_funding)
1092110922
}
1092210923

10924+
/// Used to validate a negative `funding_contribution_satoshis` in `splice_init` and `splice_ack` messages.
10925+
#[cfg(splicing)]
10926+
fn validate_their_negative_funding_contribution(
10927+
&self, spliced_funding: &FundingScope,
10928+
) -> Result<(), ChannelError> {
10929+
// Calculate the remote's new balance
10930+
//
10931+
// We only validate the remote's balance on the next *remote* commitment transaction.
10932+
//
10933+
// We don't care for a small / no to_remote output on our next *local* commitment transaction as the purpose of the
10934+
// channel reserve is to ensure we can punish *them* if they misbehave. See `validate_update_add_htlc` for another
10935+
// place where we apply the same reasoning.
10936+
//
10937+
// This comment is only relevant if they are the funder of the channel because the remote balance will be the same
10938+
// on both local and remote commitments if they are the fundee.
10939+
let spliced_commitment_stats =
10940+
self.context.build_commitment_stats(&spliced_funding, false, true, None, None);
10941+
let spliced_remote_balance_msat = if spliced_funding.is_outbound() {
10942+
spliced_commitment_stats.remote_balance_before_fee_msat
10943+
} else {
10944+
spliced_commitment_stats
10945+
.remote_balance_before_fee_msat
10946+
.saturating_sub(spliced_commitment_stats.commit_tx_fee_sat * 1000)
10947+
};
10948+
10949+
// Check if the remote's new balance is under the specified reserve
10950+
if spliced_remote_balance_msat
10951+
< spliced_funding.holder_selected_channel_reserve_satoshis * 1000
10952+
{
10953+
return Err(ChannelError::Warn(format!(
10954+
"Remote balance below reserve mandated by holder: {} vs {}",
10955+
spliced_remote_balance_msat,
10956+
spliced_funding.holder_selected_channel_reserve_satoshis * 1000,
10957+
)));
10958+
}
10959+
10960+
Ok(())
10961+
}
10962+
1092310963
#[cfg(splicing)]
1092410964
pub fn splice_locked<NS: Deref, L: Deref>(
1092510965
&mut self, msg: &msgs::SpliceLocked, node_signer: &NS, chain_hash: ChainHash,

0 commit comments

Comments
 (0)