@@ -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 }
0 commit comments