Skip to content

Commit 32ba447

Browse files
committed
Improve error handling, persistence; misc review changes
1 parent 0565480 commit 32ba447

File tree

4 files changed

+136
-134
lines changed

4 files changed

+136
-134
lines changed

lightning/src/ln/channel.rs

Lines changed: 72 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -4590,38 +4590,6 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
45904590
self.channel_transaction_parameters = channel_transaction_parameters;
45914591
self.get_initial_counterparty_commitment_signature(funding, logger)
45924592
}
4593-
4594-
/// Get the splice message that can be sent during splice initiation.
4595-
#[cfg(splicing)]
4596-
pub fn get_splice_init(&self, our_funding_contribution_satoshis: i64,
4597-
funding_feerate_perkw: u32, locktime: u32,
4598-
) -> msgs::SpliceInit {
4599-
// Reuse the existing funding pubkey, in spite of the channel value changing
4600-
// (though at this point we don't know the new value yet, due tue the optional counterparty contribution)
4601-
// Note that channel_keys_id is supposed NOT to change
4602-
let funding_pubkey = self.get_holder_pubkeys().funding_pubkey.clone();
4603-
msgs::SpliceInit {
4604-
channel_id: self.channel_id,
4605-
funding_contribution_satoshis: our_funding_contribution_satoshis,
4606-
funding_feerate_perkw,
4607-
locktime,
4608-
funding_pubkey,
4609-
require_confirmed_inputs: None,
4610-
}
4611-
}
4612-
4613-
/// Get the splice_ack message that can be sent in response to splice initiation.
4614-
#[cfg(splicing)]
4615-
pub fn get_splice_ack(&self, our_funding_contribution_satoshis: i64) -> msgs::SpliceAck {
4616-
// Reuse the existing funding pubkey, in spite of the channel value changing
4617-
let funding_pubkey = self.get_holder_pubkeys().funding_pubkey;
4618-
msgs::SpliceAck {
4619-
channel_id: self.channel_id,
4620-
funding_contribution_satoshis: our_funding_contribution_satoshis,
4621-
funding_pubkey,
4622-
require_confirmed_inputs: None,
4623-
}
4624-
}
46254593
}
46264594

46274595
// Internal utility functions for channels
@@ -8364,61 +8332,72 @@ impl<SP: Deref> FundedChannel<SP> where
83648332
}
83658333
}
83668334

