@@ -6849,24 +6849,13 @@ impl FundingNegotiationContext {
68496849 }
68506850 }
68516851
6852- fn into_contributed_inputs_and_outputs(self) -> (Vec<bitcoin::OutPoint>, Vec<TxOut>) {
6853- let contributed_inputs =
6854- self.our_funding_inputs.into_iter().map(|input| input.utxo.outpoint).collect();
6855- let contributed_outputs = self.our_funding_outputs;
6856- (contributed_inputs, contributed_outputs)
6857- }
6858-
68596852 fn contributed_inputs(&self) -> impl Iterator<Item = bitcoin::OutPoint> + '_ {
68606853 self.our_funding_inputs.iter().map(|input| input.utxo.outpoint)
68616854 }
68626855
68636856 fn contributed_outputs(&self) -> impl Iterator<Item = &TxOut> + '_ {
68646857 self.our_funding_outputs.iter()
68656858 }
6866-
6867- fn to_contributed_inputs_and_outputs(&self) -> (Vec<bitcoin::OutPoint>, Vec<TxOut>) {
6868- (self.contributed_inputs().collect(), self.contributed_outputs().cloned().collect())
6869- }
68706859}
68716860
68726861// Holder designates channel data owned for the benefit of the user client.
@@ -7044,48 +7033,29 @@ impl SpliceFundingFailed {
70447033 }
70457034}
70467035
7047- macro_rules! maybe_create_splice_funding_failed {
7048- ($funded_channel: expr, $pending_splice: expr, $pending_splice_ref: expr, $get: ident, $contributed_inputs_and_outputs: ident) => {{
7049- $pending_splice
7050- .and_then(|pending_splice| pending_splice.funding_negotiation.$get())
7051- .and_then(|funding_negotiation| {
7052- let is_initiator = funding_negotiation.is_initiator();
7053-
7054- let (mut contributed_inputs, mut contributed_outputs) = match funding_negotiation {
7055- FundingNegotiation::AwaitingAck { context, .. } => {
7056- context.$contributed_inputs_and_outputs()
7057- },
7058- FundingNegotiation::ConstructingTransaction {
7059- interactive_tx_constructor,
7060- ..
7061- } => interactive_tx_constructor.$contributed_inputs_and_outputs(),
7062- FundingNegotiation::AwaitingSignatures { .. } => $funded_channel
7063- .context
7064- .interactive_tx_signing_session
7065- .$get()
7066- .expect("We have a pending splice awaiting signatures")
7067- .$contributed_inputs_and_outputs(),
7068- };
7069-
7070- if let Some(pending_splice) = $pending_splice_ref {
7071- for input in pending_splice.prior_contributed_inputs() {
7072- contributed_inputs.retain(|i| *i != input);
7073- }
7074- for output in pending_splice.prior_contributed_outputs() {
7075- contributed_outputs.retain(|o| o.script_pubkey != output.script_pubkey);
7076- }
7077- }
7078-
7079- if !is_initiator && contributed_inputs.is_empty() && contributed_outputs.is_empty()
7080- {
7081- return None;
7082- }
7083-
7084- let contribution =
7085- $pending_splice_ref.and_then(|ps| ps.contributions.last().cloned());
7086-
7087- Some(SpliceFundingFailed { contributed_inputs, contributed_outputs, contribution })
7088- })
7036+ macro_rules! splice_funding_failed_for {
7037+ ($self: expr, $is_initiator: expr, $contribution: expr,
7038+ $contributed_inputs: ident, $contributed_outputs: ident) => {{
7039+ let contribution = $contribution;
7040+ let existing_inputs =
7041+ $self.pending_splice.as_ref().into_iter().flat_map(|ps| ps.$contributed_inputs());
7042+ let existing_outputs =
7043+ $self.pending_splice.as_ref().into_iter().flat_map(|ps| ps.$contributed_outputs());
7044+ let filtered =
7045+ contribution.clone().into_unique_contributions(existing_inputs, existing_outputs);
7046+ match filtered {
7047+ None if !$is_initiator => None,
7048+ None => Some(SpliceFundingFailed {
7049+ contributed_inputs: vec![],
7050+ contributed_outputs: vec![],
7051+ contribution: Some(contribution),
7052+ }),
7053+ Some((contributed_inputs, contributed_outputs)) => Some(SpliceFundingFailed {
7054+ contributed_inputs,
7055+ contributed_outputs,
7056+ contribution: Some(contribution),
7057+ }),
7058+ }
70897059 }};
70907060}
70917061
@@ -7115,21 +7085,16 @@ where
71157085 /// Builds a [`SpliceFundingFailed`] from a contribution, filtering out inputs/outputs
71167086 /// that are still committed to a prior splice round.
71177087 fn splice_funding_failed_for(&self, contribution: FundingContribution) -> SpliceFundingFailed {
7118- let cloned_contribution = contribution.clone();
7119- let (mut inputs, mut outputs) = contribution.into_contributed_inputs_and_outputs();
7120- if let Some(ref pending_splice) = self.pending_splice {
7121- for input in pending_splice.contributed_inputs() {
7122- inputs.retain(|i| *i != input);
7123- }
7124- for output in pending_splice.contributed_outputs() {
7125- outputs.retain(|o| o.script_pubkey != output.script_pubkey);
7126- }
7127- }
7128- SpliceFundingFailed {
7129- contributed_inputs: inputs,
7130- contributed_outputs: outputs,
7131- contribution: Some(cloned_contribution),
7132- }
7088+ // The contribution was never pushed to `contributions`, so `contributed_inputs()` and
7089+ // `contributed_outputs()` return only prior rounds' entries for filtering.
7090+ splice_funding_failed_for!(
7091+ self,
7092+ true,
7093+ contribution,
7094+ contributed_inputs,
7095+ contributed_outputs
7096+ )
7097+ .expect("is_initiator is true so this always returns Some")
71337098 }
71347099
71357100 fn quiescent_action_into_error(&self, action: QuiescentAction) -> QuiescentError {
@@ -7273,21 +7238,23 @@ where
72737238 );
72747239 }
72757240
7276- let splice_funding_failed = maybe_create_splice_funding_failed!(
7277- self,
7278- self.pending_splice.as_mut(),
7279- self.pending_splice.as_ref(),
7280- take,
7281- into_contributed_inputs_and_outputs
7282- );
7283-
7284- // Pop the current round's contribution, if any (acceptors may not have one). This
7285- // must happen after `maybe_create_splice_funding_failed` for correct filtering.
7241+ // Take the funding negotiation and pop the current round's contribution, if any
7242+ // (acceptors may not have one).
72867243 let pending_splice = self
72877244 .pending_splice
72887245 .as_mut()
72897246 .expect("reset_pending_splice_state requires pending_splice");
7290- if let Some(contribution) = pending_splice.contributions.pop() {
7247+ debug_assert!(
7248+ pending_splice.funding_negotiation.is_some(),
7249+ "reset_pending_splice_state requires an active funding negotiation"
7250+ );
7251+ let is_initiator = pending_splice
7252+ .funding_negotiation
7253+ .take()
7254+ .map(|negotiation| negotiation.is_initiator())
7255+ .unwrap_or(false);
7256+ let contribution = pending_splice.contributions.pop();
7257+ if let Some(ref contribution) = contribution {
72917258 debug_assert!(
72927259 pending_splice
72937260 .last_funding_feerate_sat_per_1000_weight
@@ -7297,6 +7264,18 @@ where
72977264 );
72987265 }
72997266
7267+ // After pop, `contributed_inputs()` / `contributed_outputs()` return only prior
7268+ // rounds for filtering.
7269+ let splice_funding_failed = contribution.and_then(|contribution| {
7270+ splice_funding_failed_for!(
7271+ self,
7272+ is_initiator,
7273+ contribution,
7274+ contributed_inputs,
7275+ contributed_outputs
7276+ )
7277+ });
7278+
73007279 if self.pending_funding().is_empty() {
73017280 self.pending_splice.take();
73027281 }
@@ -7314,12 +7293,23 @@ where
73147293 return None;
73157294 }
73167295
7317- maybe_create_splice_funding_failed!(
7296+ let pending_splice = self.pending_splice.as_ref()?;
7297+ debug_assert!(
7298+ pending_splice.funding_negotiation.is_some(),
7299+ "maybe_splice_funding_failed requires an active funding negotiation"
7300+ );
7301+ let is_initiator = pending_splice
7302+ .funding_negotiation
7303+ .as_ref()
7304+ .map(|negotiation| negotiation.is_initiator())
7305+ .unwrap_or(false);
7306+ let contribution = pending_splice.contributions.last().cloned()?;
7307+ splice_funding_failed_for!(
73187308 self,
7319- self.pending_splice.as_ref() ,
7320- self.pending_splice.as_ref() ,
7321- as_ref ,
7322- to_contributed_inputs_and_outputs
7309+ is_initiator ,
7310+ contribution ,
7311+ prior_contributed_inputs ,
7312+ prior_contributed_outputs
73237313 )
73247314 }
73257315
0 commit comments