@@ -3050,6 +3050,35 @@ pub(crate) enum QuiescentAction {
30503050 DoNothing,
30513051}
30523052
3053+ pub(super) enum QuiescentError {
3054+ DoNothing,
3055+ DiscardFunding { inputs: Vec<bitcoin::OutPoint>, outputs: Vec<bitcoin::TxOut> },
3056+ FailSplice(SpliceFundingFailed),
3057+ }
3058+
3059+ impl From<QuiescentAction> for QuiescentError {
3060+ fn from(action: QuiescentAction) -> Self {
3061+ match action {
3062+ QuiescentAction::LegacySplice(_) => {
3063+ debug_assert!(false);
3064+ QuiescentError::DoNothing
3065+ },
3066+ QuiescentAction::Splice { contribution, .. } => {
3067+ let (contributed_inputs, contributed_outputs) =
3068+ contribution.into_contributed_inputs_and_outputs();
3069+ return QuiescentError::FailSplice(SpliceFundingFailed {
3070+ funding_txo: None,
3071+ channel_type: None,
3072+ contributed_inputs,
3073+ contributed_outputs,
3074+ });
3075+ },
3076+ #[cfg(any(test, fuzzing, feature = "_test_utils"))]
3077+ QuiescentAction::DoNothing => QuiescentError::DoNothing,
3078+ }
3079+ }
3080+ }
3081+
30533082pub(crate) enum StfuResponse {
30543083 Stfu(msgs::Stfu),
30553084 SpliceInit(msgs::SpliceInit),
@@ -6833,11 +6862,16 @@ impl FundingNegotiationContext {
68336862 (contributed_inputs, contributed_outputs)
68346863 }
68356864
6865+ fn contributed_inputs(&self) -> impl Iterator<Item = bitcoin::OutPoint> + '_ {
6866+ self.our_funding_inputs.iter().map(|input| input.utxo.outpoint)
6867+ }
6868+
6869+ fn contributed_outputs(&self) -> impl Iterator<Item = &TxOut> + '_ {
6870+ self.our_funding_outputs.iter()
6871+ }
6872+
68366873 fn to_contributed_inputs_and_outputs(&self) -> (Vec<bitcoin::OutPoint>, Vec<TxOut>) {
6837- let contributed_inputs =
6838- self.our_funding_inputs.iter().map(|input| input.utxo.outpoint).collect();
6839- let contributed_outputs = self.our_funding_outputs.clone();
6840- (contributed_inputs, contributed_outputs)
6874+ (self.contributed_inputs().collect(), self.contributed_outputs().cloned().collect())
68416875 }
68426876}
68436877
@@ -12210,9 +12244,58 @@ where
1221012244
1221112245 pub fn funding_contributed<L: Logger>(
1221212246 &mut self, contribution: FundingContribution, locktime: LockTime, logger: &L,
12213- ) -> Result<Option<msgs::Stfu>, SpliceFundingFailed > {
12247+ ) -> Result<Option<msgs::Stfu>, QuiescentError > {
1221412248 debug_assert!(contribution.is_splice());
1221512249
12250+ if let Some(QuiescentAction::Splice { contribution: existing, .. }) = &self.quiescent_action
12251+ {
12252+ return match contribution.into_unique_contributions(
12253+ existing.contributed_inputs(),
12254+ existing.contributed_outputs(),
12255+ ) {
12256+ None => Err(QuiescentError::DoNothing),
12257+ Some((inputs, outputs)) => Err(QuiescentError::DiscardFunding { inputs, outputs }),
12258+ };
12259+ }
12260+
12261+ let initiated_funding_negotiation = self
12262+ .pending_splice
12263+ .as_ref()
12264+ .and_then(|pending_splice| pending_splice.funding_negotiation.as_ref())
12265+ .filter(|funding_negotiation| funding_negotiation.is_initiator());
12266+
12267+ if let Some(funding_negotiation) = initiated_funding_negotiation {
12268+ let unique_contributions = match funding_negotiation {
12269+ FundingNegotiation::AwaitingAck { context, .. } => contribution
12270+ .into_unique_contributions(
12271+ context.contributed_inputs(),
12272+ context.contributed_outputs(),
12273+ ),
12274+ FundingNegotiation::ConstructingTransaction {
12275+ interactive_tx_constructor, ..
12276+ } => contribution.into_unique_contributions(
12277+ interactive_tx_constructor.contributed_inputs(),
12278+ interactive_tx_constructor.contributed_outputs(),
12279+ ),
12280+ FundingNegotiation::AwaitingSignatures { .. } => {
12281+ let session = self
12282+ .context
12283+ .interactive_tx_signing_session
12284+ .as_ref()
12285+ .expect("pending splice awaiting signatures");
12286+ contribution.into_unique_contributions(
12287+ session.contributed_inputs(),
12288+ session.contributed_outputs(),
12289+ )
12290+ },
12291+ };
12292+
12293+ return match unique_contributions {
12294+ None => Err(QuiescentError::DoNothing),
12295+ Some((inputs, outputs)) => Err(QuiescentError::DiscardFunding { inputs, outputs }),
12296+ };
12297+ }
12298+
1221612299 if let Err(e) = contribution.validate().and_then(|()| {
1221712300 // For splice-out, our_funding_contribution is adjusted to cover fees if there
1221812301 // aren't any inputs.
@@ -12224,37 +12307,15 @@ where
1222412307 let (contributed_inputs, contributed_outputs) =
1222512308 contribution.into_contributed_inputs_and_outputs();
1222612309
12227- return Err(SpliceFundingFailed {
12310+ return Err(QuiescentError::FailSplice( SpliceFundingFailed {
1222812311 funding_txo: None,
1222912312 channel_type: None,
1223012313 contributed_inputs,
1223112314 contributed_outputs,
12232- });
12315+ })) ;
1223312316 }
1223412317
12235- self.propose_quiescence(logger, QuiescentAction::Splice { contribution, locktime }).map_err(
12236- |action| {
12237- // FIXME: Any better way to do this?
12238- if let QuiescentAction::Splice { contribution, .. } = action {
12239- let (contributed_inputs, contributed_outputs) =
12240- contribution.into_contributed_inputs_and_outputs();
12241- SpliceFundingFailed {
12242- funding_txo: None,
12243- channel_type: None,
12244- contributed_inputs,
12245- contributed_outputs,
12246- }
12247- } else {
12248- debug_assert!(false);
12249- SpliceFundingFailed {
12250- funding_txo: None,
12251- channel_type: None,
12252- contributed_inputs: vec![],
12253- contributed_outputs: vec![],
12254- }
12255- }
12256- },
12257- )
12318+ self.propose_quiescence(logger, QuiescentAction::Splice { contribution, locktime })
1225812319 }
1225912320
1226012321 fn send_splice_init(&mut self, instructions: SpliceInstructions) -> msgs::SpliceInit {
@@ -13377,19 +13438,19 @@ where
1337713438 #[rustfmt::skip]
1337813439 pub fn propose_quiescence<L: Logger>(
1337913440 &mut self, logger: &L, action: QuiescentAction,
13380- ) -> Result<Option<msgs::Stfu>, QuiescentAction > {
13441+ ) -> Result<Option<msgs::Stfu>, QuiescentError > {
1338113442 log_debug!(logger, "Attempting to initiate quiescence");
1338213443
1338313444 if !self.context.is_usable() {
1338413445 log_debug!(logger, "Channel is not in a usable state to propose quiescence");
13385- return Err(action);
13446+ return Err(action.into() );
1338613447 }
1338713448 if self.quiescent_action.is_some() {
1338813449 log_debug!(
1338913450 logger,
1339013451 "Channel already has a pending quiescent action and cannot start another",
1339113452 );
13392- return Err(action);
13453+ return Err(action.into() );
1339313454 }
1339413455 // Since we don't have a pending quiescent action, we should never be in a state where we
1339513456 // sent `stfu` without already having become quiescent.
0 commit comments