@@ -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