diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs
index d01af737c32..83c987e8efe 100644
--- a/lightning/src/events/mod.rs
+++ b/lightning/src/events/mod.rs
@@ -1582,6 +1582,55 @@ pub enum Event {
/// onion messages.
peer_node_id: PublicKey,
},
+ /// Indicates that a funding transaction constructed via interactive transaction construction for a
+ /// channel is ready to be signed by the client. This event will only be triggered
+ /// if at least one input was contributed by the holder and needs to be signed.
+ ///
+ /// The transaction contains all inputs provided by both parties along with the channel's funding
+ /// output and a change output if applicable.
+ ///
+ /// No part of the transaction should be changed before signing as the content of the transaction
+ /// has already been negotiated with the counterparty.
+ ///
+ /// Each signature MUST use the SIGHASH_ALL flag to avoid invalidation of the initial commitment and
+ /// hence possible loss of funds.
+ ///
+ /// After signing, call [`ChannelManager::funding_transaction_signed`] with the (partially) signed
+ /// funding transaction.
+ ///
+ /// Generated in [`ChannelManager`] message handling.
+ ///
+ /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+ /// [`ChannelManager::funding_transaction_signed`]: crate::ln::channelmanager::ChannelManager::funding_transaction_signed
+ FundingTransactionReadyForSigning {
+ /// The channel_id of the channel which you'll need to pass back into
+ /// [`ChannelManager::funding_transaction_signed`].
+ ///
+ /// [`ChannelManager::funding_transaction_signed`]: crate::ln::channelmanager::ChannelManager::funding_transaction_signed
+ channel_id: ChannelId,
+ /// The counterparty's node_id, which you'll need to pass back into
+ /// [`ChannelManager::funding_transaction_signed`].
+ ///
+ /// [`ChannelManager::funding_transaction_signed`]: crate::ln::channelmanager::ChannelManager::funding_transaction_signed
+ counterparty_node_id: PublicKey,
+ // TODO(dual_funding): Enable links when methods are implemented
+ /// The `user_channel_id` value passed in to `ChannelManager::create_dual_funded_channel` for outbound
+ /// channels, or to [`ChannelManager::accept_inbound_channel`] or `ChannelManager::accept_inbound_channel_with_contribution`
+ /// for inbound channels if [`UserConfig::manually_accept_inbound_channels`] config flag is set to true.
+ /// Otherwise `user_channel_id` will be randomized for an inbound channel.
+ /// This may be zero for objects serialized with LDK versions prior to 0.0.113.
+ ///
+ /// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
+ /// [`UserConfig::manually_accept_inbound_channels`]: crate::util::config::UserConfig::manually_accept_inbound_channels
+ // [`ChannelManager::create_dual_funded_channel`]: crate::ln::channelmanager::ChannelManager::create_dual_funded_channel
+ // [`ChannelManager::accept_inbound_channel_with_contribution`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel_with_contribution
+ user_channel_id: u128,
+ /// The unsigned transaction to be signed and passed back to
+ /// [`ChannelManager::funding_transaction_signed`].
+ ///
+ /// [`ChannelManager::funding_transaction_signed`]: crate::ln::channelmanager::ChannelManager::funding_transaction_signed
+ unsigned_transaction: Transaction,
+ },
}
impl Writeable for Event {
@@ -2012,6 +2061,13 @@ impl Writeable for Event {
(8, former_temporary_channel_id, required),
});
},
+ &Event::FundingTransactionReadyForSigning { .. } => {
+ 45u8.write(writer)?;
+ // We never write out FundingTransactionReadyForSigning events as, upon disconnection, peers
+ // drop any V2-established/spliced channels which have not yet exchanged the initial `commitment_signed`.
+ // We only exhange the initial `commitment_signed` after the client calls
+ // `ChannelManager::funding_transaction_signed` and ALWAYS before we send a `tx_signatures`
+ },
// Note that, going forward, all new events must only write data inside of
// `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write
// data via `write_tlv_fields`.
@@ -2583,6 +2639,10 @@ impl MaybeReadable for Event {
former_temporary_channel_id: former_temporary_channel_id.0.unwrap(),
}))
},
+ 45u8 => {
+ // Value 45 is used for `Event::FundingTransactionReadyForSigning`.
+ Ok(None)
+ },
// Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue.
// Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt
// reads.
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index b516961d100..b7ee5e26ec9 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -14,7 +14,7 @@ use bitcoin::constants::ChainHash;
use bitcoin::script::{Builder, Script, ScriptBuf, WScriptHash};
use bitcoin::sighash::EcdsaSighashType;
use bitcoin::transaction::{Transaction, TxIn, TxOut};
-use bitcoin::Weight;
+use bitcoin::{Weight, Witness};
use bitcoin::hash_types::{BlockHash, Txid};
use bitcoin::hashes::sha256::Hash as Sha256;
@@ -2967,7 +2967,7 @@ where
},
};
- let funding_ready_for_sig_event = if signing_session.local_inputs_count() == 0 {
+ let funding_ready_for_sig_event_opt = if signing_session.local_inputs_count() == 0 {
debug_assert_eq!(our_funding_satoshis, 0);
if signing_session.provide_holder_witnesses(self.context.channel_id, Vec::new()).is_err() {
debug_assert!(
@@ -2981,28 +2981,12 @@ where
}
None
} else {
- // TODO(dual_funding): Send event for signing if we've contributed funds.
- // Inform the user that SIGHASH_ALL must be used for all signatures when contributing
- // inputs/signatures.
- // Also warn the user that we don't do anything to prevent the counterparty from
- // providing non-standard witnesses which will prevent the funding transaction from
- // confirming. This warning must appear in doc comments wherever the user is contributing
- // funds, whether they are initiator or acceptor.
- //
- // The following warning can be used when the APIs allowing contributing inputs become available:
- //
- // WARNING: LDK makes no attempt to prevent the counterparty from using non-standard inputs which
- // will prevent the funding transaction from being relayed on the bitcoin network and hence being
- // confirmed.
- //
- debug_assert!(
- false,
- "We don't support users providing inputs but somehow we had more than zero inputs",
- );
- return Err(ChannelError::Close((
- "V2 channel rejected due to sender error".into(),
- ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) }
- )));
+ Some(Event::FundingTransactionReadyForSigning {
+ channel_id: self.context.channel_id,
+ counterparty_node_id: self.context.counterparty_node_id,
+ user_channel_id: self.context.user_id,
+ unsigned_transaction: signing_session.unsigned_tx().build_unsigned_tx(),
+ })
};
let mut channel_state = ChannelState::FundingNegotiated(FundingNegotiatedFlags::new());
@@ -3013,7 +2997,7 @@ where
self.interactive_tx_constructor.take();
self.interactive_tx_signing_session = Some(signing_session);
- Ok((commitment_signed, funding_ready_for_sig_event))
+ Ok((commitment_signed, funding_ready_for_sig_event_opt))
}
}
@@ -7640,6 +7624,45 @@ where
}
}
+ fn verify_interactive_tx_signatures(&mut self, _witnesses: &Vec) {
+ if let Some(ref mut _signing_session) = self.interactive_tx_signing_session {
+ // Check that sighash_all was used:
+ // TODO(dual_funding): Check sig for sighash
+ }
+ }
+
+ pub fn funding_transaction_signed(
+ &mut self, witnesses: Vec, logger: &L,
+ ) -> Result