8367-
/// Initiate splicing
8335+
/// Initiate splicing.
8336+
/// - our_funding_inputs: the inputs we contribute to the new funding transaction.
8337+
/// Includes the witness weight for this input (e.g. P2WPKH_WITNESS_WEIGHT=109 for typical P2WPKH inputs).
83688338
#[cfg(splicing)]
83698339
pub fn splice_channel(&mut self, our_funding_contribution_satoshis: i64,
8370-
our_funding_inputs: Vec<(TxIn, Transaction, Weight)>, funding_feerate_perkw: u32, locktime: u32,
8371-
) -> Result<msgs::SpliceInit, ChannelError> {
8340+
_our_funding_inputs: &Vec<(TxIn, Transaction, Weight)>,
8341+
funding_feerate_per_kw: u32, locktime: u32,
8342+
) -> Result<msgs::SpliceInit, APIError> {
83728343
// Check if a splice has been initiated already.
8373-
// Note: this could be handled more nicely, and support multiple outstanding splice's, the incoming splice_ack matters anyways.
8344+
// Note: only a single outstanding splice is supported (per spec)
83748345
if let Some(splice_info) = &self.pending_splice_pre {
8375-
return Err(ChannelError::Warn(format!(
8376-
"Channel has already a splice pending, contribution {}", splice_info.our_funding_contribution
8377-
)));
8346+
return Err(APIError::APIMisuseError { err: format!(
8347+
"Channel {} cannot be spliced, as it has already a splice pending (contribution {})",
8348+
self.context.channel_id(), splice_info.our_funding_contribution
8349+
)});
83788350
}
83798351

8380-
if !matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
8381-
return Err(ChannelError::Warn(format!("Cannot initiate splicing, as channel is not Ready")));
8352+
if !self.context.is_live() {
8353+
return Err(APIError::APIMisuseError { err: format!(
8354+
"Channel {} cannot be spliced, as channel is not live",
8355+
self.context.channel_id()
8356+
)});
83828357
}
83838358

8384-
let pre_channel_value = self.funding.get_value_satoshis();
8385-
// Sanity check: capacity cannot decrease below 0
8386-
if (pre_channel_value as i64).saturating_add(our_funding_contribution_satoshis) < 0 {
8387-
return Err(ChannelError::Warn(format!(
8388-
"Post-splicing channel value cannot be negative. It was {} + {}",
8389-
pre_channel_value, our_funding_contribution_satoshis
8390-
)));
8391-
}
8359+
// TODO(splicing): check for quiescence
83928360

83938361
if our_funding_contribution_satoshis < 0 {
8394-
return Err(ChannelError::Warn(format!(
8395-
"TODO(splicing): Splice-out not supported, only splice in, contribution {}",
8396-
our_funding_contribution_satoshis,
8397-
)));
8362+
return Err(APIError::APIMisuseError { err: format!(
8363+
"TODO(splicing): Splice-out not supported, only splice in; channel ID {}, contribution {}",
8364+
self.context.channel_id(), our_funding_contribution_satoshis,
8365+
)});
83988366
}
83998367

8400-
// Note: post-splice channel value is not yet known at this point, counterpary contribution is not known
8368+
// TODO(splicing): Once splice-out is supported, check that channel balance does not go below 0
8369+
// (or below channel reserve)
8370+
8371+
// Note: post-splice channel value is not yet known at this point, counterparty contribution is not known
84018372
// (Cannot test for miminum required post-splice channel value)
84028373

8403-
// Check that inputs are sufficient to cover our contribution
8404-
let sum_input: i64 = our_funding_inputs.into_iter().map(
8405-
|(txin, tx, _)| tx.output.get(txin.previous_output.vout as usize).map(|tx| tx.value.to_sat() as i64).unwrap_or(0)
8406-
).sum();
8407-
if sum_input < our_funding_contribution_satoshis {
8408-
return Err(ChannelError::Warn(format!(
8409-
"Provided inputs are insufficient for our contribution, {} {}",
8410-
sum_input, our_funding_contribution_satoshis,
8411-
)));
8412-
}
84138374

84148375
self.pending_splice_pre = Some(PendingSplice {
84158376
our_funding_contribution: our_funding_contribution_satoshis,
84168377
});
84178378

8418-
let msg = self.context.get_splice_init(our_funding_contribution_satoshis, funding_feerate_perkw, locktime);
8379+
let msg = self.get_splice_init(our_funding_contribution_satoshis, funding_feerate_per_kw, locktime);
84198380
Ok(msg)
84208381
}
84218382

8383+
/// Get the splice message that can be sent during splice initiation.
8384+
#[cfg(splicing)]
8385+
pub fn get_splice_init(&self, our_funding_contribution_satoshis: i64,
8386+
funding_feerate_per_kw: u32, locktime: u32,
8387+
) -> msgs::SpliceInit {
8388+
// TODO(splicing): The exisiting pubkey is reused, but a new one should be generated. See #3542.
8389+
// Note that channel_keys_id is supposed NOT to change
8390+
let funding_pubkey = self.context.get_holder_pubkeys().funding_pubkey.clone();
8391+
msgs::SpliceInit {
8392+
channel_id: self.context.channel_id,
8393+
funding_contribution_satoshis: our_funding_contribution_satoshis,
8394+
funding_feerate_per_kw,
8395+
locktime,
8396+
funding_pubkey,
8397+
require_confirmed_inputs: None,
8398+
}
8399+
}
8400+
84228401
/// Handle splice_init
84238402
#[cfg(splicing)]
84248403
pub fn splice_init(&mut self, msg: &msgs::SpliceInit) -> Result<msgs::SpliceAck, ChannelError> {
@@ -8434,20 +8413,11 @@ impl<SP: Deref> FundedChannel<SP> where
84348413
)));
84358414
}
84368415

