Skip to content

Commit e5cd5c8

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 91ad40e commit e5cd5c8

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
@@ -7056,48 +7056,29 @@ impl SpliceFundingFailed {
70567056
}
70577057
}
70587058

7059-
macro_rules! maybe_create_splice_funding_failed {
7060-
($funded_channel: expr, $pending_splice: expr, $pending_splice_ref: expr, $get: ident, $contributed_inputs_and_outputs: ident) => {{
7061-
$pending_splice
7062-
.and_then(|pending_splice| pending_splice.funding_negotiation.$get())
7063-
.and_then(|funding_negotiation| {
7064-
let is_initiator = funding_negotiation.is_initiator();
7065-
7066-
let (mut contributed_inputs, mut contributed_outputs) = match funding_negotiation {
7067-
FundingNegotiation::AwaitingAck { context, .. } => {
7068-
context.$contributed_inputs_and_outputs()
7069-
},
7070-
FundingNegotiation::ConstructingTransaction {
7071-
interactive_tx_constructor,
7072-
..
7073-
} => interactive_tx_constructor.$contributed_inputs_and_outputs(),
7074-
FundingNegotiation::AwaitingSignatures { .. } => $funded_channel
7075-
.context
7076-
.interactive_tx_signing_session
7077-
.$get()
7078-
.expect("We have a pending splice awaiting signatures")
7079-
.$contributed_inputs_and_outputs(),
7080-
};
7081-
7082-
if let Some(pending_splice) = $pending_splice_ref {
7083-
for input in pending_splice.prior_contributed_inputs() {
7084-
contributed_inputs.retain(|i| *i != input);
7085-
}
7086-
for output in pending_splice.prior_contributed_outputs() {
7087-
contributed_outputs.retain(|o| o.script_pubkey != output.script_pubkey);
7088-
}
7089-
}
7090-
7091-
if !is_initiator && contributed_inputs.is_empty() && contributed_outputs.is_empty()
7092-
{
7093-
return None;
7094-
}
7095-
7096-
let contribution =
7097-
$pending_splice_ref.and_then(|ps| ps.contributions.last().cloned());
7098-
7099-
Some(SpliceFundingFailed { contributed_inputs, contributed_outputs, contribution })
7100-
})
7059+
macro_rules! splice_funding_failed_for {
7060+
($self: expr, $is_initiator: expr, $contribution: expr,
7061+
$contributed_inputs: ident, $contributed_outputs: ident) => {{
7062+
let contribution = $contribution;
7063+
let existing_inputs =
7064+
$self.pending_splice.as_ref().into_iter().flat_map(|ps| ps.$contributed_inputs());
7065+
let existing_outputs =
7066+
$self.pending_splice.as_ref().into_iter().flat_map(|ps| ps.$contributed_outputs());
7067+
let filtered =
7068+
contribution.clone().into_unique_contributions(existing_inputs, existing_outputs);
7069+
match filtered {
7070+
None if !$is_initiator => None,
7071+
None => Some(SpliceFundingFailed {
7072+
contributed_inputs: vec![],
7073+
contributed_outputs: vec![],
7074+
contribution: Some(contribution),
7075+
}),
7076+
Some((contributed_inputs, contributed_outputs)) => Some(SpliceFundingFailed {
7077+
contributed_inputs,
7078+
contributed_outputs,
7079+
contribution: Some(contribution),
7080+
}),
7081+
}
71017082
}};
71027083
}
71037084

@@ -7127,21 +7108,16 @@ where
71277108
/// Builds a [`SpliceFundingFailed`] from a contribution, filtering out inputs/outputs
71287109
/// that are still committed to a prior splice round.
71297110
fn splice_funding_failed_for(&self, contribution: FundingContribution) -> SpliceFundingFailed {
7130-
let cloned_contribution = contribution.clone();
7131-
let (mut inputs, mut outputs) = contribution.into_contributed_inputs_and_outputs();
7132-
if let Some(ref pending_splice) = self.pending_splice {
7133-
for input in pending_splice.contributed_inputs() {
7134-
inputs.retain(|i| *i != input);
7135-
}
7136-
for output in pending_splice.contributed_outputs() {
7137-
outputs.retain(|o| o.script_pubkey != output.script_pubkey);
7138-
}
7139-
}
7140-
SpliceFundingFailed {
7141-
contributed_inputs: inputs,
7142-
contributed_outputs: outputs,
7143-
contribution: Some(cloned_contribution),
7144-
}
7111+
// The contribution was never pushed to `contributions`, so `contributed_inputs()` and
7112+
// `contributed_outputs()` return only prior rounds' entries for filtering.
7113+
splice_funding_failed_for!(
7114+
self,
7115+
true,
7116+
contribution,
7117+
contributed_inputs,
7118+
contributed_outputs
7119+
)
7120+
.expect("is_initiator is true so this always returns Some")
71457121
}
71467122

71477123
fn quiescent_action_into_error(&self, action: QuiescentAction) -> QuiescentError {
@@ -7285,21 +7261,19 @@ where
72857261
);
72867262
}
72877263

7288-
let splice_funding_failed = maybe_create_splice_funding_failed!(
7289-
self,
7290-
self.pending_splice.as_mut(),
7291-
self.pending_splice.as_ref(),
7292-
take,
7293-
into_contributed_inputs_and_outputs
7294-
);
7295-
7296-
// Pop the current round's contribution, if any (acceptors may not have one). This
7297-
// must happen after `maybe_create_splice_funding_failed` for correct filtering.
7264+
// Take the funding negotiation and pop the current round's contribution, if any
7265+
// (acceptors may not have one).
72987266
let pending_splice = self
72997267
.pending_splice
73007268
.as_mut()
73017269
.expect("reset_pending_splice_state requires pending_splice");
7302-
if let Some(contribution) = pending_splice.contributions.pop() {
7270+
let is_initiator = pending_splice
7271+
.funding_negotiation
7272+
.take()
7273+
.map(|negotiation| negotiation.is_initiator())
7274+
.unwrap_or(false);
7275+
let contribution = pending_splice.contributions.pop();
7276+
if let Some(ref contribution) = contribution {
73037277
debug_assert!(
73047278
pending_splice
73057279
.last_funding_feerate_sat_per_1000_weight
@@ -7309,6 +7283,18 @@ where
73097283
);
73107284
}
73117285

7286+
// After pop, `contributed_inputs()` / `contributed_outputs()` return only prior
7287+
// rounds for filtering.
7288+
let splice_funding_failed = contribution.and_then(|contribution| {
7289+
splice_funding_failed_for!(
7290+
self,
7291+
is_initiator,
7292+
contribution,
7293+
contributed_inputs,
7294+
contributed_outputs
7295+
)
7296+
});
7297+
73127298
if self.pending_funding().is_empty() {
73137299
self.pending_splice.take();
73147300
}
@@ -7326,12 +7312,19 @@ where
73267312
return None;
73277313
}
73287314

7329-
maybe_create_splice_funding_failed!(
7315+
let pending_splice = self.pending_splice.as_ref()?;
7316+
let is_initiator = pending_splice
7317+
.funding_negotiation
7318+
.as_ref()
7319+
.map(|negotiation| negotiation.is_initiator())
7320+
.unwrap_or(false);
7321+
let contribution = pending_splice.contributions.last().cloned()?;
7322+
splice_funding_failed_for!(
73307323
self,
7331-
self.pending_splice.as_ref(),
7332-
self.pending_splice.as_ref(),
7333-
as_ref,
7334-
to_contributed_inputs_and_outputs
7324+
is_initiator,
7325+
contribution,
7326+
prior_contributed_inputs,
7327+
prior_contributed_outputs
73357328
)
73367329
}
73377330

0 commit comments

Comments
 (0)