@@ -60,7 +60,8 @@ use crate::ln::funding::{FundingTxInput, SpliceContribution};
6060use crate::ln::interactivetxs::{
6161 calculate_change_output_value, get_output_weight, AbortReason, HandleTxCompleteValue,
6262 InteractiveTxConstructor, InteractiveTxConstructorArgs, InteractiveTxMessageSend,
63- InteractiveTxSigningSession, SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT,
63+ InteractiveTxSigningSession, NegotiationError, SharedOwnedInput, SharedOwnedOutput,
64+ TX_COMMON_FIELDS_WEIGHT,
6465};
6566use crate::ln::msgs;
6667use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket};
@@ -1794,20 +1795,22 @@ where
17941795
17951796 let (interactive_tx_msg_send, negotiation_complete) = match tx_complete_action {
17961797 HandleTxCompleteValue::SendTxMessage(interactive_tx_msg_send) => {
1797- (Some(interactive_tx_msg_send), false )
1798+ (Some(interactive_tx_msg_send), None )
17981799 },
1799- HandleTxCompleteValue::SendTxComplete (
1800+ HandleTxCompleteValue::NegotiationComplete (
18001801 interactive_tx_msg_send,
1801- negotiation_complete,
1802- ) => (Some(interactive_tx_msg_send), negotiation_complete),
1803- HandleTxCompleteValue::NegotiationComplete => (None, true),
1802+ funding_outpoint,
1803+ ) => (interactive_tx_msg_send, Some(funding_outpoint)),
18041804 };
1805- if !negotiation_complete {
1805+
1806+ let funding_outpoint = if let Some(funding_outpoint) = negotiation_complete {
1807+ funding_outpoint
1808+ } else {
18061809 return Ok((interactive_tx_msg_send, None));
1807- }
1810+ };
18081811
18091812 let commitment_signed = self
1810- .funding_tx_constructed(logger)
1813+ .funding_tx_constructed(funding_outpoint, logger)
18111814 .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))?;
18121815 Ok((interactive_tx_msg_send, Some(commitment_signed)))
18131816 }
@@ -1890,13 +1893,13 @@ where
18901893 }
18911894
18921895 fn funding_tx_constructed<L: Deref>(
1893- &mut self, logger: &L,
1896+ &mut self, funding_outpoint: OutPoint, logger: &L,
18941897 ) -> Result<msgs::CommitmentSigned, AbortReason>
18951898 where
18961899 L::Target: Logger,
18971900 {
18981901 let logger = WithChannelContext::from(logger, self.context(), None);
1899- match &mut self.phase {
1902+ let (interactive_tx_constructor, commitment_signed) = match &mut self.phase {
19001903 ChannelPhase::UnfundedV2(chan) => {
19011904 debug_assert_eq!(
19021905 chan.context.channel_state,
@@ -1906,60 +1909,85 @@ where
19061909 ),
19071910 );
19081911
1909- let signing_session = chan
1912+ let interactive_tx_constructor = chan
19101913 .interactive_tx_constructor
19111914 .take()
1912- .expect("PendingV2Channel::interactive_tx_constructor should be set")
1913- .into_signing_session();
1915+ .expect("PendingV2Channel::interactive_tx_constructor should be set");
19141916 let commitment_signed = chan.context.funding_tx_constructed(
19151917 &mut chan.funding,
1916- signing_session ,
1918+ funding_outpoint ,
19171919 false,
19181920 chan.unfunded_context.transaction_number(),
19191921 &&logger,
19201922 )?;
19211923
1922- return Ok( commitment_signed);
1924+ (interactive_tx_constructor, commitment_signed)
19231925 },
19241926 ChannelPhase::Funded(chan) => {
19251927 if let Some(pending_splice) = chan.pending_splice.as_mut() {
1926- if let Some(funding_negotiation) = pending_splice.funding_negotiation.take() {
1927- if let FundingNegotiation::ConstructingTransaction {
1928- mut funding,
1929- interactive_tx_constructor,
1930- } = funding_negotiation
1931- {
1932- let signing_session = interactive_tx_constructor.into_signing_session();
1933- let commitment_signed = chan.context.funding_tx_constructed(
1928+ pending_splice
1929+ .funding_negotiation
1930+ .take()
1931+ .and_then(|funding_negotiation| {
1932+ if let FundingNegotiation::ConstructingTransaction {
1933+ funding,
1934+ interactive_tx_constructor,
1935+ } = funding_negotiation
1936+ {
1937+ Some((funding, interactive_tx_constructor))
1938+ } else {
1939+ // Replace the taken state for later error handling
1940+ pending_splice.funding_negotiation = Some(funding_negotiation);
1941+ None
1942+ }
1943+ })
1944+ .ok_or_else(|| {
1945+ AbortReason::InternalError(
1946+ "Got a tx_complete message in an invalid state",
1947+ )
1948+ })
1949+ .and_then(|(mut funding, interactive_tx_constructor)| {
1950+ match chan.context.funding_tx_constructed(
19341951 &mut funding,
1935- signing_session ,
1952+ funding_outpoint ,
19361953 true,
19371954 chan.holder_commitment_point.next_transaction_number(),
19381955 &&logger,
1939- )?;
1940-
1941- pending_splice.funding_negotiation =
1942- Some(FundingNegotiation::AwaitingSignatures { funding });
1943-
1944- return Ok(commitment_signed);
1945- } else {
1946- // Replace the taken state
1947- pending_splice.funding_negotiation = Some(funding_negotiation);
1948- }
1949- }
1956+ ) {
1957+ Ok(commitment_signed) => {
1958+ // Advance the state
1959+ pending_splice.funding_negotiation =
1960+ Some(FundingNegotiation::AwaitingSignatures { funding });
1961+ Ok((interactive_tx_constructor, commitment_signed))
1962+ },
1963+ Err(e) => {
1964+ // Restore the taken state for later error handling
1965+ pending_splice.funding_negotiation =
1966+ Some(FundingNegotiation::ConstructingTransaction {
1967+ funding,
1968+ interactive_tx_constructor,
1969+ });
1970+ Err(e)
1971+ },
1972+ }
1973+ })?
1974+ } else {
1975+ return Err(AbortReason::InternalError(
1976+ "Got a tx_complete message in an invalid state",
1977+ ));
19501978 }
1951-
1952- return Err(AbortReason::InternalError(
1953- "Got a tx_complete message in an invalid state",
1954- ));
19551979 },
19561980 _ => {
19571981 debug_assert!(false);
19581982 return Err(AbortReason::InternalError(
19591983 "Got a tx_complete message in an invalid phase",
19601984 ));
19611985 },
1962- }
1986+ };
1987+
1988+ let signing_session = interactive_tx_constructor.into_signing_session();
1989+ self.context_mut().interactive_tx_signing_session = Some(signing_session);
1990+ Ok(commitment_signed)
19631991 }
19641992
19651993 pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
@@ -6051,30 +6079,13 @@ where
60516079
60526080 #[rustfmt::skip]
60536081 fn funding_tx_constructed<L: Deref>(
6054- &mut self, funding: &mut FundingScope, signing_session: InteractiveTxSigningSession ,
6055- is_splice: bool, holder_commitment_transaction_number: u64, logger: &L
6082+ &mut self, funding: &mut FundingScope, funding_outpoint: OutPoint, is_splice: bool ,
6083+ holder_commitment_transaction_number: u64, logger: &L,
60566084 ) -> Result<msgs::CommitmentSigned, AbortReason>
60576085 where
60586086 L::Target: Logger
60596087 {
6060- let mut output_index = None;
6061- let expected_spk = funding.get_funding_redeemscript().to_p2wsh();
6062- for (idx, outp) in signing_session.unsigned_tx().tx().output.iter().enumerate() {
6063- if outp.script_pubkey == expected_spk && outp.value.to_sat() == funding.get_value_satoshis() {
6064- if output_index.is_some() {
6065- return Err(AbortReason::DuplicateFundingOutput);
6066- }
6067- output_index = Some(idx as u16);
6068- }
6069- }
6070- let outpoint = if let Some(output_index) = output_index {
6071- OutPoint { txid: signing_session.unsigned_tx().compute_txid(), index: output_index }
6072- } else {
6073- return Err(AbortReason::MissingFundingOutput);
6074- };
6075- funding
6076- .channel_transaction_parameters.funding_outpoint = Some(outpoint);
6077- self.interactive_tx_signing_session = Some(signing_session);
6088+ funding.channel_transaction_parameters.funding_outpoint = Some(funding_outpoint);
60786089
60796090 if is_splice {
60806091 debug_assert_eq!(
@@ -6091,7 +6102,6 @@ where
60916102 Some(commitment_signed) => commitment_signed,
60926103 // TODO(splicing): Support async signing
60936104 None => {
6094- funding.channel_transaction_parameters.funding_outpoint = None;
60956105 return Err(AbortReason::InternalError("Failed to compute commitment_signed signatures"));
60966106 },
60976107 };
@@ -6167,8 +6177,6 @@ where
61676177 SP::Target: SignerProvider,
61686178 L::Target: Logger,
61696179 {
6170- debug_assert!(self.interactive_tx_signing_session.is_some());
6171-
61726180 let signatures = self.get_initial_counterparty_commitment_signatures(funding, logger);
61736181 if let Some((signature, htlc_signatures)) = signatures {
61746182 log_info!(
@@ -6508,9 +6516,9 @@ impl FundingNegotiationContext {
65086516 /// Prepare and start interactive transaction negotiation.
65096517 /// If error occurs, it is caused by our side, not the counterparty.
65106518 fn into_interactive_tx_constructor<SP: Deref, ES: Deref>(
6511- self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
6519+ mut self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
65126520 entropy_source: &ES, holder_node_id: PublicKey,
6513- ) -> Result<InteractiveTxConstructor, AbortReason >
6521+ ) -> Result<InteractiveTxConstructor, NegotiationError >
65146522 where
65156523 SP::Target: SignerProvider,
65166524 ES::Target: EntropySource,
@@ -6536,25 +6544,32 @@ impl FundingNegotiationContext {
65366544
65376545 // Optionally add change output
65386546 let change_value_opt = if self.our_funding_contribution > SignedAmount::ZERO {
6539- calculate_change_output_value(
6547+ match calculate_change_output_value(
65406548 &self,
65416549 self.shared_funding_input.is_some(),
65426550 &shared_funding_output.script_pubkey,
65436551 context.holder_dust_limit_satoshis,
6544- )?
6552+ ) {
6553+ Ok(change_value_opt) => change_value_opt,
6554+ Err(reason) => {
6555+ return Err(self.into_negotiation_error(reason));
6556+ },
6557+ }
65456558 } else {
65466559 None
65476560 };
65486561
6549- let mut funding_outputs = self.our_funding_outputs;
6550-
65516562 if let Some(change_value) = change_value_opt {
65526563 let change_script = if let Some(script) = self.change_script {
65536564 script
65546565 } else {
6555- signer_provider
6556- .get_destination_script(context.channel_keys_id)
6557- .map_err(|_err| AbortReason::InternalError("Error getting change script"))?
6566+ match signer_provider.get_destination_script(context.channel_keys_id) {
6567+ Ok(script) => script,
6568+ Err(_) => {
6569+ let reason = AbortReason::InternalError("Error getting change script");
6570+ return Err(self.into_negotiation_error(reason));
6571+ },
6572+ }
65586573 };
65596574 let mut change_output =
65606575 TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
@@ -6565,7 +6580,7 @@ impl FundingNegotiationContext {
65656580 // Check dust limit again
65666581 if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
65676582 change_output.value = Amount::from_sat(change_value_decreased_with_fee);
6568- funding_outputs .push(change_output);
6583+ self.our_funding_outputs .push(change_output);
65696584 }
65706585 }
65716586
@@ -6583,10 +6598,19 @@ impl FundingNegotiationContext {
65836598 shared_funding_output,
65846599 funding.value_to_self_msat / 1000,
65856600 ),
6586- outputs_to_contribute: funding_outputs ,
6601+ outputs_to_contribute: self.our_funding_outputs ,
65876602 };
65886603 InteractiveTxConstructor::new(constructor_args)
65896604 }
6605+
6606+ fn into_negotiation_error(self, reason: AbortReason) -> NegotiationError {
6607+ let contributed_inputs =
6608+ self.our_funding_inputs.into_iter().map(|input| input.utxo.outpoint).collect();
6609+
6610+ let contributed_outputs = self.our_funding_outputs;
6611+
6612+ NegotiationError { reason, contributed_inputs, contributed_outputs }
6613+ }
65906614}
65916615
65926616// Holder designates channel data owned for the benefit of the user client.
@@ -13660,8 +13684,8 @@ where
1366013684 outputs_to_contribute: funding_negotiation_context.our_funding_outputs.clone(),
1366113685 }
1366213686 ).map_err(|err| {
13663- let reason = ClosureReason::ProcessingError { err: err.to_string() };
13664- ChannelError::Close((err.to_string(), reason))
13687+ let reason = ClosureReason::ProcessingError { err: err.reason. to_string() };
13688+ ChannelError::Close((err.reason. to_string(), reason))
1366513689 })?);
1366613690
1366713691 let unfunded_context = UnfundedChannelContext {
0 commit comments