Skip to content

Commit 59fbd7e

Browse files
committed
f - check that splice-out outputs can be paid for by channel balance
1 parent d9f10e4 commit 59fbd7e

File tree

2 files changed

+75
-35
lines changed

2 files changed

+75
-35
lines changed

lightning/src/ln/channel.rs

Lines changed: 74 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use bitcoin::secp256k1::{ecdsa::Signature, Secp256k1};
2626
use bitcoin::secp256k1::{PublicKey, SecretKey};
2727
use bitcoin::{secp256k1, sighash};
2828
#[cfg(splicing)]
29-
use bitcoin::{Sequence, TxIn, Witness};
29+
use bitcoin::{FeeRate, Sequence, TxIn, Witness};
3030

3131
use crate::chain::chaininterface::{
3232
fee_for_weight, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator,
@@ -5879,6 +5879,40 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos
58795879
cmp::min(channel_value_satoshis, cmp::max(q, dust_limit_satoshis))
58805880
}
58815881

5882+
#[cfg(splicing)]
5883+
fn check_splice_contribution_sufficient(
5884+
channel_balance: Amount, contribution: &SpliceContribution, is_initiator: bool,
5885+
funding_feerate: FeeRate,
5886+
) -> Result<Amount, ChannelError> {
5887+
let contribution_amount = contribution.value();
5888+
if contribution_amount < SignedAmount::ZERO {
5889+
let estimated_fee = Amount::from_sat(estimate_v2_funding_transaction_fee(
5890+
is_initiator,
5891+
1, // spends the previous funding output
5892+
Weight::from_wu(FUNDING_TRANSACTION_WITNESS_WEIGHT),
5893+
funding_feerate.to_sat_per_kwu() as u32,
5894+
));
5895+
5896+
if channel_balance > contribution_amount.unsigned_abs() + estimated_fee {
5897+
Ok(estimated_fee)
5898+
} else {
5899+
Err(ChannelError::Warn(format!(
5900+
"Available channel balance {} is lower than needed for splicing out {}, considering fees of {}",
5901+
channel_balance, contribution_amount.unsigned_abs(), estimated_fee,
5902+
)))
5903+
}
5904+
} else {
5905+
check_v2_funding_inputs_sufficient(
5906+
contribution_amount.to_sat(),
5907+
contribution.inputs(),
5908+
is_initiator,
5909+
true,
5910+
funding_feerate.to_sat_per_kwu() as u32,
5911+
)
5912+
.map(Amount::from_sat)
5913+
}
5914+
}
5915+
58825916
/// Estimate our part of the fee of the new funding transaction.
58835917
/// input_count: Number of contributed inputs.
58845918
/// witness_weight: The witness weight for contributed inputs.
@@ -10679,42 +10713,48 @@ where
1067910713
});
1068010714
}
1068110715

10682-
if our_funding_contribution < SignedAmount::ZERO {
10683-
// TODO(splicing): Check that channel balance does not go below the channel reserve
10684-
let post_channel_value = AddSigned::checked_add_signed(
10685-
self.funding.get_value_to_self_msat() / 1000,
10686-
our_funding_contribution.to_sat(),
10687-
);
10688-
// FIXME: Check that we can pay for the outputs from the channel value?
10689-
if post_channel_value.is_none() {
10690-
return Err(APIError::APIMisuseError {
10691-
err: format!(
10692-
"Channel {} cannot be spliced out; contribution exceeds the channel value: {}",
10693-
self.context.channel_id(),
10694-
our_funding_contribution,
10695-
),
10696-
});
10697-
}
10698-
} else {
10699-
// Note: post-splice channel value is not yet known at this point, counterparty contribution is not known
10700-
// (Cannot test for miminum required post-splice channel value)
10716+
// Note: post-splice channel value is not yet known at this point, counterparty contribution is not known
10717+
// (Cannot test for miminum required post-splice channel value)
1070110718

10702-
// Check that inputs are sufficient to cover our contribution.
10703-
let _fee = check_v2_funding_inputs_sufficient(
10704-
our_funding_contribution.to_sat(),
10705-
contribution.inputs(),
10706-
true,
10707-
true,
10708-
funding_feerate_per_kw,
10709-
)
10710-
.map_err(|err| APIError::APIMisuseError {
10719+
let channel_balance = Amount::from_sat(self.funding.get_value_to_self_msat() / 1000);
10720+
let fees = check_splice_contribution_sufficient(
10721+
channel_balance,
10722+
&contribution,
10723+
true, // is_initiator
10724+
FeeRate::from_sat_per_kwu(funding_feerate_per_kw as u64),
10725+
)
10726+
.map_err(|e| {
10727+
let splice_type = if our_funding_contribution < SignedAmount::ZERO {
10728+
"spliced out"
10729+
} else {
10730+
"spliced in"
10731+
};
10732+
APIError::APIMisuseError {
1071110733
err: format!(
10712-
"Insufficient inputs for splicing; channel ID {}, err {}",
10734+
"Channel {} cannot be {}; {}",
1071310735
self.context.channel_id(),
10714-
err,
10736+
splice_type,
10737+
e,
1071510738
),
10716-
})?;
10717-
}
10739+
}
10740+
})?;
10741+
10742+
// Fees for splice-out are paid from the channel balance whereas fees for splice-in are paid
10743+
// by the funding inputs.
10744+
let adjusted_funding_contribution = if our_funding_contribution < SignedAmount::ZERO {
10745+
let adjusted_funding_contribution = our_funding_contribution
10746+
+ fees.to_signed().expect("fees should never exceed splice-out value");
10747+
10748+
// TODO(splicing): Check that channel balance does not go below the channel reserve
10749+
let _post_channel_balance = AddSigned::checked_add_signed(
10750+
channel_balance.to_sat(),
10751+
adjusted_funding_contribution.to_sat(),
10752+
);
10753+
10754+
adjusted_funding_contribution
10755+
} else {
10756+
our_funding_contribution
10757+
};
1071810758

1071910759
for FundingTxInput { txin, prevtx, .. } in contribution.inputs().iter() {
1072010760
const MESSAGE_TEMPLATE: msgs::TxAddInput = msgs::TxAddInput {
@@ -10740,7 +10780,7 @@ where
1074010780
let (our_funding_inputs, our_funding_outputs, change_script) = contribution.into_tx_parts();
1074110781
let funding_negotiation_context = FundingNegotiationContext {
1074210782
is_initiator: true,
10743-
our_funding_contribution,
10783+
our_funding_contribution: adjusted_funding_contribution,
1074410784
funding_tx_locktime: LockTime::from_consensus(locktime),
1074510785
funding_feerate_sat_per_1000_weight: funding_feerate_per_kw,
1074610786
shared_funding_input: Some(prev_funding_input),

lightning/src/ln/splicing_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ fn test_v1_splice_in_negative_insufficient_inputs() {
341341
);
342342
match res {
343343
Err(APIError::APIMisuseError { err }) => {
344-
assert!(err.contains("Insufficient inputs for splicing"))
344+
assert!(err.contains("Need more inputs"))
345345
},
346346
_ => panic!("Wrong error {:?}", res.err().unwrap()),
347347
}

0 commit comments

Comments
 (0)