Skip to content

Commit dc0609d

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 bc7490d commit dc0609d

1 file changed

Lines changed: 74 additions & 84 deletions

File tree

lightning/src/ln/channel.rs

Lines changed: 74 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -6861,24 +6861,13 @@ impl FundingNegotiationContext {
68616861
}
68626862
}
68636863

6864-
fn into_contributed_inputs_and_outputs(self) -> (Vec<bitcoin::OutPoint>, Vec<TxOut>) {
6865-
let contributed_inputs =
6866-
self.our_funding_inputs.into_iter().map(|input| input.utxo.outpoint).collect();
6867-
let contributed_outputs = self.our_funding_outputs;
6868-
(contributed_inputs, contributed_outputs)
6869-
}
6870-
68716864
fn contributed_inputs(&self) -> impl Iterator<Item = bitcoin::OutPoint> + '_ {
68726865
self.our_funding_inputs.iter().map(|input| input.utxo.outpoint)
68736866
}
68746867

68756868
fn contributed_outputs(&self) -> impl Iterator<Item = &TxOut> + '_ {
68766869
self.our_funding_outputs.iter()
68776870
}
6878-
6879-
fn to_contributed_inputs_and_outputs(&self) -> (Vec<bitcoin::OutPoint>, Vec<TxOut>) {
6880-
(self.contributed_inputs().collect(), self.contributed_outputs().cloned().collect())
6881-
}
68826871
}
68836872

68846873
// Holder designates channel data owned for the benefit of the user client.
@@ -7056,48 +7045,29 @@ impl SpliceFundingFailed {
70567045
}
70577046
}
70587047

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-
})
7048+
macro_rules! splice_funding_failed_for {
7049+
($self: expr, $is_initiator: expr, $contribution: expr,
7050+
$contributed_inputs: ident, $contributed_outputs: ident) => {{
7051+
let contribution = $contribution;
7052+
let existing_inputs =
7053+
$self.pending_splice.as_ref().into_iter().flat_map(|ps| ps.$contributed_inputs());
7054+
let existing_outputs =
7055+
$self.pending_splice.as_ref().into_iter().flat_map(|ps| ps.$contributed_outputs());
7056+
let filtered =
7057+
contribution.clone().into_unique_contributions(existing_inputs, existing_outputs);
7058+
match filtered {
7059+
None if !$is_initiator => None,
7060+
None => Some(SpliceFundingFailed {
7061+
contributed_inputs: vec![],
7062+
contributed_outputs: vec![],
7063+
contribution: Some(contribution),
7064+
}),
7065+
Some((contributed_inputs, contributed_outputs)) => Some(SpliceFundingFailed {
7066+
contributed_inputs,
7067+
contributed_outputs,
7068+
contribution: Some(contribution),
7069+
}),
7070+
}
71017071
}};
71027072
}
71037073

@@ -7127,21 +7097,16 @@ where
71277097
/// Builds a [`SpliceFundingFailed`] from a contribution, filtering out inputs/outputs
71287098
/// that are still committed to a prior splice round.
71297099
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-
}
7100+
// The contribution was never pushed to `contributions`, so `contributed_inputs()` and
7101+
// `contributed_outputs()` return only prior rounds' entries for filtering.
7102+
splice_funding_failed_for!(
7103+
self,
7104+
true,
7105+
contribution,
7106+
contributed_inputs,
7107+
contributed_outputs
7108+
)
7109+
.expect("is_initiator is true so this always returns Some")
71457110
}
71467111

71477112
fn quiescent_action_into_error(&self, action: QuiescentAction) -> QuiescentError {
@@ -7285,21 +7250,23 @@ where
72857250
);
72867251
}
72877252

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.
7253+
// Take the funding negotiation and pop the current round's contribution, if any
7254+
// (acceptors may not have one).
72987255
let pending_splice = self
72997256
.pending_splice
73007257
.as_mut()
73017258
.expect("reset_pending_splice_state requires pending_splice");
7302-
if let Some(contribution) = pending_splice.contributions.pop() {
7259+
debug_assert!(
7260+
pending_splice.funding_negotiation.is_some(),
7261+
"reset_pending_splice_state requires an active funding negotiation"
7262+
);
7263+
let is_initiator = pending_splice
7264+
.funding_negotiation
7265+
.take()
7266+
.map(|negotiation| negotiation.is_initiator())
7267+
.unwrap_or(false);
7268+
let contribution = pending_splice.contributions.pop();
7269+
if let Some(ref contribution) = contribution {
73037270
debug_assert!(
73047271
pending_splice
73057272
.last_funding_feerate_sat_per_1000_weight
@@ -7309,6 +7276,18 @@ where
73097276
);
73107277
}
73117278

7279+
// After pop, `contributed_inputs()` / `contributed_outputs()` return only prior
7280+
// rounds for filtering.
7281+
let splice_funding_failed = contribution.and_then(|contribution| {
7282+
splice_funding_failed_for!(
7283+
self,
7284+
is_initiator,
7285+
contribution,
7286+
contributed_inputs,
7287+
contributed_outputs
7288+
)
7289+
});
7290+
73127291
if self.pending_funding().is_empty() {
73137292
self.pending_splice.take();
73147293
}
@@ -7326,12 +7305,23 @@ where
73267305
return None;
73277306
}
73287307

7329-
maybe_create_splice_funding_failed!(
7308+
let pending_splice = self.pending_splice.as_ref()?;
7309+
debug_assert!(
7310+
pending_splice.funding_negotiation.is_some(),
7311+
"maybe_splice_funding_failed requires an active funding negotiation"
7312+
);
7313+
let is_initiator = pending_splice
7314+
.funding_negotiation
7315+
.as_ref()
7316+
.map(|negotiation| negotiation.is_initiator())
7317+
.unwrap_or(false);
7318+
let contribution = pending_splice.contributions.last().cloned()?;
7319+
splice_funding_failed_for!(
73307320
self,
7331-
self.pending_splice.as_ref(),
7332-
self.pending_splice.as_ref(),
7333-
as_ref,
7334-
to_contributed_inputs_and_outputs
7321+
is_initiator,
7322+
contribution,
7323+
prior_contributed_inputs,
7324+
prior_contributed_outputs
73357325
)
73367326
}
73377327

0 commit comments

Comments
 (0)