@@ -60,7 +60,8 @@ use crate::ln::funding::{FundingTxInput, SpliceContribution};
60
60
use crate::ln::interactivetxs::{
61
61
calculate_change_output_value, get_output_weight, AbortReason, HandleTxCompleteValue,
62
62
InteractiveTxConstructor, InteractiveTxConstructorArgs, InteractiveTxMessageSend,
63
- InteractiveTxSigningSession, SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT,
63
+ InteractiveTxSigningSession, NegotiationError, SharedOwnedInput, SharedOwnedOutput,
64
+ TX_COMMON_FIELDS_WEIGHT,
64
65
};
65
66
use crate::ln::msgs;
66
67
use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket};
@@ -1794,20 +1795,22 @@ where
1794
1795
1795
1796
let (interactive_tx_msg_send, negotiation_complete) = match tx_complete_action {
1796
1797
HandleTxCompleteValue::SendTxMessage(interactive_tx_msg_send) => {
1797
- (Some(interactive_tx_msg_send), false )
1798
+ (Some(interactive_tx_msg_send), None )
1798
1799
},
1799
- HandleTxCompleteValue::SendTxComplete (
1800
+ HandleTxCompleteValue::NegotiationComplete (
1800
1801
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)),
1804
1804
};
1805
- if !negotiation_complete {
1805
+
1806
+ let funding_outpoint = if let Some(funding_outpoint) = negotiation_complete {
1807
+ funding_outpoint
1808
+ } else {
1806
1809
return Ok((interactive_tx_msg_send, None));
1807
- }
1810
+ };
1808
1811
1809
1812
let commitment_signed = self
1810
- .funding_tx_constructed(logger)
1813
+ .funding_tx_constructed(funding_outpoint, logger)
1811
1814
.map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))?;
1812
1815
Ok((interactive_tx_msg_send, Some(commitment_signed)))
1813
1816
}
@@ -1890,13 +1893,13 @@ where
1890
1893
}
1891
1894
1892
1895
fn funding_tx_constructed<L: Deref>(
1893
- &mut self, logger: &L,
1896
+ &mut self, funding_outpoint: OutPoint, logger: &L,
1894
1897
) -> Result<msgs::CommitmentSigned, AbortReason>
1895
1898
where
1896
1899
L::Target: Logger,
1897
1900
{
1898
1901
let logger = WithChannelContext::from(logger, self.context(), None);
1899
- match &mut self.phase {
1902
+ let (interactive_tx_constructor, commitment_signed) = match &mut self.phase {
1900
1903
ChannelPhase::UnfundedV2(chan) => {
1901
1904
debug_assert_eq!(
1902
1905
chan.context.channel_state,
@@ -1906,60 +1909,77 @@ where
1906
1909
),
1907
1910
);
1908
1911
1909
- let signing_session = chan
1912
+ let interactive_tx_constructor = chan
1910
1913
.interactive_tx_constructor
1911
1914
.take()
1912
- .expect("PendingV2Channel::interactive_tx_constructor should be set")
1913
- .into_signing_session();
1915
+ .expect("PendingV2Channel::interactive_tx_constructor should be set");
1914
1916
let commitment_signed = chan.context.funding_tx_constructed(
1915
1917
&mut chan.funding,
1916
- signing_session ,
1918
+ funding_outpoint ,
1917
1919
false,
1918
1920
chan.unfunded_context.transaction_number(),
1919
1921
&&logger,
1920
1922
)?;
1921
1923
1922
- return Ok( commitment_signed);
1924
+ (interactive_tx_constructor, commitment_signed)
1923
1925
},
1924
1926
ChannelPhase::Funded(chan) => {
1925
1927
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
+ Some((funding, interactive_tx_constructor))
1937
+ } else {
1938
+ // Replace the taken state for later error handling
1939
+ pending_splice.funding_negotiation = Some(funding_negotiation);
1940
+ None
1941
+ }
1942
+ })
1943
+ .ok_or_else(|| AbortReason::InternalError("Got a tx_complete message in an invalid state"))
1944
+ .and_then(|(mut funding, interactive_tx_constructor)| {
1945
+ match chan.context.funding_tx_constructed(
1934
1946
&mut funding,
1935
- signing_session ,
1947
+ funding_outpoint ,
1936
1948
true,
1937
1949
chan.holder_commitment_point.next_transaction_number(),
1938
1950
&&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
- }
1951
+ ) {
1952
+ Ok(commitment_signed) => {
1953
+ // Advance the state
1954
+ pending_splice.funding_negotiation =
1955
+ Some(FundingNegotiation::AwaitingSignatures { funding });
1956
+ Ok((interactive_tx_constructor, commitment_signed))
1957
+ },
1958
+ Err(e) => {
1959
+ // Restore the taken state for later error handling
1960
+ pending_splice.funding_negotiation =
1961
+ Some(FundingNegotiation::ConstructingTransaction { funding, interactive_tx_constructor });
1962
+ Err(e)
1963
+ },
1964
+ }
1965
+ })?
1966
+ } else {
1967
+ return Err(AbortReason::InternalError(
1968
+ "Got a tx_complete message in an invalid state",
1969
+ ));
1950
1970
}
1951
-
1952
- return Err(AbortReason::InternalError(
1953
- "Got a tx_complete message in an invalid state",
1954
- ));
1955
1971
},
1956
1972
_ => {
1957
1973
debug_assert!(false);
1958
1974
return Err(AbortReason::InternalError(
1959
1975
"Got a tx_complete message in an invalid phase",
1960
1976
));
1961
1977
},
1962
- }
1978
+ };
1979
+
1980
+ let signing_session = interactive_tx_constructor.into_signing_session();
1981
+ self.context_mut().interactive_tx_signing_session = Some(signing_session);
1982
+ Ok(commitment_signed)
1963
1983
}
1964
1984
1965
1985
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
@@ -6051,30 +6071,13 @@ where
6051
6071
6052
6072
#[rustfmt::skip]
6053
6073
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
6074
+ &mut self, funding: &mut FundingScope, funding_outpoint: OutPoint, is_splice: bool ,
6075
+ holder_commitment_transaction_number: u64, logger: &L,
6056
6076
) -> Result<msgs::CommitmentSigned, AbortReason>
6057
6077
where
6058
6078
L::Target: Logger
6059
6079
{
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);
6080
+ funding.channel_transaction_parameters.funding_outpoint = Some(funding_outpoint);
6078
6081
6079
6082
if is_splice {
6080
6083
debug_assert_eq!(
@@ -6091,7 +6094,6 @@ where
6091
6094
Some(commitment_signed) => commitment_signed,
6092
6095
// TODO(splicing): Support async signing
6093
6096
None => {
6094
- funding.channel_transaction_parameters.funding_outpoint = None;
6095
6097
return Err(AbortReason::InternalError("Failed to compute commitment_signed signatures"));
6096
6098
},
6097
6099
};
@@ -6167,8 +6169,6 @@ where
6167
6169
SP::Target: SignerProvider,
6168
6170
L::Target: Logger,
6169
6171
{
6170
- debug_assert!(self.interactive_tx_signing_session.is_some());
6171
-
6172
6172
let signatures = self.get_initial_counterparty_commitment_signatures(funding, logger);
6173
6173
if let Some((signature, htlc_signatures)) = signatures {
6174
6174
log_info!(
@@ -6508,9 +6508,9 @@ impl FundingNegotiationContext {
6508
6508
/// Prepare and start interactive transaction negotiation.
6509
6509
/// If error occurs, it is caused by our side, not the counterparty.
6510
6510
fn into_interactive_tx_constructor<SP: Deref, ES: Deref>(
6511
- self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
6511
+ mut self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
6512
6512
entropy_source: &ES, holder_node_id: PublicKey,
6513
- ) -> Result<InteractiveTxConstructor, AbortReason >
6513
+ ) -> Result<InteractiveTxConstructor, NegotiationError >
6514
6514
where
6515
6515
SP::Target: SignerProvider,
6516
6516
ES::Target: EntropySource,
@@ -6536,25 +6536,32 @@ impl FundingNegotiationContext {
6536
6536
6537
6537
// Optionally add change output
6538
6538
let change_value_opt = if self.our_funding_contribution > SignedAmount::ZERO {
6539
- calculate_change_output_value(
6539
+ match calculate_change_output_value(
6540
6540
&self,
6541
6541
self.shared_funding_input.is_some(),
6542
6542
&shared_funding_output.script_pubkey,
6543
6543
context.holder_dust_limit_satoshis,
6544
- )?
6544
+ ) {
6545
+ Ok(change_value_opt) => change_value_opt,
6546
+ Err(reason) => {
6547
+ return Err(self.into_negotiation_error(reason));
6548
+ },
6549
+ }
6545
6550
} else {
6546
6551
None
6547
6552
};
6548
6553
6549
- let mut funding_outputs = self.our_funding_outputs;
6550
-
6551
6554
if let Some(change_value) = change_value_opt {
6552
6555
let change_script = if let Some(script) = self.change_script {
6553
6556
script
6554
6557
} else {
6555
- signer_provider
6556
- .get_destination_script(context.channel_keys_id)
6557
- .map_err(|_err| AbortReason::InternalError("Error getting change script"))?
6558
+ match signer_provider.get_destination_script(context.channel_keys_id) {
6559
+ Ok(script) => script,
6560
+ Err(_) => {
6561
+ let reason = AbortReason::InternalError("Error getting change script");
6562
+ return Err(self.into_negotiation_error(reason));
6563
+ },
6564
+ }
6558
6565
};
6559
6566
let mut change_output =
6560
6567
TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
@@ -6565,7 +6572,7 @@ impl FundingNegotiationContext {
6565
6572
// Check dust limit again
6566
6573
if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
6567
6574
change_output.value = Amount::from_sat(change_value_decreased_with_fee);
6568
- funding_outputs .push(change_output);
6575
+ self.our_funding_outputs .push(change_output);
6569
6576
}
6570
6577
}
6571
6578
@@ -6583,10 +6590,19 @@ impl FundingNegotiationContext {
6583
6590
shared_funding_output,
6584
6591
funding.value_to_self_msat / 1000,
6585
6592
),
6586
- outputs_to_contribute: funding_outputs ,
6593
+ outputs_to_contribute: self.our_funding_outputs ,
6587
6594
};
6588
6595
InteractiveTxConstructor::new(constructor_args)
6589
6596
}
6597
+
6598
+ fn into_negotiation_error(self, reason: AbortReason) -> NegotiationError {
6599
+ let contributed_inputs =
6600
+ self.our_funding_inputs.into_iter().map(|input| input.utxo.outpoint).collect();
6601
+
6602
+ let contributed_outputs = self.our_funding_outputs;
6603
+
6604
+ NegotiationError { reason, contributed_inputs, contributed_outputs }
6605
+ }
6590
6606
}
6591
6607
6592
6608
// Holder designates channel data owned for the benefit of the user client.
@@ -13660,8 +13676,8 @@ where
13660
13676
outputs_to_contribute: funding_negotiation_context.our_funding_outputs.clone(),
13661
13677
}
13662
13678
).map_err(|err| {
13663
- let reason = ClosureReason::ProcessingError { err: err.to_string() };
13664
- ChannelError::Close((err.to_string(), reason))
13679
+ let reason = ClosureReason::ProcessingError { err: err.reason. to_string() };
13680
+ ChannelError::Close((err.reason. to_string(), reason))
13665
13681
})?);
13666
13682
13667
13683
let unfunded_context = UnfundedChannelContext {
0 commit comments