@@ -126,6 +126,25 @@ pub struct SpliceFundingNegotiated {
126
126
pub channel_type: ChannelTypeFeatures,
127
127
}
128
128
129
+ /// Information about a splice funding negotiation that has failed.
130
+ /// This is returned from channel operations and converted to an Event::SpliceFailed in ChannelManager.
131
+ pub struct SpliceFundingFailed {
132
+ /// The channel_id of the channel for which the splice failed.
133
+ pub channel_id: ChannelId,
134
+ /// The counterparty's node_id.
135
+ pub counterparty_node_id: PublicKey,
136
+ /// The user_channel_id value.
137
+ pub user_channel_id: u128,
138
+ /// The outpoint of the channel's splice funding transaction, if one was created.
139
+ pub funding_txo: Option<bitcoin::OutPoint>,
140
+ /// The features that this channel will operate with, if available.
141
+ pub channel_type: Option<ChannelTypeFeatures>,
142
+ /// Input outpoints contributed to the splice transaction.
143
+ pub contributed_inputs: Vec<bitcoin::OutPoint>,
144
+ /// Outputs contributed to the splice transaction.
145
+ pub contributed_outputs: Vec<bitcoin::TxOut>,
146
+ }
147
+
129
148
pub struct AvailableBalances {
130
149
/// Total amount available for our counterparty to send to us.
131
150
pub inbound_capacity_msat: u64,
@@ -1728,42 +1747,68 @@ where
1728
1747
1729
1748
fn fail_interactive_tx_negotiation<L: Deref>(
1730
1749
&mut self, reason: AbortReason, logger: &L,
1731
- ) -> msgs::TxAbort
1750
+ ) -> ( msgs::TxAbort, Option<SpliceFundingFailed>)
1732
1751
where
1733
1752
L::Target: Logger,
1734
1753
{
1735
1754
let logger = WithChannelContext::from(logger, &self.context(), None);
1736
1755
log_info!(logger, "Failed interactive transaction negotiation: {reason}");
1737
1756
1757
+ let mut splice_failed = None;
1758
+
1738
1759
let _interactive_tx_constructor = match &mut self.phase {
1739
1760
ChannelPhase::Undefined => unreachable!(),
1740
1761
ChannelPhase::UnfundedOutboundV1(_) | ChannelPhase::UnfundedInboundV1(_) => None,
1741
1762
ChannelPhase::UnfundedV2(pending_v2_channel) => {
1742
1763
pending_v2_channel.interactive_tx_constructor.take()
1743
1764
},
1744
- ChannelPhase::Funded(funded_channel) => funded_channel
1745
- .pending_splice
1746
- .as_mut()
1747
- .and_then(|pending_splice| pending_splice.funding_negotiation.take())
1748
- .and_then(|funding_negotiation| {
1749
- if let FundingNegotiation::ConstructingTransaction {
1750
- interactive_tx_constructor,
1751
- ..
1752
- } = funding_negotiation
1753
- {
1754
- Some(interactive_tx_constructor)
1765
+ ChannelPhase::Funded(funded_channel) => {
1766
+ if let Some(pending_splice) = funded_channel.pending_splice.as_mut() {
1767
+ if pending_splice.funding_negotiation.is_some() {
1768
+ let funding_negotiation = pending_splice.funding_negotiation.take();
1769
+
1770
+ let (funding_txo, channel_type, contributed_inputs, contributed_outputs) =
1771
+ if let Some(FundingNegotiation::ConstructingTransaction { funding, interactive_tx_constructor: _ }) = &funding_negotiation {
1772
+ (
1773
+ funding.get_funding_txo().map(|txo| txo.into_bitcoin_outpoint()),
1774
+ Some(funding.get_channel_type().clone()),
1775
+ Vec::new(), // TODO: Extract contributed inputs from interactive_tx_constructor
1776
+ Vec::new(), // TODO: Extract contributed outputs from interactive_tx_constructor
1777
+ )
1778
+ } else {
1779
+ (None, None, Vec::new(), Vec::new())
1780
+ };
1781
+
1782
+ splice_failed = Some(SpliceFundingFailed {
1783
+ channel_id: funded_channel.context.channel_id,
1784
+ counterparty_node_id: funded_channel.context.counterparty_node_id,
1785
+ user_channel_id: funded_channel.context.user_id,
1786
+ funding_txo,
1787
+ channel_type,
1788
+ contributed_inputs,
1789
+ contributed_outputs,
1790
+ });
1791
+
1792
+ if let Some(FundingNegotiation::ConstructingTransaction { interactive_tx_constructor, .. }) = funding_negotiation {
1793
+ Some(interactive_tx_constructor)
1794
+ } else {
1795
+ None
1796
+ }
1755
1797
} else {
1756
1798
None
1757
1799
}
1758
- }),
1800
+ } else {
1801
+ None
1802
+ }
1803
+ },
1759
1804
};
1760
1805
1761
- reason.into_tx_abort_msg(self.context().channel_id)
1806
+ ( reason.into_tx_abort_msg(self.context().channel_id), splice_failed )
1762
1807
}
1763
1808
1764
1809
pub fn tx_add_input<L: Deref>(
1765
1810
&mut self, msg: &msgs::TxAddInput, logger: &L,
1766
- ) -> Result<InteractiveTxMessageSend, msgs::TxAbort>
1811
+ ) -> Result<InteractiveTxMessageSend, ( msgs::TxAbort, Option<SpliceFundingFailed>) >
1767
1812
where
1768
1813
L::Target: Logger,
1769
1814
{
@@ -1778,7 +1823,7 @@ where
1778
1823
1779
1824
pub fn tx_add_output<L: Deref>(
1780
1825
&mut self, msg: &msgs::TxAddOutput, logger: &L,
1781
- ) -> Result<InteractiveTxMessageSend, msgs::TxAbort>
1826
+ ) -> Result<InteractiveTxMessageSend, ( msgs::TxAbort, Option<SpliceFundingFailed>) >
1782
1827
where
1783
1828
L::Target: Logger,
1784
1829
{
@@ -1795,7 +1840,7 @@ where
1795
1840
1796
1841
pub fn tx_remove_input<L: Deref>(
1797
1842
&mut self, msg: &msgs::TxRemoveInput, logger: &L,
1798
- ) -> Result<InteractiveTxMessageSend, msgs::TxAbort>
1843
+ ) -> Result<InteractiveTxMessageSend, ( msgs::TxAbort, Option<SpliceFundingFailed>) >
1799
1844
where
1800
1845
L::Target: Logger,
1801
1846
{
@@ -1812,7 +1857,7 @@ where
1812
1857
1813
1858
pub fn tx_remove_output<L: Deref>(
1814
1859
&mut self, msg: &msgs::TxRemoveOutput, logger: &L,
1815
- ) -> Result<InteractiveTxMessageSend, msgs::TxAbort>
1860
+ ) -> Result<InteractiveTxMessageSend, ( msgs::TxAbort, Option<SpliceFundingFailed>) >
1816
1861
where
1817
1862
L::Target: Logger,
1818
1863
{
@@ -1829,7 +1874,7 @@ where
1829
1874
1830
1875
pub fn tx_complete<L: Deref>(
1831
1876
&mut self, msg: &msgs::TxComplete, logger: &L,
1832
- ) -> Result<(Option<InteractiveTxMessageSend>, Option<msgs::CommitmentSigned>), msgs::TxAbort>
1877
+ ) -> Result<(Option<InteractiveTxMessageSend>, Option<msgs::CommitmentSigned>), ( msgs::TxAbort, Option<SpliceFundingFailed>) >
1833
1878
where
1834
1879
L::Target: Logger,
1835
1880
{
0 commit comments