Skip to content

Commit 1830a7a

Browse files
committed
f - check that splice-out outputs can be paid for by channel balance
1 parent beff815 commit 1830a7a

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};
29+
use bitcoin::{FeeRate, Sequence, TxIn};
3030

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

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

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

10694-
// Check that inputs are sufficient to cover our contribution.
10695-
let _fee = check_v2_funding_inputs_sufficient(
10696-
our_funding_contribution.to_sat(),
10697-
contribution.inputs(),
10698-
true,
10699-
true,
10700-
funding_feerate_per_kw,
10701-
)
10702-
.map_err(|err| APIError::APIMisuseError {
10711+
let channel_balance = Amount::from_sat(self.funding.get_value_to_self_msat() / 1000);
10712+
let fees = check_splice_contribution_sufficient(
10713+
channel_balance,
10714+
&contribution,
10715+
true, // is_initiator
10716+
FeeRate::from_sat_per_kwu(funding_feerate_per_kw as u64),
10717+
)
10718+
.map_err(|e| {
10719+
let splice_type = if our_funding_contribution < SignedAmount::ZERO {
10720+
"spliced out"
10721+
} else {
10722+
"spliced in"
10723+
};
10724+
APIError::APIMisuseError {
1070310725
err: format!(
10704-
"Insufficient inputs for splicing; channel ID {}, err {}",
10726+
"Channel {} cannot be {}; {}",
1070510727
self.context.channel_id(),
10706-
err,
10728+
splice_type,
10729+
e,
1070710730
),
10708-
})?;
10709-
}
10731+
}
10732+
})?;
10733+
10734+
// Fees for splice-out are paid from the channel balance whereas fees for splice-in are paid
10735+
// by the funding inputs.
10736+
let adjusted_funding_contribution = if our_funding_contribution < SignedAmount::ZERO {
10737+
let adjusted_funding_contribution = our_funding_contribution
10738+
+ fees.to_signed().expect("fees should never exceed splice-out value");
10739+
10740+
// TODO(splicing): Check that channel balance does not go below the channel reserve
10741+
let _post_channel_balance = AddSigned::checked_add_signed(
10742+
channel_balance.to_sat(),
10743+
adjusted_funding_contribution.to_sat(),
10744+
);
10745+
10746+
adjusted_funding_contribution
10747+
} else {
10748+
our_funding_contribution
10749+
};
1071010750

1071110751
for FundingTxInput { txin, prevtx, .. } in contribution.inputs().iter() {
1071210752
const MESSAGE_TEMPLATE: msgs::TxAddInput = msgs::TxAddInput {
@@ -10732,7 +10772,7 @@ where
1073210772
let (our_funding_inputs, our_funding_outputs, change_script) = contribution.into_tx_parts();
1073310773
let funding_negotiation_context = FundingNegotiationContext {
1073410774
is_initiator: true,
10735-
our_funding_contribution,
10775+
our_funding_contribution: adjusted_funding_contribution,
1073610776
funding_tx_locktime: LockTime::from_consensus(locktime),
1073710777
funding_feerate_sat_per_1000_weight: funding_feerate_per_kw,
1073810778
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
@@ -319,7 +319,7 @@ fn test_v1_splice_in_negative_insufficient_inputs() {
319319
);
320320
match res {
321321
Err(APIError::APIMisuseError { err }) => {
322-
assert!(err.contains("Insufficient inputs for splicing"))
322+
assert!(err.contains("Need more inputs"))
323323
},
324324
_ => panic!("Wrong error {:?}", res.err().unwrap()),
325325
}

0 commit comments

Comments
 (0)