@@ -63,12 +63,11 @@ use crate::ln::funding::FundingTxInput;
6363#[cfg(splicing)]
6464use crate::ln::funding::SpliceContribution;
6565#[cfg(splicing)]
66+ use crate::ln::interactivetxs::calculate_change_output_value;
6667use crate::ln::interactivetxs::{
67- calculate_change_output_value, AbortReason, InteractiveTxMessageSend,
68- };
69- use crate::ln::interactivetxs::{
70- get_output_weight, InteractiveTxConstructor, InteractiveTxConstructorArgs,
71- InteractiveTxSigningSession, SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT,
68+ get_output_weight, AbortReason, HandleTxCompleteValue, InteractiveTxConstructor,
69+ InteractiveTxConstructorArgs, InteractiveTxMessageSend, InteractiveTxSigningSession,
70+ SharedOwnedInput, SharedOwnedOutput, TX_COMMON_FIELDS_WEIGHT,
7271};
7372use crate::ln::msgs;
7473use crate::ln::msgs::{ClosingSigned, ClosingSignedFeeRange, DecodeError, OnionErrorPacket};
@@ -1597,14 +1596,6 @@ where
15971596 }
15981597 }
15991598
1600- pub fn as_unfunded_v2_mut(&mut self) -> Option<&mut PendingV2Channel<SP>> {
1601- if let ChannelPhase::UnfundedV2(channel) = &mut self.phase {
1602- Some(channel)
1603- } else {
1604- None
1605- }
1606- }
1607-
16081599 #[rustfmt::skip]
16091600 pub fn signer_maybe_unblocked<L: Deref>(
16101601 &mut self, chain_hash: ChainHash, logger: &L,
@@ -1739,7 +1730,7 @@ where
17391730 }
17401731 }
17411732
1742- pub fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> {
1733+ fn interactive_tx_constructor_mut(&mut self) -> Option<&mut InteractiveTxConstructor> {
17431734 match &mut self.phase {
17441735 ChannelPhase::UnfundedV2(chan) => chan.interactive_tx_constructor.as_mut(),
17451736 #[cfg(splicing)]
@@ -1748,6 +1739,195 @@ where
17481739 }
17491740 }
17501741
1742+ fn fail_interactive_tx_negotiation<L: Deref>(
1743+ &mut self, reason: AbortReason, logger: &L,
1744+ ) -> msgs::TxAbort
1745+ where
1746+ L::Target: Logger,
1747+ {
1748+ let logger = WithChannelContext::from(logger, &self.context(), None);
1749+ log_info!(logger, "Failed interactive transaction negotiation: {reason}");
1750+
1751+ let _interactive_tx_constructor = match &mut self.phase {
1752+ ChannelPhase::Undefined => unreachable!(),
1753+ ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => None,
1754+ ChannelPhase::UnfundedV2(pending_v2_channel) => {
1755+ pending_v2_channel.interactive_tx_constructor.take()
1756+ },
1757+ #[cfg(not(splicing))]
1758+ ChannelPhase::Funded(_) => unreachable!(),
1759+ #[cfg(splicing)]
1760+ ChannelPhase::Funded(funded_channel) => funded_channel
1761+ .pending_splice
1762+ .as_mut()
1763+ .and_then(|pending_splice| pending_splice.funding_negotiation.take())
1764+ .and_then(|funding_negotiation| {
1765+ if let FundingNegotiation::ConstructingTransaction(
1766+ _,
1767+ interactive_tx_constructor,
1768+ ) = funding_negotiation
1769+ {
1770+ Some(interactive_tx_constructor)
1771+ } else {
1772+ None
1773+ }
1774+ }),
1775+ };
1776+
1777+ reason.into_tx_abort_msg(self.context().channel_id)
1778+ }
1779+
1780+ pub fn tx_add_input<L: Deref>(
1781+ &mut self, msg: &msgs::TxAddInput, logger: &L,
1782+ ) -> Result<InteractiveTxMessageSend, msgs::TxAbort>
1783+ where
1784+ L::Target: Logger,
1785+ {
1786+ match self.interactive_tx_constructor_mut() {
1787+ Some(interactive_tx_constructor) => interactive_tx_constructor.handle_tx_add_input(msg),
1788+ None => Err(AbortReason::InternalError(
1789+ "Received unexpected interactive transaction negotiation message",
1790+ )),
1791+ }
1792+ .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))
1793+ }
1794+
1795+ pub fn tx_add_output<L: Deref>(
1796+ &mut self, msg: &msgs::TxAddOutput, logger: &L,
1797+ ) -> Result<InteractiveTxMessageSend, msgs::TxAbort>
1798+ where
1799+ L::Target: Logger,
1800+ {
1801+ match self.interactive_tx_constructor_mut() {
1802+ Some(interactive_tx_constructor) => {
1803+ interactive_tx_constructor.handle_tx_add_output(msg)
1804+ },
1805+ None => Err(AbortReason::InternalError(
1806+ "Received unexpected interactive transaction negotiation message",
1807+ )),
1808+ }
1809+ .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))
1810+ }
1811+
1812+ pub fn tx_remove_input<L: Deref>(
1813+ &mut self, msg: &msgs::TxRemoveInput, logger: &L,
1814+ ) -> Result<InteractiveTxMessageSend, msgs::TxAbort>
1815+ where
1816+ L::Target: Logger,
1817+ {
1818+ match self.interactive_tx_constructor_mut() {
1819+ Some(interactive_tx_constructor) => {
1820+ interactive_tx_constructor.handle_tx_remove_input(msg)
1821+ },
1822+ None => Err(AbortReason::InternalError(
1823+ "Received unexpected interactive transaction negotiation message",
1824+ )),
1825+ }
1826+ .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))
1827+ }
1828+
1829+ pub fn tx_remove_output<L: Deref>(
1830+ &mut self, msg: &msgs::TxRemoveOutput, logger: &L,
1831+ ) -> Result<InteractiveTxMessageSend, msgs::TxAbort>
1832+ where
1833+ L::Target: Logger,
1834+ {
1835+ match self.interactive_tx_constructor_mut() {
1836+ Some(interactive_tx_constructor) => {
1837+ interactive_tx_constructor.handle_tx_remove_output(msg)
1838+ },
1839+ None => Err(AbortReason::InternalError(
1840+ "Received unexpected interactive transaction negotiation message",
1841+ )),
1842+ }
1843+ .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))
1844+ }
1845+
1846+ pub fn tx_complete<L: Deref>(
1847+ &mut self, msg: &msgs::TxComplete, logger: &L,
1848+ ) -> Result<(Option<InteractiveTxMessageSend>, Option<msgs::CommitmentSigned>), msgs::TxAbort>
1849+ where
1850+ L::Target: Logger,
1851+ {
1852+ let tx_complete_action = match self.interactive_tx_constructor_mut() {
1853+ Some(interactive_tx_constructor) => interactive_tx_constructor.handle_tx_complete(msg),
1854+ None => Err(AbortReason::InternalError(
1855+ "Received unexpected interactive transaction negotiation message",
1856+ )),
1857+ }
1858+ .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))?;
1859+
1860+ let (interactive_tx_msg_send, negotiation_complete) = match tx_complete_action {
1861+ HandleTxCompleteValue::SendTxMessage(interactive_tx_msg_send) => {
1862+ (Some(interactive_tx_msg_send), false)
1863+ },
1864+ HandleTxCompleteValue::SendTxComplete(
1865+ interactive_tx_msg_send,
1866+ negotiation_complete,
1867+ ) => (Some(interactive_tx_msg_send), negotiation_complete),
1868+ HandleTxCompleteValue::NegotiationComplete => (None, true),
1869+ };
1870+ if !negotiation_complete {
1871+ return Ok((interactive_tx_msg_send, None));
1872+ }
1873+
1874+ let commitment_signed = self
1875+ .funding_tx_constructed(logger)
1876+ .map_err(|abort_reason| self.fail_interactive_tx_negotiation(abort_reason, logger))?;
1877+ Ok((interactive_tx_msg_send, Some(commitment_signed)))
1878+ }
1879+
1880+ pub fn tx_abort<L: Deref>(
1881+ &mut self, msg: &msgs::TxAbort, logger: &L,
1882+ ) -> Result<Option<msgs::TxAbort>, ChannelError>
1883+ where
1884+ L::Target: Logger,
1885+ {
1886+ // This checks for and resets the interactive negotiation state by `take()`ing it from the channel.
1887+ // The existence of the `tx_constructor` indicates that we have not moved into the signing
1888+ // phase for this interactively constructed transaction and hence we have not exchanged
1889+ // `tx_signatures`. Either way, we never close the channel upon receiving a `tx_abort`:
1890+ // https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L574-L576
1891+ let should_ack = match &mut self.phase {
1892+ ChannelPhase::Undefined => unreachable!(),
1893+ ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => {
1894+ let err = "Got an unexpected tx_abort message: This is an unfunded channel created with V1 channel establishment";
1895+ return Err(ChannelError::Warn(err.into()));
1896+ },
1897+ ChannelPhase::UnfundedV2(pending_v2_channel) => {
1898+ pending_v2_channel.interactive_tx_constructor.take().is_some()
1899+ },
1900+ #[cfg(not(splicing))]
1901+ ChannelPhase::Funded(_) => {
1902+ let err = "Got an unexpected tx_abort message: This is an funded channel and splicing is not supported";
1903+ return Err(ChannelError::Warn(err.into()));
1904+ },
1905+ #[cfg(splicing)]
1906+ ChannelPhase::Funded(funded_channel) => funded_channel
1907+ .pending_splice
1908+ .as_mut()
1909+ .and_then(|pending_splice| pending_splice.funding_negotiation.take())
1910+ .is_some(),
1911+ };
1912+
1913+ // NOTE: Since at this point we have not sent a `tx_abort` message for this negotiation
1914+ // previously (tx_constructor was `Some`), we need to echo back a tx_abort message according
1915+ // to the spec:
1916+ // https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L560-L561
1917+ // For rationale why we echo back `tx_abort`:
1918+ // https://github.com/lightning/bolts/blob/247e83d/02-peer-protocol.md?plain=1#L578-L580
1919+ Ok(should_ack.then(|| {
1920+ let logger = WithChannelContext::from(logger, &self.context(), None);
1921+ let reason =
1922+ types::string::UntrustedString(String::from_utf8_lossy(&msg.data).to_string());
1923+ log_info!(logger, "Counterparty failed interactive transaction negotiation: {reason}");
1924+ msgs::TxAbort {
1925+ channel_id: msg.channel_id,
1926+ data: "Acknowledged tx_abort".to_string().into_bytes(),
1927+ }
1928+ }))
1929+ }
1930+
17511931 #[rustfmt::skip]
17521932 pub fn funding_signed<L: Deref>(
17531933 &mut self, msg: &msgs::FundingSigned, best_block: BestBlock, signer_provider: &SP, logger: &L
@@ -1780,9 +1960,9 @@ where
17801960 result.map(|monitor| (self.as_funded_mut().expect("Channel should be funded"), monitor))
17811961 }
17821962
1783- pub fn funding_tx_constructed<L: Deref>(
1963+ fn funding_tx_constructed<L: Deref>(
17841964 &mut self, logger: &L,
1785- ) -> Result<msgs::CommitmentSigned, msgs::TxAbort >
1965+ ) -> Result<msgs::CommitmentSigned, AbortReason >
17861966 where
17871967 L::Target: Logger,
17881968 {
@@ -1837,17 +2017,15 @@ where
18372017 }
18382018 }
18392019
1840- return Err(msgs::TxAbort {
1841- channel_id: chan.context.channel_id(),
1842- data: "Got a tx_complete message in an invalid state".to_owned().into_bytes(),
1843- });
2020+ return Err(AbortReason::InternalError(
2021+ "Got a tx_complete message in an invalid state",
2022+ ));
18442023 },
18452024 _ => {
18462025 debug_assert!(false);
1847- return Err(msgs::TxAbort {
1848- channel_id: self.context().channel_id(),
1849- data: "Got a tx_complete message in an invalid phase".to_owned().into_bytes(),
1850- });
2026+ return Err(AbortReason::InternalError(
2027+ "Got a tx_complete message in an invalid phase",
2028+ ));
18512029 },
18522030 }
18532031 }
@@ -5855,7 +6033,7 @@ where
58556033 fn funding_tx_constructed<L: Deref>(
58566034 &mut self, funding: &mut FundingScope, signing_session: &mut InteractiveTxSigningSession,
58576035 is_splice: bool, holder_commitment_transaction_number: u64, logger: &L
5858- ) -> Result<msgs::CommitmentSigned, msgs::TxAbort >
6036+ ) -> Result<msgs::CommitmentSigned, AbortReason >
58596037 where
58606038 L::Target: Logger
58616039 {
@@ -5864,21 +6042,15 @@ where
58646042 for (idx, outp) in signing_session.unsigned_tx().outputs().enumerate() {
58656043 if outp.script_pubkey() == &expected_spk && outp.value() == funding.get_value_satoshis() {
58666044 if output_index.is_some() {
5867- return Err(msgs::TxAbort {
5868- channel_id: self.channel_id(),
5869- data: "Multiple outputs matched the expected script and value".to_owned().into_bytes(),
5870- });
6045+ return Err(AbortReason::DuplicateFundingOutput);
58716046 }
58726047 output_index = Some(idx as u16);
58736048 }
58746049 }
58756050 let outpoint = if let Some(output_index) = output_index {
58766051 OutPoint { txid: signing_session.unsigned_tx().compute_txid(), index: output_index }
58776052 } else {
5878- return Err(msgs::TxAbort {
5879- channel_id: self.channel_id(),
5880- data: "No output matched the funding script_pubkey".to_owned().into_bytes(),
5881- });
6053+ return Err(AbortReason::MissingFundingOutput);
58826054 };
58836055 funding
58846056 .channel_transaction_parameters.funding_outpoint = Some(outpoint);
@@ -5892,10 +6064,7 @@ where
58926064 self.counterparty_next_commitment_transaction_number,
58936065 );
58946066 // TODO(splicing) Forced error, as the use case is not complete
5895- return Err(msgs::TxAbort {
5896- channel_id: self.channel_id(),
5897- data: "Splicing not yet supported".to_owned().into_bytes(),
5898- });
6067+ return Err(AbortReason::InternalError("Splicing not yet supported"));
58996068 } else {
59006069 self.assert_no_commitment_advancement(holder_commitment_transaction_number, "initial commitment_signed");
59016070 }
@@ -5906,10 +6075,7 @@ where
59066075 // TODO(splicing): Support async signing
59076076 None => {
59086077 funding.channel_transaction_parameters.funding_outpoint = None;
5909- return Err(msgs::TxAbort {
5910- channel_id: self.channel_id(),
5911- data: "Failed to get signature for commitment_signed".to_owned().into_bytes(),
5912- });
6078+ return Err(AbortReason::InternalError("Failed to compute commitment_signed signatures"));
59136079 },
59146080 };
59156081
0 commit comments