@@ -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};
@@ -1787,20 +1788,22 @@ where
17871788
17881789 let (interactive_tx_msg_send, negotiation_complete) = match tx_complete_action {
17891790 HandleTxCompleteValue::SendTxMessage(interactive_tx_msg_send) => {
1790- (Some(interactive_tx_msg_send), false )
1791+ (Some(interactive_tx_msg_send), None )
17911792 },
1792- HandleTxCompleteValue::SendTxComplete (
1793+ HandleTxCompleteValue::NegotiationComplete (
17931794 interactive_tx_msg_send,
1794- negotiation_complete,
1795- ) => (Some(interactive_tx_msg_send), negotiation_complete),
1796- HandleTxCompleteValue::NegotiationComplete => (None, true),
1795+ funding_outpoint,
1796+ ) => (interactive_tx_msg_send, Some(funding_outpoint)),
17971797 };
1798- if !negotiation_complete {
1798+
1799+ let funding_outpoint = if let Some(funding_outpoint) = negotiation_complete {
1800+ funding_outpoint
1801+ } else {
17991802 return Ok((interactive_tx_msg_send, None));
1800- }
1803+ };
18011804
18021805 let commitment_signed = self
1803- .funding_tx_constructed(logger)
1806+ .funding_tx_constructed(funding_outpoint, logger)
18041807 .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))?;
18051808 Ok((interactive_tx_msg_send, Some(commitment_signed)))
18061809 }
@@ -1891,13 +1894,13 @@ where
18911894 }
18921895
18931896 fn funding_tx_constructed<L: Deref>(
1894- &mut self, logger: &L,
1897+ &mut self, funding_outpoint: OutPoint, logger: &L,
18951898 ) -> Result<msgs::CommitmentSigned, AbortReason>
18961899 where
18971900 L::Target: Logger,
18981901 {
18991902 let logger = WithChannelContext::from(logger, self.context(), None);
1900- match &mut self.phase {
1903+ let (interactive_tx_constructor, commitment_signed) = match &mut self.phase {
19011904 ChannelPhase::UnfundedV2(chan) => {
19021905 debug_assert_eq!(
19031906 chan.context.channel_state,
@@ -1907,60 +1910,85 @@ where
19071910 ),
19081911 );
19091912
1910- let signing_session = chan
1913+ let interactive_tx_constructor = chan
19111914 .interactive_tx_constructor
19121915 .take()
1913- .expect("PendingV2Channel::interactive_tx_constructor should be set")
1914- .into_signing_session();
1916+ .expect("PendingV2Channel::interactive_tx_constructor should be set");
19151917 let commitment_signed = chan.context.funding_tx_constructed(
19161918 &mut chan.funding,
1917- signing_session ,
1919+ funding_outpoint ,
19181920 false,
19191921 chan.unfunded_context.transaction_number(),
19201922 &&logger,
19211923 )?;
19221924
1923- return Ok( commitment_signed);
1925+ (interactive_tx_constructor, commitment_signed)
19241926 },
19251927 ChannelPhase::Funded(chan) => {
19261928 if let Some(pending_splice) = chan.pending_splice.as_mut() {
1927- if let Some(funding_negotiation) = pending_splice.funding_negotiation.take() {
1928- if let FundingNegotiation::ConstructingTransaction {
1929- mut funding,
1930- interactive_tx_constructor,
1931- } = funding_negotiation
1932- {
1933- let signing_session = interactive_tx_constructor.into_signing_session();
1934- let commitment_signed = chan.context.funding_tx_constructed(
1929+ pending_splice
1930+ .funding_negotiation
1931+ .take()
1932+ .and_then(|funding_negotiation| {
1933+ if let FundingNegotiation::ConstructingTransaction {
1934+ funding,
1935+ interactive_tx_constructor,
1936+ } = funding_negotiation
1937+ {
1938+ Some((funding, interactive_tx_constructor))
1939+ } else {
1940+ // Replace the taken state for later error handling
1941+ pending_splice.funding_negotiation = Some(funding_negotiation);
1942+ None
1943+ }
1944+ })
1945+ .ok_or_else(|| {
1946+ AbortReason::InternalError(
1947+ "Got a tx_complete message in an invalid state",
1948+ )
1949+ })
1950+ .and_then(|(mut funding, interactive_tx_constructor)| {
1951+ match chan.context.funding_tx_constructed(
19351952 &mut funding,
1936- signing_session ,
1953+ funding_outpoint ,
19371954 true,
19381955 chan.holder_commitment_point.next_transaction_number(),
19391956 &&logger,
1940- )?;
1941-
1942- pending_splice.funding_negotiation =
1943- Some(FundingNegotiation::AwaitingSignatures { funding });
1944-
1945- return Ok(commitment_signed);
1946- } else {
1947- // Replace the taken state
1948- pending_splice.funding_negotiation = Some(funding_negotiation);
1949- }
1950- }
1957+ ) {
1958+ Ok(commitment_signed) => {
1959+ // Advance the state
1960+ pending_splice.funding_negotiation =
1961+ Some(FundingNegotiation::AwaitingSignatures { funding });
1962+ Ok((interactive_tx_constructor, commitment_signed))
1963+ },
1964+ Err(e) => {
1965+ // Restore the taken state for later error handling
1966+ pending_splice.funding_negotiation =
1967+ Some(FundingNegotiation::ConstructingTransaction {
1968+ funding,
1969+ interactive_tx_constructor,
1970+ });
1971+ Err(e)
1972+ },
1973+ }
1974+ })?
1975+ } else {
1976+ return Err(AbortReason::InternalError(
1977+ "Got a tx_complete message in an invalid state",
1978+ ));
19511979 }
1952-
1953- return Err(AbortReason::InternalError(
1954- "Got a tx_complete message in an invalid state",
1955- ));
19561980 },
19571981 _ => {
19581982 debug_assert!(false);
19591983 return Err(AbortReason::InternalError(
19601984 "Got a tx_complete message in an invalid phase",
19611985 ));
19621986 },
1963- }
1987+ };
1988+
1989+ let signing_session = interactive_tx_constructor.into_signing_session();
1990+ self.context_mut().interactive_tx_signing_session = Some(signing_session);
1991+ Ok(commitment_signed)
19641992 }
19651993
19661994 pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
@@ -6061,30 +6089,13 @@ where
60616089
60626090 #[rustfmt::skip]
60636091 fn funding_tx_constructed<L: Deref>(
6064- &mut self, funding: &mut FundingScope, signing_session: InteractiveTxSigningSession ,
6065- is_splice: bool, holder_commitment_transaction_number: u64, logger: &L
6092+ &mut self, funding: &mut FundingScope, funding_outpoint: OutPoint, is_splice: bool ,
6093+ holder_commitment_transaction_number: u64, logger: &L,
60666094 ) -> Result<msgs::CommitmentSigned, AbortReason>
60676095 where
60686096 L::Target: Logger
60696097 {
6070- let mut output_index = None;
6071- let expected_spk = funding.get_funding_redeemscript().to_p2wsh();
6072- for (idx, outp) in signing_session.unsigned_tx().tx().output.iter().enumerate() {
6073- if outp.script_pubkey == expected_spk && outp.value.to_sat() == funding.get_value_satoshis() {
6074- if output_index.is_some() {
6075- return Err(AbortReason::DuplicateFundingOutput);
6076- }
6077- output_index = Some(idx as u16);
6078- }
6079- }
6080- let outpoint = if let Some(output_index) = output_index {
6081- OutPoint { txid: signing_session.unsigned_tx().compute_txid(), index: output_index }
6082- } else {
6083- return Err(AbortReason::MissingFundingOutput);
6084- };
6085- funding
6086- .channel_transaction_parameters.funding_outpoint = Some(outpoint);
6087- self.interactive_tx_signing_session = Some(signing_session);
6098+ funding.channel_transaction_parameters.funding_outpoint = Some(funding_outpoint);
60886099
60896100 if is_splice {
60906101 debug_assert_eq!(
@@ -6101,7 +6112,6 @@ where
61016112 Some(commitment_signed) => commitment_signed,
61026113 // TODO(splicing): Support async signing
61036114 None => {
6104- funding.channel_transaction_parameters.funding_outpoint = None;
61056115 return Err(AbortReason::InternalError("Failed to compute commitment_signed signatures"));
61066116 },
61076117 };
@@ -6177,8 +6187,6 @@ where
61776187 SP::Target: SignerProvider,
61786188 L::Target: Logger,
61796189 {
6180- debug_assert!(self.interactive_tx_signing_session.is_some());
6181-
61826190 let signatures = self.get_initial_counterparty_commitment_signatures(funding, logger);
61836191 if let Some((signature, htlc_signatures)) = signatures {
61846192 log_info!(
@@ -6518,9 +6526,9 @@ impl FundingNegotiationContext {
65186526 /// Prepare and start interactive transaction negotiation.
65196527 /// If error occurs, it is caused by our side, not the counterparty.
65206528 fn into_interactive_tx_constructor<SP: Deref, ES: Deref>(
6521- self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
6529+ mut self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
65226530 entropy_source: &ES, holder_node_id: PublicKey,
6523- ) -> Result<InteractiveTxConstructor, AbortReason >
6531+ ) -> Result<InteractiveTxConstructor, NegotiationError >
65246532 where
65256533 SP::Target: SignerProvider,
65266534 ES::Target: EntropySource,
@@ -6546,25 +6554,32 @@ impl FundingNegotiationContext {
65466554
65476555 // Optionally add change output
65486556 let change_value_opt = if self.our_funding_contribution > SignedAmount::ZERO {
6549- calculate_change_output_value(
6557+ match calculate_change_output_value(
65506558 &self,
65516559 self.shared_funding_input.is_some(),
65526560 &shared_funding_output.script_pubkey,
65536561 context.holder_dust_limit_satoshis,
6554- )?
6562+ ) {
6563+ Ok(change_value_opt) => change_value_opt,
6564+ Err(reason) => {
6565+ return Err(self.into_negotiation_error(reason));
6566+ },
6567+ }
65556568 } else {
65566569 None
65576570 };
65586571
6559- let mut funding_outputs = self.our_funding_outputs;
6560-
65616572 if let Some(change_value) = change_value_opt {
65626573 let change_script = if let Some(script) = self.change_script {
65636574 script
65646575 } else {
6565- signer_provider
6566- .get_destination_script(context.channel_keys_id)
6567- .map_err(|_err| AbortReason::InternalError("Error getting change script"))?
6576+ match signer_provider.get_destination_script(context.channel_keys_id) {
6577+ Ok(script) => script,
6578+ Err(_) => {
6579+ let reason = AbortReason::InternalError("Error getting change script");
6580+ return Err(self.into_negotiation_error(reason));
6581+ },
6582+ }
65686583 };
65696584 let mut change_output =
65706585 TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
@@ -6575,7 +6590,7 @@ impl FundingNegotiationContext {
65756590 // Check dust limit again
65766591 if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
65776592 change_output.value = Amount::from_sat(change_value_decreased_with_fee);
6578- funding_outputs .push(change_output);
6593+ self.our_funding_outputs .push(change_output);
65796594 }
65806595 }
65816596
@@ -6593,10 +6608,19 @@ impl FundingNegotiationContext {
65936608 shared_funding_output,
65946609 funding.value_to_self_msat / 1000,
65956610 ),
6596- outputs_to_contribute: funding_outputs ,
6611+ outputs_to_contribute: self.our_funding_outputs ,
65976612 };
65986613 InteractiveTxConstructor::new(constructor_args)
65996614 }
6615+
6616+ fn into_negotiation_error(self, reason: AbortReason) -> NegotiationError {
6617+ let contributed_inputs =
6618+ self.our_funding_inputs.into_iter().map(|input| input.utxo.outpoint).collect();
6619+
6620+ let contributed_outputs = self.our_funding_outputs;
6621+
6622+ NegotiationError { reason, contributed_inputs, contributed_outputs }
6623+ }
66006624}
66016625
66026626// Holder designates channel data owned for the benefit of the user client.
@@ -13737,8 +13761,8 @@ where
1373713761 outputs_to_contribute: funding_negotiation_context.our_funding_outputs.clone(),
1373813762 }
1373913763 ).map_err(|err| {
13740- let reason = ClosureReason::ProcessingError { err: err.to_string() };
13741- ChannelError::Close((err.to_string(), reason))
13764+ let reason = ClosureReason::ProcessingError { err: err.reason. to_string() };
13765+ ChannelError::Close((err.reason. to_string(), reason))
1374213766 })?);
1374313767
1374413768 let unfunded_context = UnfundedChannelContext {
0 commit comments