From 3d6091a27a3d7d2ca8980eb01f343c8473fa2e3e Mon Sep 17 00:00:00 2001 From: Duncan Dean Date: Fri, 13 Dec 2024 10:54:58 +0200 Subject: [PATCH 1/2] Reintroduce cfg(dual_funding) for handling of open_channel2 messages --- Cargo.toml | 1 + lightning/src/ln/channel.rs | 9 +++++- lightning/src/ln/channelmanager.rs | 22 ++++++++++--- lightning/src/ln/dual_funding_tests.rs | 43 ++++++++++++++------------ lightning/src/ln/peer_handler.rs | 4 +-- 5 files changed, 53 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2250f06b3ee..f5bc0448fba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,4 +65,5 @@ check-cfg = [ "cfg(require_route_graph_test)", "cfg(splicing)", "cfg(async_payments)", + "cfg(dual_funding)", ] diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 18e009e38ea..c9680fcd99b 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -1131,6 +1131,7 @@ pub(super) enum ChannelPhase where SP::Target: SignerProvider { UnfundedInboundV1(InboundV1Channel), #[allow(dead_code)] // TODO(dual_funding): Remove once creating V2 channels is enabled. UnfundedOutboundV2(OutboundV2Channel), + #[allow(dead_code)] // TODO(dual_funding): Remove once accepting V2 channels is enabled. UnfundedInboundV2(InboundV2Channel), Funded(Channel), } @@ -4080,7 +4081,7 @@ impl ChannelContext where SP::Target: SignerProvider { }) } - #[cfg(test)] + #[cfg(all(test, dual_funding))] pub fn get_initial_counterparty_commitment_signature_for_test( &mut self, logger: &L, channel_transaction_parameters: ChannelTransactionParameters, counterparty_cur_commitment_point_override: PublicKey, @@ -4150,6 +4151,7 @@ fn get_v2_channel_reserve_satoshis(channel_value_satoshis: u64, dust_limit_satos cmp::min(channel_value_satoshis, cmp::max(q, dust_limit_satoshis)) } +#[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled. pub(super) fn calculate_our_funding_satoshis( is_initiator: bool, funding_inputs: &[(TxIn, TransactionU16LenLimited)], total_witness_weight: Weight, funding_feerate_sat_per_1000_weight: u32, @@ -4199,6 +4201,7 @@ pub(super) struct DualFundingChannelContext { /// to the current block height to align incentives against fee-sniping. pub funding_tx_locktime: LockTime, /// The feerate set by the initiator to be used for the funding transaction. + #[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled. pub funding_feerate_sat_per_1000_weight: u32, /// The funding inputs we will be contributing to the channel. /// @@ -8276,6 +8279,7 @@ pub(super) struct OutboundV1Channel where SP::Target: SignerProvider } impl OutboundV1Channel where SP::Target: SignerProvider { + #[allow(dead_code)] // TODO(dual_funding): Remove once opending V2 channels is enabled. pub fn new( fee_estimator: &LowerBoundedFeeEstimator, entropy_source: &ES, signer_provider: &SP, counterparty_node_id: PublicKey, their_features: &InitFeatures, channel_value_satoshis: u64, push_msat: u64, user_id: u128, config: &UserConfig, current_chain_height: u32, @@ -8901,6 +8905,7 @@ pub(super) struct InboundV2Channel where SP::Target: SignerProvider { impl InboundV2Channel where SP::Target: SignerProvider { /// Creates a new dual-funded channel from a remote side's request for one. /// Assumes chain_hash has already been checked and corresponds with what we expect! + #[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled. pub fn new( fee_estimator: &LowerBoundedFeeEstimator, entropy_source: &ES, signer_provider: &SP, holder_node_id: PublicKey, counterparty_node_id: PublicKey, our_supported_features: &ChannelTypeFeatures, @@ -9005,6 +9010,7 @@ impl InboundV2Channel where SP::Target: SignerProvider { /// should be sent back to the counterparty node. /// /// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2 + #[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled. pub fn accept_inbound_dual_funded_channel(&self) -> msgs::AcceptChannelV2 { if self.context.is_outbound() { debug_assert!(false, "Tried to send accept_channel for an outbound channel?"); @@ -9027,6 +9033,7 @@ impl InboundV2Channel where SP::Target: SignerProvider { /// use [`InboundV1Channel::accept_inbound_channel`] instead. /// /// [`msgs::AcceptChannelV2`]: crate::ln::msgs::AcceptChannelV2 + #[allow(dead_code)] // TODO(dual_funding): Remove once V2 channels is enabled. fn generate_accept_channel_v2_message(&self) -> msgs::AcceptChannelV2 { let first_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point( self.context.holder_commitment_point.transaction_number(), &self.context.secp_ctx) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 53c190d36a0..e48eedfe52e 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -48,7 +48,9 @@ use crate::events::{self, Event, EventHandler, EventsProvider, InboundChannelFun use crate::ln::inbound_payment; use crate::ln::types::ChannelId; use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; -use crate::ln::channel::{self, Channel, ChannelPhase, ChannelError, ChannelUpdateStatus, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel, WithChannelContext, InboundV2Channel, InteractivelyFunded as _}; +use crate::ln::channel::{self, Channel, ChannelPhase, ChannelError, ChannelUpdateStatus, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel, WithChannelContext, InteractivelyFunded as _}; +#[cfg(dual_funding)] +use crate::ln::channel::InboundV2Channel; use crate::ln::channel_state::ChannelDetails; use crate::types::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; #[cfg(any(feature = "_test_utils", test))] @@ -1376,11 +1378,13 @@ impl PeerState where SP::Target: SignerProvider { #[derive(Clone)] pub(super) enum OpenChannelMessage { V1(msgs::OpenChannel), + #[cfg(dual_funding)] V2(msgs::OpenChannelV2), } pub(super) enum OpenChannelMessageRef<'a> { V1(&'a msgs::OpenChannel), + #[cfg(dual_funding)] V2(&'a msgs::OpenChannelV2), } @@ -7686,8 +7690,8 @@ where fn do_accept_inbound_channel( &self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, accept_0conf: bool, - user_channel_id: u128, funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, - total_witness_weight: Weight, + user_channel_id: u128, _funding_inputs: Vec<(TxIn, TransactionU16LenLimited)>, + _total_witness_weight: Weight, ) -> Result<(), APIError> { let logger = WithContext::from(&self.logger, Some(*counterparty_node_id), Some(*temporary_channel_id), None); let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); @@ -7728,10 +7732,11 @@ where (*temporary_channel_id, ChannelPhase::UnfundedInboundV1(channel), message_send_event) }) }, + #[cfg(dual_funding)] OpenChannelMessage::V2(open_channel_msg) => { InboundV2Channel::new(&self.fee_estimator, &self.entropy_source, &self.signer_provider, self.get_our_node_id(), *counterparty_node_id, &self.channel_type_features(), &peer_state.latest_features, - &open_channel_msg, funding_inputs, total_witness_weight, user_channel_id, + &open_channel_msg, _funding_inputs, _total_witness_weight, user_channel_id, &self.default_configuration, best_block_height, &self.logger ).map_err(|_| MsgHandleErrInternal::from_chan_no_close( ChannelError::Close( @@ -7882,6 +7887,7 @@ where fn internal_open_channel(&self, counterparty_node_id: &PublicKey, msg: OpenChannelMessageRef<'_>) -> Result<(), MsgHandleErrInternal> { let common_fields = match msg { OpenChannelMessageRef::V1(msg) => &msg.common_fields, + #[cfg(dual_funding)] OpenChannelMessageRef::V2(msg) => &msg.common_fields, }; @@ -7959,6 +7965,7 @@ where funding_satoshis: common_fields.funding_satoshis, channel_negotiation_type: match msg { OpenChannelMessageRef::V1(msg) => InboundChannelFunds::PushMsat(msg.push_msat), + #[cfg(dual_funding)] OpenChannelMessageRef::V2(_) => InboundChannelFunds::DualFunded, }, channel_type, @@ -7968,6 +7975,7 @@ where peer_state.inbound_channel_request_by_id.insert(channel_id, InboundChannelRequest { open_channel_msg: match msg { OpenChannelMessageRef::V1(msg) => OpenChannelMessage::V1(msg.clone()), + #[cfg(dual_funding)] OpenChannelMessageRef::V2(msg) => OpenChannelMessage::V2(msg.clone()), }, ticks_remaining: UNACCEPTED_INBOUND_CHANNEL_AGE_LIMIT_TICKS, @@ -8000,6 +8008,7 @@ where }; (ChannelPhase::UnfundedInboundV1(channel), message_send_event) }, + #[cfg(dual_funding)] OpenChannelMessageRef::V2(msg) => { let channel = InboundV2Channel::new(&self.fee_estimator, &self.entropy_source, &self.signer_provider, self.get_our_node_id(), *counterparty_node_id, @@ -11273,6 +11282,7 @@ where // Note that we never need to persist the updated ChannelManager for an inbound // open_channel message - pre-funded channels are never written so there should be no // change to the contents. + #[cfg(dual_funding)] let _persistence_guard = PersistenceNotifierGuard::optionally_notify(self, || { let res = self.internal_open_channel(&counterparty_node_id, OpenChannelMessageRef::V2(msg)); let persist = match &res { @@ -11285,6 +11295,10 @@ where let _ = handle_error!(self, res, counterparty_node_id); persist }); + #[cfg(not(dual_funding))] + let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close( + "Dual-funded channels not supported".to_owned(), + msg.common_fields.temporary_channel_id.clone())), counterparty_node_id); } fn handle_accept_channel(&self, counterparty_node_id: PublicKey, msg: &msgs::AcceptChannel) { diff --git a/lightning/src/ln/dual_funding_tests.rs b/lightning/src/ln/dual_funding_tests.rs index 7742931cd9f..c0a79ba303d 100644 --- a/lightning/src/ln/dual_funding_tests.rs +++ b/lightning/src/ln/dual_funding_tests.rs @@ -9,32 +9,36 @@ //! Tests that test the creation of dual-funded channels in ChannelManager. -use bitcoin::Weight; - -use crate::chain::chaininterface::{ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator}; -use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider}; -use crate::ln::chan_utils::{ - make_funding_redeemscript, ChannelPublicKeys, ChannelTransactionParameters, - CounterpartyChannelTransactionParameters, -}; -use crate::ln::channel::{ - calculate_our_funding_satoshis, OutboundV2Channel, MIN_CHAN_DUST_LIMIT_SATOSHIS, +#[cfg(dual_funding)] +use { + crate::chain::chaininterface::{ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator}, + crate::events::{Event, MessageSendEvent, MessageSendEventsProvider}, + crate::ln::chan_utils::{ + make_funding_redeemscript, ChannelPublicKeys, ChannelTransactionParameters, + CounterpartyChannelTransactionParameters, + }, + crate::ln::channel::{ + calculate_our_funding_satoshis, OutboundV2Channel, MIN_CHAN_DUST_LIMIT_SATOSHIS, + }, + crate::ln::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint, RevocationBasepoint}, + crate::ln::functional_test_utils::*, + crate::ln::msgs::ChannelMessageHandler, + crate::ln::msgs::{CommitmentSigned, TxAddInput, TxAddOutput, TxComplete}, + crate::ln::types::ChannelId, + crate::prelude::*, + crate::sign::{ChannelSigner as _, P2WPKH_WITNESS_WEIGHT}, + crate::util::ser::TransactionU16LenLimited, + crate::util::test_utils, + bitcoin::Weight, }; -use crate::ln::channel_keys::{DelayedPaymentBasepoint, HtlcBasepoint, RevocationBasepoint}; -use crate::ln::functional_test_utils::*; -use crate::ln::msgs::ChannelMessageHandler; -use crate::ln::msgs::{CommitmentSigned, TxAddInput, TxAddOutput, TxComplete}; -use crate::ln::types::ChannelId; -use crate::prelude::*; -use crate::sign::{ChannelSigner as _, P2WPKH_WITNESS_WEIGHT}; -use crate::util::ser::TransactionU16LenLimited; -use crate::util::test_utils; +#[cfg(dual_funding)] // Dual-funding: V2 Channel Establishment Tests struct V2ChannelEstablishmentTestSession { initiator_input_value_satoshis: u64, } +#[cfg(dual_funding)] // TODO(dual_funding): Use real node and API for creating V2 channels as initiator when available, // instead of manually constructing messages. fn do_test_v2_channel_establishment( @@ -252,6 +256,7 @@ fn do_test_v2_channel_establishment( } #[test] +#[cfg(dual_funding)] fn test_v2_channel_establishment() { // Only initiator contributes, no persist pending do_test_v2_channel_establishment( diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index f561ef18edc..93aae4a6f4f 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -1820,8 +1820,8 @@ impl { self.message_handler.chan_handler.handle_open_channel(their_node_id, &msg); }, - wire::Message::OpenChannelV2(msg) => { - self.message_handler.chan_handler.handle_open_channel_v2(their_node_id, &msg); + wire::Message::OpenChannelV2(_msg) => { + self.message_handler.chan_handler.handle_open_channel_v2(their_node_id, &_msg); }, wire::Message::AcceptChannel(msg) => { self.message_handler.chan_handler.handle_accept_channel(their_node_id, &msg); From e5f6e4eed24ce428631270ada1d045716e749d9e Mon Sep 17 00:00:00 2001 From: Duncan Dean Date: Fri, 13 Dec 2024 11:22:01 +0200 Subject: [PATCH 2/2] Modify release notes for PR 3137 We will not support accepting V2 channels in the v0.1 release, but we do need to document the API change for push_msats -> channel_negotiation_type. --- .../3137-accept-dual-funding-without-contributing.txt | 2 +- pending_changelog/3137-channel-negotiation-type.txt | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 pending_changelog/3137-channel-negotiation-type.txt diff --git a/pending_changelog/3137-accept-dual-funding-without-contributing.txt b/pending_changelog/3137-accept-dual-funding-without-contributing.txt index 486e71a46b2..9ea8de24e54 100644 --- a/pending_changelog/3137-accept-dual-funding-without-contributing.txt +++ b/pending_changelog/3137-accept-dual-funding-without-contributing.txt @@ -1,4 +1,4 @@ -# API Updates +# API Updates (0.2) * Accepting dual-funded (V2 establishment) channels (without contibuting) is now supported (#3137). Some particulars to be aware of for this feature: * Creating dual-funded channels is not yet supported. diff --git a/pending_changelog/3137-channel-negotiation-type.txt b/pending_changelog/3137-channel-negotiation-type.txt new file mode 100644 index 00000000000..8eafa4e072b --- /dev/null +++ b/pending_changelog/3137-channel-negotiation-type.txt @@ -0,0 +1,7 @@ +# API Updates + * `Event::OpenChannelRequest::push_msat` has been replaced by the field `channel_negotiation_type` to + differentiate between an inbound request for a dual-funded (V2) or non-dual-funded (V1) channel to be + opened, with value being either of the enum variants `InboundChannelFunds::DualFunded` and + `InboundChannelFunds::PushMsat(u64)` corresponding to V2 and V1 channel open requests respectively. + This is in preparation for supporting accepting dual-funded channels, which will be available in a later release. +