Skip to content

Commit 410324c

Browse files
jkczyzclaude
andcommitted
Derive SpliceFundingFailed inputs from FundingContribution
Replace the maybe_create_splice_funding_failed! macro and splice_funding_failed_for method with a unified splice_funding_failed_for! macro that derives contributed inputs and outputs from the FundingContribution rather than extracting them from the negotiation state. Callers pass ident parameters for which PendingSplice filtering methods to use: contributed_inputs/contributed_outputs when the current round's contribution has been popped or was never pushed, and prior_contributed_inputs/prior_contributed_outputs for the read-only persistence path where the contribution is cloned instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent fa558da commit 410324c

1 file changed

Lines changed: 66 additions & 73 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 66 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -7039,48 +7039,29 @@ pub struct SpliceFundingFailed {
70397039
pub contribution: Option<FundingContribution>,
70407040
}
70417041

7042-
macro_rules! maybe_create_splice_funding_failed {
7043-
($funded_channel: expr, $pending_splice: expr, $pending_splice_ref: expr, $get: ident, $contributed_inputs_and_outputs: ident) => {{
7044-
$pending_splice
7045-
.and_then(|pending_splice| pending_splice.funding_negotiation.$get())
7046-
.and_then(|funding_negotiation| {
7047-
let is_initiator = funding_negotiation.is_initiator();
7048-
7049-
let (mut contributed_inputs, mut contributed_outputs) = match funding_negotiation {
7050-
FundingNegotiation::AwaitingAck { context, .. } => {
7051-
context.$contributed_inputs_and_outputs()
7052-
},
7053-
FundingNegotiation::ConstructingTransaction {
7054-
interactive_tx_constructor,
7055-
..
7056-
} => interactive_tx_constructor.$contributed_inputs_and_outputs(),
7057-
FundingNegotiation::AwaitingSignatures { .. } => $funded_channel
7058-
.context
7059-
.interactive_tx_signing_session
7060-
.$get()
7061-
.expect("We have a pending splice awaiting signatures")
7062-
.$contributed_inputs_and_outputs(),
7063-
};
7064-
7065-
if let Some(pending_splice) = $pending_splice_ref {
7066-
for input in pending_splice.prior_contributed_inputs() {
7067-
contributed_inputs.retain(|i| *i != input);
7068-
}
7069-
for output in pending_splice.prior_contributed_outputs() {
7070-
contributed_outputs.retain(|o| o.script_pubkey != output.script_pubkey);
7071-
}
7072-
}
7073-
7074-
if !is_initiator && contributed_inputs.is_empty() && contributed_outputs.is_empty()
7075-
{
7076-
return None;
7077-
}
7078-
7079-
let contribution =
7080-
$pending_splice_ref.and_then(|ps| ps.contributions.last().cloned());
7081-
7082-
Some(SpliceFundingFailed { contributed_inputs, contributed_outputs, contribution })
7083-
})
7042+
macro_rules! splice_funding_failed_for {
7043+
($self: expr, $is_initiator: expr, $contribution: expr,
7044+
$contributed_inputs: ident, $contributed_outputs: ident) => {{
7045+
let contribution = $contribution;
7046+
let existing_inputs =
7047+
$self.pending_splice.as_ref().into_iter().flat_map(|ps| ps.$contributed_inputs());
7048+
let existing_outputs =
7049+
$self.pending_splice.as_ref().into_iter().flat_map(|ps| ps.$contributed_outputs());
7050+
let filtered =
7051+
contribution.clone().into_unique_contributions(existing_inputs, existing_outputs);
7052+
match filtered {
7053+
None if !$is_initiator => None,
7054+
None => Some(SpliceFundingFailed {
7055+
contributed_inputs: vec![],
7056+
contributed_outputs: vec![],
7057+
contribution: Some(contribution),
7058+
}),
7059+
Some((contributed_inputs, contributed_outputs)) => Some(SpliceFundingFailed {
7060+
contributed_inputs,
7061+
contributed_outputs,
7062+
contribution: Some(contribution),
7063+
}),
7064+
}
70847065
}};
70857066
}
70867067

@@ -7110,21 +7091,16 @@ where
71107091
/// Builds a [`SpliceFundingFailed`] from a contribution, filtering out inputs/outputs
71117092
/// that are still committed to a prior splice round.
71127093
fn splice_funding_failed_for(&self, contribution: FundingContribution) -> SpliceFundingFailed {
7113-
let cloned_contribution = contribution.clone();
7114-
let (mut inputs, mut outputs) = contribution.into_contributed_inputs_and_outputs();
7115-
if let Some(ref pending_splice) = self.pending_splice {
7116-
for input in pending_splice.contributed_inputs() {
7117-
inputs.retain(|i| *i != input);
7118-
}
7119-
for output in pending_splice.contributed_outputs() {
7120-
outputs.retain(|o| o.script_pubkey != output.script_pubkey);
7121-
}
7122-
}
7123-
SpliceFundingFailed {
7124-
contributed_inputs: inputs,
7125-
contributed_outputs: outputs,
7126-
contribution: Some(cloned_contribution),
7127-
}
7094+
// The contribution was never pushed to `contributions`, so `contributed_inputs()` and
7095+
// `contributed_outputs()` return only prior rounds' entries for filtering.
7096+
splice_funding_failed_for!(
7097+
self,
7098+
true,
7099+
contribution,
7100+
contributed_inputs,
7101+
contributed_outputs
7102+
)
7103+
.expect("is_initiator is true so this always returns Some")
71287104
}
71297105

71307106
fn quiescent_action_into_error(&self, action: QuiescentAction) -> QuiescentError {
@@ -7268,21 +7244,19 @@ where
72687244
);
72697245
}
72707246

7271-
let splice_funding_failed = maybe_create_splice_funding_failed!(
7272-
self,
7273-
self.pending_splice.as_mut(),
7274-
self.pending_splice.as_ref(),
7275-
take,
7276-
into_contributed_inputs_and_outputs
7277-
);
7278-
7279-
// Pop the current round's contribution, if any (acceptors may not have one). This
7280-
// must happen after `maybe_create_splice_funding_failed` for correct filtering.
7247+
// Take the funding negotiation and pop the current round's contribution, if any
7248+
// (acceptors may not have one).
72817249
let pending_splice = self
72827250
.pending_splice
72837251
.as_mut()
72847252
.expect("reset_pending_splice_state requires pending_splice");
7285-
if let Some(contribution) = pending_splice.contributions.pop() {
7253+
let is_initiator = pending_splice
7254+
.funding_negotiation
7255+
.take()
7256+
.map(|negotiation| negotiation.is_initiator())
7257+
.unwrap_or(false);
7258+
let contribution = pending_splice.contributions.pop();
7259+
if let Some(ref contribution) = contribution {
72867260
debug_assert!(
72877261
pending_splice
72887262
.last_funding_feerate_sat_per_1000_weight
@@ -7292,6 +7266,18 @@ where
72927266
);
72937267
}
72947268

7269+
// After pop, `contributed_inputs()` / `contributed_outputs()` return only prior
7270+
// rounds for filtering.
7271+
let splice_funding_failed = contribution.and_then(|contribution| {
7272+
splice_funding_failed_for!(
7273+
self,
7274+
is_initiator,
7275+
contribution,
7276+
contributed_inputs,
7277+
contributed_outputs
7278+
)
7279+
});
7280+
72957281
if self.pending_funding().is_empty() {
72967282
self.pending_splice.take();
72977283
}
@@ -7309,12 +7295,19 @@ where
73097295
return None;
73107296
}
73117297

7312-
maybe_create_splice_funding_failed!(
7298+
let pending_splice = self.pending_splice.as_ref()?;
7299+
let is_initiator = pending_splice
7300+
.funding_negotiation
7301+
.as_ref()
7302+
.map(|negotiation| negotiation.is_initiator())
7303+
.unwrap_or(false);
7304+
let contribution = pending_splice.contributions.last().cloned()?;
7305+
splice_funding_failed_for!(
73137306
self,
7314-
self.pending_splice.as_ref(),
7315-
self.pending_splice.as_ref(),
7316-
as_ref,
7317-
to_contributed_inputs_and_outputs
7307+
is_initiator,
7308+
contribution,
7309+
prior_contributed_inputs,
7310+
prior_contributed_outputs
73187311
)
73197312
}
73207313

0 commit comments

Comments
 (0)