Skip to content

Commit 3d94ac7

Browse files
authored
Merge pull request #4615 from tankyleo/2026-05-splice-min-funding-satoshis
Enforce `min_funding_satoshis` after splices
2 parents b8118e3 + 6c2090d commit 3d94ac7

4 files changed

Lines changed: 339 additions & 13 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,7 +2778,7 @@ impl FundingScope {
27782778
fn for_splice<SP: SignerProvider>(
27792779
prev_funding: &Self, context: &ChannelContext<SP>, our_funding_contribution: SignedAmount,
27802780
their_funding_contribution: SignedAmount, counterparty_funding_pubkey: PublicKey,
2781-
our_new_holder_keys: ChannelPublicKeys,
2781+
our_new_holder_keys: ChannelPublicKeys, min_funding_satoshis: u64,
27822782
) -> Result<Self, String> {
27832783
if our_funding_contribution.unsigned_abs() > Amount::MAX_MONEY {
27842784
return Err(format!(
@@ -2817,13 +2817,27 @@ impl FundingScope {
28172817
),
28182818
)?;
28192819

2820-
let post_channel_value_sat = prev_funding.get_value_satoshis()
2820+
let post_channel_value_sat = prev_funding
2821+
.get_value_satoshis()
28212822
.checked_add_signed(our_funding_contribution.to_sat())
28222823
.and_then(|v| v.checked_add_signed(their_funding_contribution.to_sat()))
2823-
.ok_or(format!("The sum of contributions {our_funding_contribution} and {their_funding_contribution} is greater than the channel's value"))?;
2824+
.ok_or(format!(
2825+
"The sum of contributions {our_funding_contribution} and \
2826+
{their_funding_contribution} is greater than the channel's value"
2827+
))?;
28242828
if post_channel_value_sat < MIN_CHANNEL_VALUE_SATOSHIS {
28252829
return Err(format!(
2826-
"Spliced channel value must be at least 1000 satoshis. It would be {post_channel_value_sat}",
2830+
"Spliced channel value must be at least 1000 satoshis. It would be \
2831+
{post_channel_value_sat}"
2832+
));
2833+
}
2834+
if post_channel_value_sat < min_funding_satoshis
2835+
&& their_funding_contribution.is_negative()
2836+
&& !prev_funding.is_outbound()
2837+
{
2838+
return Err(format!(
2839+
"Spliced channel value {post_channel_value_sat} would be smaller \
2840+
than the configured min_funding_satoshis {min_funding_satoshis}"
28272841
));
28282842
}
28292843

@@ -13048,6 +13062,7 @@ where
1304813062
fn validate_splice_contributions(
1304913063
&self, our_funding_contribution: SignedAmount, their_funding_contribution: SignedAmount,
1305013064
counterparty_funding_pubkey: PublicKey, our_new_holder_keys: ChannelPublicKeys,
13065+
min_funding_satoshis: u64,
1305113066
) -> Result<FundingScope, String> {
1305213067
let candidate_scope = FundingScope::for_splice(
1305313068
&self.funding,
@@ -13056,6 +13071,7 @@ where
1305613071
their_funding_contribution,
1305713072
counterparty_funding_pubkey,
1305813073
our_new_holder_keys,
13074+
min_funding_satoshis,
1305913075
)
1306013076
.map_err(|e| format!("Channel {} cannot be spliced; {}", self.context.channel_id(), e))?;
1306113077

@@ -13166,7 +13182,7 @@ where
1316613182

1316713183
pub(crate) fn splice_init<ES: EntropySource, L: Logger>(
1316813184
&mut self, msg: &msgs::SpliceInit, entropy_source: &ES, holder_node_id: &PublicKey,
13169-
logger: &L,
13185+
min_funding_satoshis: u64, logger: &L,
1317013186
) -> Result<msgs::SpliceAck, InteractiveTxMsgError> {
1317113187
self.validate_splice_init(msg).map_err(|e| self.quiescent_negotiation_err(e))?;
1317213188

@@ -13199,6 +13215,7 @@ where
1319913215
their_funding_contribution,
1320013216
msg.funding_pubkey,
1320113217
holder_pubkeys,
13218+
min_funding_satoshis,
1320213219
)
1320313220
.map_err(|e| self.quiescent_negotiation_err(ChannelError::WarnAndDisconnect(e)))?;
1320413221

@@ -13334,7 +13351,7 @@ where
1333413351

1333513352
pub(crate) fn tx_init_rbf<ES: EntropySource, F: FeeEstimator, L: Logger>(
1333613353
&mut self, msg: &msgs::TxInitRbf, entropy_source: &ES, holder_node_id: &PublicKey,
13337-
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
13354+
fee_estimator: &LowerBoundedFeeEstimator<F>, min_funding_satoshis: u64, logger: &L,
1333813355
) -> Result<msgs::TxAckRbf, InteractiveTxMsgError> {
1333913356
let (holder_pubkeys, counterparty_funding_pubkey) = self
1334013357
.validate_tx_init_rbf(msg, fee_estimator)
@@ -13381,6 +13398,7 @@ where
1338113398
their_funding_contribution,
1338213399
counterparty_funding_pubkey,
1338313400
holder_pubkeys,
13401+
min_funding_satoshis,
1338413402
)
1338513403
.map_err(|e| self.quiescent_negotiation_err(ChannelError::WarnAndDisconnect(e)))?;
1338613404

@@ -13452,7 +13470,9 @@ where
1345213470
})
1345313471
}
1345413472

13455-
fn validate_tx_ack_rbf(&self, msg: &msgs::TxAckRbf) -> Result<FundingScope, ChannelError> {
13473+
fn validate_tx_ack_rbf(
13474+
&self, msg: &msgs::TxAckRbf, min_funding_satoshis: u64,
13475+
) -> Result<FundingScope, ChannelError> {
1345613476
let pending_splice = self
1345713477
.pending_splice
1345813478
.as_ref()
@@ -13478,6 +13498,7 @@ where
1347813498
their_funding_contribution,
1347913499
counterparty_funding_pubkey,
1348013500
holder_pubkeys,
13501+
min_funding_satoshis,
1348113502
)
1348213503
.map_err(|e| ChannelError::WarnAndDisconnect(e))?;
1348313504

@@ -13486,9 +13507,9 @@ where
1348613507

1348713508
pub(crate) fn tx_ack_rbf<ES: EntropySource, L: Logger>(
1348813509
&mut self, msg: &msgs::TxAckRbf, entropy_source: &ES, holder_node_id: &PublicKey,
13489-
logger: &L,
13510+
min_funding_satoshis: u64, logger: &L,
1349013511
) -> Result<Option<InteractiveTxMessageSend>, ChannelError> {
13491-
let rbf_funding = self.validate_tx_ack_rbf(msg)?;
13512+
let rbf_funding = self.validate_tx_ack_rbf(msg, min_funding_satoshis)?;
1349213513

1349313514
log_info!(
1349413515
logger,
@@ -13519,9 +13540,9 @@ where
1351913540

1352013541
pub(crate) fn splice_ack<ES: EntropySource, L: Logger>(
1352113542
&mut self, msg: &msgs::SpliceAck, entropy_source: &ES, holder_node_id: &PublicKey,
13522-
logger: &L,
13543+
min_funding_satoshis: u64, logger: &L,
1352313544
) -> Result<Option<InteractiveTxMessageSend>, ChannelError> {
13524-
let splice_funding = self.validate_splice_ack(msg)?;
13545+
let splice_funding = self.validate_splice_ack(msg, min_funding_satoshis)?;
1352513546

1352613547
log_info!(
1352713548
logger,
@@ -13553,7 +13574,9 @@ where
1355313574
Ok(tx_msg_opt)
1355413575
}
1355513576

13556-
fn validate_splice_ack(&self, msg: &msgs::SpliceAck) -> Result<FundingScope, ChannelError> {
13577+
fn validate_splice_ack(
13578+
&self, msg: &msgs::SpliceAck, min_funding_satoshis: u64,
13579+
) -> Result<FundingScope, ChannelError> {
1355713580
// TODO(splicing): Add check that we are the splice (quiescence) initiator
1355813581

1355913582
let pending_splice = self
@@ -13576,6 +13599,7 @@ where
1357613599
their_funding_contribution,
1357713600
msg.funding_pubkey,
1357813601
new_keys,
13602+
min_funding_satoshis,
1357913603
)
1358013604
.map_err(|e| ChannelError::WarnAndDisconnect(e))?;
1358113605

@@ -13692,6 +13716,9 @@ where
1369213716
SignedAmount::ZERO,
1369313717
funding.counterparty_funding_pubkey().clone(),
1369413718
funding.get_holder_pubkeys().clone(),
13719+
// When the counterparty's contribution is non-negative, we don't validate
13720+
// the post splice channel value against `min_funding_satoshis`
13721+
0,
1369513722
)
1369613723
.unwrap();
1369713724
// Splice-out an additional satoshi, and validation fails!
@@ -13700,6 +13727,9 @@ where
1370013727
SignedAmount::ZERO,
1370113728
funding.counterparty_funding_pubkey().clone(),
1370213729
funding.get_holder_pubkeys().clone(),
13730+
// When the counterparty's contribution is non-negative, we don't validate
13731+
// the post splice channel value against `min_funding_satoshis`
13732+
0,
1370313733
)
1370413734
.unwrap_err();
1370513735
}

lightning/src/ln/channelmanager.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13384,6 +13384,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1338413384
msg,
1338513385
&self.entropy_source,
1338613386
&self.get_our_node_id(),
13387+
self.config.read().unwrap().channel_handshake_limits.min_funding_satoshis,
1338713388
&self.logger,
1338813389
) {
1338913390
Ok(splice_ack_msg) => {
@@ -13441,6 +13442,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1344113442
&self.entropy_source,
1344213443
&self.get_our_node_id(),
1344313444
&self.fee_estimator,
13445+
self.config.read().unwrap().channel_handshake_limits.min_funding_satoshis,
1344413446
&self.logger,
1344513447
) {
1344613448
Ok(tx_ack_rbf_msg) => {
@@ -13497,6 +13499,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1349713499
msg,
1349813500
&self.entropy_source,
1349913501
&self.get_our_node_id(),
13502+
self.config.read().unwrap().channel_handshake_limits.min_funding_satoshis,
1350013503
&self.logger,
1350113504
);
1350213505
let tx_msg_opt =
@@ -13541,6 +13544,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1354113544
msg,
1354213545
&self.entropy_source,
1354313546
&self.get_our_node_id(),
13547+
self.config.read().unwrap().channel_handshake_limits.min_funding_satoshis,
1354413548
&self.logger,
1354513549
);
1354613550
let tx_msg_opt =

0 commit comments

Comments
 (0)