8437-
if !matches!(self.context.channel_state, ChannelState::ChannelReady(_)) {
8438-
return Err(ChannelError::Warn(format!("Splicing requested on a channel that is not Ready")));
8439-
}
8440-
8441-
let pre_channel_value = self.funding.get_value_satoshis();
8442-
// Sanity check: capacity cannot decrease below 0
8443-
if (pre_channel_value as i64)
8444-
.saturating_add(their_funding_contribution_satoshis)
8445-
.saturating_add(our_funding_contribution_satoshis) < 0
8446-
{
8447-
return Err(ChannelError::Warn(format!(
8448-
"Post-splicing channel value cannot be negative. It was {} + {} + {}",
8449-
pre_channel_value, their_funding_contribution_satoshis, our_funding_contribution_satoshis,
8450-
)));
8416+
// - If it has received shutdown:
8417+
// MUST send a warning and close the connection or send an error
8418+
// and fail the channel.
8419+
if !self.context.is_live() {
8420+
return Err(ChannelError::Warn(format!("Splicing requested on a channel that is not live")));
84518421
}
84528422

84538423
if their_funding_contribution_satoshis.saturating_add(our_funding_contribution_satoshis) < 0 {
@@ -8457,20 +8427,35 @@ impl<SP: Deref> FundedChannel<SP> where
84578427
)));
84588428
}
84598429

8460-
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, their_funding_contribution_satoshis, our_funding_contribution_satoshis);
8461-
let post_balance = PendingSplice::add_checked(self.funding.value_to_self_msat, our_funding_contribution_satoshis);
8462-
// Early check for reserve requirement, assuming maximum balance of full channel value
8463-
// This will also be checked later at tx_complete
8464-
let _res = self.context.check_balance_meets_reserve_requirements(post_balance, post_channel_value)?;
8430+
// TODO(splicing): Once splice acceptor can contribute, check that inputs are sufficient,
8431+
// similarly to the check in `splice_channel`.
8432+
8433+
// Note on channel reserve requirement pre-check: as the splice acceptor does not contribute,
8434+
// it can't go below reserve, therefore no pre-check is done here.
8435+
// TODO(splicing): Once splice acceptor can contribute, add reserve pre-check, similar to the one in `splice_ack`.
84658436

84668437
// TODO(splicing): Store msg.funding_pubkey
84678438
// TODO(splicing): Apply start of splice (splice_start)
84688439

8469-
let splice_ack_msg = self.context.get_splice_ack(our_funding_contribution_satoshis);
8440+
let splice_ack_msg = self.get_splice_ack(our_funding_contribution_satoshis);
84708441
// TODO(splicing): start interactive funding negotiation
84718442
Ok(splice_ack_msg)
84728443
}
84738444

8445+
/// Get the splice_ack message that can be sent in response to splice initiation.
8446+
#[cfg(splicing)]
8447+
pub fn get_splice_ack(&self, our_funding_contribution_satoshis: i64) -> msgs::SpliceAck {
8448+
// TODO(splicing): The exisiting pubkey is reused, but a new one should be generated. See #3542.
8449+
// Note that channel_keys_id is supposed NOT to change
8450+
let funding_pubkey = self.context.get_holder_pubkeys().funding_pubkey;
8451+
msgs::SpliceAck {
8452+
channel_id: self.context.channel_id,
8453+
funding_contribution_satoshis: our_funding_contribution_satoshis,
8454+
funding_pubkey,
8455+
require_confirmed_inputs: None,
8456+
}
8457+
}
8458+
84748459
/// Handle splice_ack
84758460
#[cfg(splicing)]
84768461
pub fn splice_ack(&mut self, msg: &msgs::SpliceAck) -> Result<(), ChannelError> {
@@ -12890,15 +12875,15 @@ mod tests {
1289012875
);
1289112876
}
1289212877

12893-
#[cfg(all(test, splicing))]
12878+
#[cfg(splicing)]
1289412879
fn get_pre_and_post(pre_channel_value: u64, our_funding_contribution: i64, their_funding_contribution: i64) -> (u64, u64) {
1289512880
use crate::ln::channel::PendingSplice;
1289612881

1289712882
let post_channel_value = PendingSplice::compute_post_value(pre_channel_value, our_funding_contribution, their_funding_contribution);
1289812883
(pre_channel_value, post_channel_value)
1289912884
}
1290012885

12901-
#[cfg(all(test, splicing))]
12886+
#[cfg(splicing)]
1290212887
#[test]
1290312888
fn test_splice_compute_post_value() {
1290412889
{

0 commit comments

Comments
 (0)