@@ -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,85 @@ 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
+ {
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(
1934
1951
&mut funding,
1935
- signing_session ,
1952
+ funding_outpoint ,
1936
1953
true,
1937
1954
chan.holder_commitment_point.next_transaction_number(),
1938
1955
&&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
+ ));
1950
1978
}
1951
-
1952
- return Err(AbortReason::InternalError(
1953
- "Got a tx_complete message in an invalid state",
1954
- ));
1955
1979
},
1956
1980
_ => {
1957
1981
debug_assert!(false);
1958
1982
return Err(AbortReason::InternalError(
1959
1983
"Got a tx_complete message in an invalid phase",
1960
1984
));
1961
1985
},
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)
1963
1991
}
1964
1992
1965
1993
pub fn force_shutdown(&mut self, closure_reason: ClosureReason) -> ShutdownResult {
@@ -6051,30 +6079,13 @@ where
6051
6079
6052
6080
#[rustfmt::skip]
6053
6081
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,
6056
6084
) -> Result<msgs::CommitmentSigned, AbortReason>
6057
6085
where
6058
6086
L::Target: Logger
6059
6087
{
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);
6078
6089
6079
6090
if is_splice {
6080
6091
debug_assert_eq!(
@@ -6091,7 +6102,6 @@ where
6091
6102
Some(commitment_signed) => commitment_signed,
6092
6103
// TODO(splicing): Support async signing
6093
6104
None => {
6094
- funding.channel_transaction_parameters.funding_outpoint = None;
6095
6105
return Err(AbortReason::InternalError("Failed to compute commitment_signed signatures"));
6096
6106
},
6097
6107
};
@@ -6167,8 +6177,6 @@ where
6167
6177
SP::Target: SignerProvider,
6168
6178
L::Target: Logger,
6169
6179
{
6170
- debug_assert!(self.interactive_tx_signing_session.is_some());
6171
-
6172
6180
let signatures = self.get_initial_counterparty_commitment_signatures(funding, logger);
6173
6181
if let Some((signature, htlc_signatures)) = signatures {
6174
6182
log_info!(
@@ -6508,9 +6516,9 @@ impl FundingNegotiationContext {
6508
6516
/// Prepare and start interactive transaction negotiation.
6509
6517
/// If error occurs, it is caused by our side, not the counterparty.
6510
6518
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,
6512
6520
entropy_source: &ES, holder_node_id: PublicKey,
6513
- ) -> Result<InteractiveTxConstructor, AbortReason >
6521
+ ) -> Result<InteractiveTxConstructor, NegotiationError >
6514
6522
where
6515
6523
SP::Target: SignerProvider,
6516
6524
ES::Target: EntropySource,
@@ -6536,25 +6544,32 @@ impl FundingNegotiationContext {
6536
6544
6537
6545
// Optionally add change output
6538
6546
let change_value_opt = if self.our_funding_contribution > SignedAmount::ZERO {
6539
- calculate_change_output_value(
6547
+ match calculate_change_output_value(
6540
6548
&self,
6541
6549
self.shared_funding_input.is_some(),
6542
6550
&shared_funding_output.script_pubkey,
6543
6551
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
+ }
6545
6558
} else {
6546
6559
None
6547
6560
};
6548
6561
6549
- let mut funding_outputs = self.our_funding_outputs;
6550
-
6551
6562
if let Some(change_value) = change_value_opt {
6552
6563
let change_script = if let Some(script) = self.change_script {
6553
6564
script
6554
6565
} 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
+ }
6558
6573
};
6559
6574
let mut change_output =
6560
6575
TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
@@ -6565,7 +6580,7 @@ impl FundingNegotiationContext {
6565
6580
// Check dust limit again
6566
6581
if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
6567
6582
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);
6569
6584
}
6570
6585
}
6571
6586
@@ -6583,10 +6598,19 @@ impl FundingNegotiationContext {
6583
6598
shared_funding_output,
6584
6599
funding.value_to_self_msat / 1000,
6585
6600
),
6586
- outputs_to_contribute: funding_outputs ,
6601
+ outputs_to_contribute: self.our_funding_outputs ,
6587
6602
};
6588
6603
InteractiveTxConstructor::new(constructor_args)
6589
6604
}
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
+ }
6590
6614
}
6591
6615
6592
6616
// Holder designates channel data owned for the benefit of the user client.
@@ -13660,8 +13684,8 @@ where
13660
13684
outputs_to_contribute: funding_negotiation_context.our_funding_outputs.clone(),
13661
13685
}
13662
13686
).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))
13665
13689
})?);
13666
13690
13667
13691
let unfunded_context = UnfundedChannelContext {
0 commit comments