@@ -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};
@@ -1678,12 +1679,13 @@ where
1678
1679
}
1679
1680
1680
1681
fn fail_interactive_tx_negotiation<L: Deref>(
1681
- &mut self, reason: AbortReason , logger: &L,
1682
+ &mut self, error: NegotiationError , logger: &L,
1682
1683
) -> msgs::TxAbort
1683
1684
where
1684
1685
L::Target: Logger,
1685
1686
{
1686
1687
let logger = WithChannelContext::from(logger, &self.context(), None);
1688
+ let NegotiationError { reason, .. } = error;
1687
1689
log_info!(logger, "Failed interactive transaction negotiation: {reason}");
1688
1690
1689
1691
let _interactive_tx_constructor = match &mut self.phase {
@@ -1720,11 +1722,15 @@ where
1720
1722
{
1721
1723
match self.interactive_tx_constructor_mut() {
1722
1724
Some(interactive_tx_constructor) => interactive_tx_constructor.handle_tx_add_input(msg),
1723
- None => Err(AbortReason::InternalError(
1724
- "Received unexpected interactive transaction negotiation message",
1725
- )),
1725
+ None => Err(NegotiationError {
1726
+ reason: AbortReason::InternalError(
1727
+ "Received unexpected interactive transaction negotiation message",
1728
+ ),
1729
+ contributed_inputs: Vec::new(),
1730
+ contributed_outputs: Vec::new(),
1731
+ }),
1726
1732
}
1727
- .map_err(|abort_reason | self.fail_interactive_tx_negotiation(abort_reason , logger))
1733
+ .map_err(|e | self.fail_interactive_tx_negotiation(e , logger))
1728
1734
}
1729
1735
1730
1736
pub fn tx_add_output<L: Deref>(
@@ -1737,11 +1743,15 @@ where
1737
1743
Some(interactive_tx_constructor) => {
1738
1744
interactive_tx_constructor.handle_tx_add_output(msg)
1739
1745
},
1740
- None => Err(AbortReason::InternalError(
1741
- "Received unexpected interactive transaction negotiation message",
1742
- )),
1746
+ None => Err(NegotiationError {
1747
+ reason: AbortReason::InternalError(
1748
+ "Received unexpected interactive transaction negotiation message",
1749
+ ),
1750
+ contributed_inputs: Vec::new(),
1751
+ contributed_outputs: Vec::new(),
1752
+ }),
1743
1753
}
1744
- .map_err(|abort_reason | self.fail_interactive_tx_negotiation(abort_reason , logger))
1754
+ .map_err(|e | self.fail_interactive_tx_negotiation(e , logger))
1745
1755
}
1746
1756
1747
1757
pub fn tx_remove_input<L: Deref>(
@@ -1754,11 +1764,15 @@ where
1754
1764
Some(interactive_tx_constructor) => {
1755
1765
interactive_tx_constructor.handle_tx_remove_input(msg)
1756
1766
},
1757
- None => Err(AbortReason::InternalError(
1758
- "Received unexpected interactive transaction negotiation message",
1759
- )),
1767
+ None => Err(NegotiationError {
1768
+ reason: AbortReason::InternalError(
1769
+ "Received unexpected interactive transaction negotiation message",
1770
+ ),
1771
+ contributed_inputs: Vec::new(),
1772
+ contributed_outputs: Vec::new(),
1773
+ }),
1760
1774
}
1761
- .map_err(|abort_reason | self.fail_interactive_tx_negotiation(abort_reason , logger))
1775
+ .map_err(|e | self.fail_interactive_tx_negotiation(e , logger))
1762
1776
}
1763
1777
1764
1778
pub fn tx_remove_output<L: Deref>(
@@ -1771,11 +1785,15 @@ where
1771
1785
Some(interactive_tx_constructor) => {
1772
1786
interactive_tx_constructor.handle_tx_remove_output(msg)
1773
1787
},
1774
- None => Err(AbortReason::InternalError(
1775
- "Received unexpected interactive transaction negotiation message",
1776
- )),
1788
+ None => Err(NegotiationError {
1789
+ reason: AbortReason::InternalError(
1790
+ "Received unexpected interactive transaction negotiation message",
1791
+ ),
1792
+ contributed_inputs: Vec::new(),
1793
+ contributed_outputs: Vec::new(),
1794
+ }),
1777
1795
}
1778
- .map_err(|abort_reason | self.fail_interactive_tx_negotiation(abort_reason , logger))
1796
+ .map_err(|e | self.fail_interactive_tx_negotiation(e , logger))
1779
1797
}
1780
1798
1781
1799
pub fn tx_complete<L: Deref>(
@@ -1786,11 +1804,15 @@ where
1786
1804
{
1787
1805
let tx_complete_action = match self.interactive_tx_constructor_mut() {
1788
1806
Some(interactive_tx_constructor) => interactive_tx_constructor.handle_tx_complete(msg),
1789
- None => Err(AbortReason::InternalError(
1790
- "Received unexpected interactive transaction negotiation message",
1791
- )),
1807
+ None => Err(NegotiationError {
1808
+ reason: AbortReason::InternalError(
1809
+ "Received unexpected interactive transaction negotiation message",
1810
+ ),
1811
+ contributed_inputs: Vec::new(),
1812
+ contributed_outputs: Vec::new(),
1813
+ }),
1792
1814
}
1793
- .map_err(|abort_reason | self.fail_interactive_tx_negotiation(abort_reason , logger))?;
1815
+ .map_err(|e | self.fail_interactive_tx_negotiation(e , logger))?;
1794
1816
1795
1817
let (interactive_tx_msg_send, negotiation_complete) = match tx_complete_action {
1796
1818
HandleTxCompleteValue::SendTxMessage(interactive_tx_msg_send) => {
@@ -1808,7 +1830,7 @@ where
1808
1830
1809
1831
let commitment_signed = self
1810
1832
.funding_tx_constructed(logger)
1811
- .map_err(|abort_reason | self.fail_interactive_tx_negotiation(abort_reason , logger))?;
1833
+ .map_err(|e | self.fail_interactive_tx_negotiation(e , logger))?;
1812
1834
Ok((interactive_tx_msg_send, Some(commitment_signed)))
1813
1835
}
1814
1836
@@ -1891,7 +1913,7 @@ where
1891
1913
1892
1914
fn funding_tx_constructed<L: Deref>(
1893
1915
&mut self, logger: &L,
1894
- ) -> Result<msgs::CommitmentSigned, AbortReason >
1916
+ ) -> Result<msgs::CommitmentSigned, NegotiationError >
1895
1917
where
1896
1918
L::Target: Logger,
1897
1919
{
@@ -1949,15 +1971,23 @@ where
1949
1971
}
1950
1972
}
1951
1973
1952
- return Err(AbortReason::InternalError(
1953
- "Got a tx_complete message in an invalid state",
1954
- ));
1974
+ return Err(NegotiationError {
1975
+ reason: AbortReason::InternalError(
1976
+ "Got a tx_complete message in an invalid state",
1977
+ ),
1978
+ contributed_inputs: Vec::new(),
1979
+ contributed_outputs: Vec::new(),
1980
+ });
1955
1981
},
1956
1982
_ => {
1957
1983
debug_assert!(false);
1958
- return Err(AbortReason::InternalError(
1959
- "Got a tx_complete message in an invalid phase",
1960
- ));
1984
+ return Err(NegotiationError {
1985
+ reason: AbortReason::InternalError(
1986
+ "Got a tx_complete message in an invalid phase",
1987
+ ),
1988
+ contributed_inputs: Vec::new(),
1989
+ contributed_outputs: Vec::new(),
1990
+ });
1961
1991
},
1962
1992
}
1963
1993
}
@@ -6053,7 +6083,7 @@ where
6053
6083
fn funding_tx_constructed<L: Deref>(
6054
6084
&mut self, funding: &mut FundingScope, signing_session: InteractiveTxSigningSession,
6055
6085
is_splice: bool, holder_commitment_transaction_number: u64, logger: &L
6056
- ) -> Result<msgs::CommitmentSigned, AbortReason >
6086
+ ) -> Result<msgs::CommitmentSigned, NegotiationError >
6057
6087
where
6058
6088
L::Target: Logger
6059
6089
{
@@ -6062,15 +6092,17 @@ where
6062
6092
for (idx, outp) in signing_session.unsigned_tx().tx().output.iter().enumerate() {
6063
6093
if outp.script_pubkey == expected_spk && outp.value.to_sat() == funding.get_value_satoshis() {
6064
6094
if output_index.is_some() {
6065
- return Err(AbortReason::DuplicateFundingOutput);
6095
+ let reason = AbortReason::DuplicateFundingOutput;
6096
+ return Err(signing_session.into_negotiation_error(reason));
6066
6097
}
6067
6098
output_index = Some(idx as u16);
6068
6099
}
6069
6100
}
6070
6101
let outpoint = if let Some(output_index) = output_index {
6071
6102
OutPoint { txid: signing_session.unsigned_tx().compute_txid(), index: output_index }
6072
6103
} else {
6073
- return Err(AbortReason::MissingFundingOutput);
6104
+ let reason = AbortReason::MissingFundingOutput;
6105
+ return Err(signing_session.into_negotiation_error(reason));
6074
6106
};
6075
6107
funding
6076
6108
.channel_transaction_parameters.funding_outpoint = Some(outpoint);
@@ -6092,7 +6124,9 @@ where
6092
6124
// TODO(splicing): Support async signing
6093
6125
None => {
6094
6126
funding.channel_transaction_parameters.funding_outpoint = None;
6095
- return Err(AbortReason::InternalError("Failed to compute commitment_signed signatures"));
6127
+ let signing_session = self.interactive_tx_signing_session.take().unwrap();
6128
+ let reason = AbortReason::InternalError("Failed to compute commitment_signed signatures");
6129
+ return Err(signing_session.into_negotiation_error(reason));
6096
6130
},
6097
6131
};
6098
6132
@@ -6508,9 +6542,9 @@ impl FundingNegotiationContext {
6508
6542
/// Prepare and start interactive transaction negotiation.
6509
6543
/// If error occurs, it is caused by our side, not the counterparty.
6510
6544
fn into_interactive_tx_constructor<SP: Deref, ES: Deref>(
6511
- self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
6545
+ mut self, context: &ChannelContext<SP>, funding: &FundingScope, signer_provider: &SP,
6512
6546
entropy_source: &ES, holder_node_id: PublicKey,
6513
- ) -> Result<InteractiveTxConstructor, AbortReason >
6547
+ ) -> Result<InteractiveTxConstructor, NegotiationError >
6514
6548
where
6515
6549
SP::Target: SignerProvider,
6516
6550
ES::Target: EntropySource,
@@ -6536,25 +6570,32 @@ impl FundingNegotiationContext {
6536
6570
6537
6571
// Optionally add change output
6538
6572
let change_value_opt = if self.our_funding_contribution > SignedAmount::ZERO {
6539
- calculate_change_output_value(
6573
+ match calculate_change_output_value(
6540
6574
&self,
6541
6575
self.shared_funding_input.is_some(),
6542
6576
&shared_funding_output.script_pubkey,
6543
6577
context.holder_dust_limit_satoshis,
6544
- )?
6578
+ ) {
6579
+ Ok(change_value_opt) => change_value_opt,
6580
+ Err(reason) => {
6581
+ return Err(self.into_negotiation_error(reason));
6582
+ },
6583
+ }
6545
6584
} else {
6546
6585
None
6547
6586
};
6548
6587
6549
- let mut funding_outputs = self.our_funding_outputs;
6550
-
6551
6588
if let Some(change_value) = change_value_opt {
6552
6589
let change_script = if let Some(script) = self.change_script {
6553
6590
script
6554
6591
} else {
6555
- signer_provider
6556
- .get_destination_script(context.channel_keys_id)
6557
- .map_err(|_err| AbortReason::InternalError("Error getting change script"))?
6592
+ match signer_provider.get_destination_script(context.channel_keys_id) {
6593
+ Ok(script) => script,
6594
+ Err(_) => {
6595
+ let reason = AbortReason::InternalError("Error getting change script");
6596
+ return Err(self.into_negotiation_error(reason));
6597
+ },
6598
+ }
6558
6599
};
6559
6600
let mut change_output =
6560
6601
TxOut { value: Amount::from_sat(change_value), script_pubkey: change_script };
@@ -6565,7 +6606,7 @@ impl FundingNegotiationContext {
6565
6606
// Check dust limit again
6566
6607
if change_value_decreased_with_fee > context.holder_dust_limit_satoshis {
6567
6608
change_output.value = Amount::from_sat(change_value_decreased_with_fee);
6568
- funding_outputs .push(change_output);
6609
+ self.our_funding_outputs .push(change_output);
6569
6610
}
6570
6611
}
6571
6612
@@ -6583,10 +6624,19 @@ impl FundingNegotiationContext {
6583
6624
shared_funding_output,
6584
6625
funding.value_to_self_msat / 1000,
6585
6626
),
6586
- outputs_to_contribute: funding_outputs ,
6627
+ outputs_to_contribute: self.our_funding_outputs ,
6587
6628
};
6588
6629
InteractiveTxConstructor::new(constructor_args)
6589
6630
}
6631
+
6632
+ fn into_negotiation_error(self, reason: AbortReason) -> NegotiationError {
6633
+ let contributed_inputs =
6634
+ self.our_funding_inputs.into_iter().map(|input| input.utxo.outpoint).collect();
6635
+
6636
+ let contributed_outputs = self.our_funding_outputs;
6637
+
6638
+ NegotiationError { reason, contributed_inputs, contributed_outputs }
6639
+ }
6590
6640
}
6591
6641
6592
6642
// Holder designates channel data owned for the benefit of the user client.
@@ -13660,8 +13710,8 @@ where
13660
13710
outputs_to_contribute: funding_negotiation_context.our_funding_outputs.clone(),
13661
13711
}
13662
13712
).map_err(|err| {
13663
- let reason = ClosureReason::ProcessingError { err: err.to_string() };
13664
- ChannelError::Close((err.to_string(), reason))
13713
+ let reason = ClosureReason::ProcessingError { err: err.reason. to_string() };
13714
+ ChannelError::Close((err.reason. to_string(), reason))
13665
13715
})?);
13666
13716
13667
13717
let unfunded_context = UnfundedChannelContext {
0 commit comments