From b0a441f3a754d18c0411d708d72f148a0679fe19 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 13 Feb 2025 14:51:42 -0600 Subject: [PATCH 01/20] Reduce ChannelContext::channel_transaction_parameters visibility --- lightning/src/ln/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 01feaf017df..e5b80862fe2 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -1862,7 +1862,7 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { counterparty_forwarding_info: Option, - pub(crate) channel_transaction_parameters: ChannelTransactionParameters, + pub(super) channel_transaction_parameters: ChannelTransactionParameters, /// The transaction which funds this channel. Note that for manually-funded channels (i.e., /// is_manual_broadcast is true) this will be a dummy empty transaction. funding_transaction: Option, From d796878589a3a11f696913d2db41b9c82ab4f3d4 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 19 Feb 2025 09:46:18 -0600 Subject: [PATCH 02/20] Move channel_transaction_parameters to FundingScope Rather than moving relevant fields of ChannelTransactionParameters to FundingScope, move the entire struct there instead. This prevents API churn wherever ChannelTransactionParameters is used, which otherwise would need a FundingScope in addition. --- lightning/src/ln/channel.rs | 503 +++++++++++++------------ lightning/src/ln/channel_state.rs | 6 +- lightning/src/ln/channelmanager.rs | 77 ++-- lightning/src/ln/dual_funding_tests.rs | 6 +- lightning/src/ln/functional_tests.rs | 4 +- 5 files changed, 309 insertions(+), 287 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index e5b80862fe2..e799b74bf14 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -1399,7 +1399,7 @@ impl Channel where ReconnectionMsg::None }, ChannelPhase::UnfundedV2(chan) => { - if chan.context.is_outbound() { + if chan.funding.is_outbound() { ReconnectionMsg::Open(OpenChannelMessage::V2( chan.get_open_channel_v2(chain_hash) )) @@ -1431,7 +1431,7 @@ impl Channel where }, ChannelPhase::UnfundedInboundV1(_) => Ok(None), ChannelPhase::UnfundedV2(chan) => { - if chan.context.is_outbound() { + if chan.funding.is_outbound() { chan.maybe_handle_error_without_close(chain_hash, fee_estimator) .map(|msg| Some(OpenChannelMessage::V2(msg))) } else { @@ -1648,6 +1648,8 @@ pub(super) struct FundingScope { next_local_commitment_tx_fee_info_cached: Mutex>, #[cfg(any(test, fuzzing))] next_remote_commitment_tx_fee_info_cached: Mutex>, + + pub(super) channel_transaction_parameters: ChannelTransactionParameters, } impl FundingScope { @@ -1672,6 +1674,44 @@ impl FundingScope { ) }) } + + pub fn is_outbound(&self) -> bool { + self.channel_transaction_parameters.is_outbound_from_holder + } + + /// Returns the funding_txo we either got from our peer, or were given by + /// get_funding_created. + pub fn get_funding_txo(&self) -> Option { + self.channel_transaction_parameters.funding_outpoint + } + + fn get_holder_selected_contest_delay(&self) -> u16 { + self.channel_transaction_parameters.holder_selected_contest_delay + } + + fn get_holder_pubkeys(&self) -> &ChannelPublicKeys { + &self.channel_transaction_parameters.holder_pubkeys + } + + pub fn get_counterparty_selected_contest_delay(&self) -> Option { + self.channel_transaction_parameters.counterparty_parameters + .as_ref().map(|params| params.selected_contest_delay) + } + + fn get_counterparty_pubkeys(&self) -> &ChannelPublicKeys { + &self.channel_transaction_parameters.counterparty_parameters.as_ref().unwrap().pubkeys + } + + /// Gets the redeemscript for the funding transaction output (ie the funding transaction output + /// pays to get_funding_redeemscript().to_p2wsh()). + /// Panics if called before accept_channel/InboundV1Channel::new + pub fn get_funding_redeemscript(&self) -> ScriptBuf { + make_funding_redeemscript(&self.get_holder_pubkeys().funding_pubkey, self.counterparty_funding_pubkey()) + } + + fn counterparty_funding_pubkey(&self) -> &PublicKey { + &self.get_counterparty_pubkeys().funding_pubkey + } } /// Contains everything about the channel including state, and various flags. @@ -1862,7 +1902,6 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { counterparty_forwarding_info: Option, - pub(super) channel_transaction_parameters: ChannelTransactionParameters, /// The transaction which funds this channel. Note that for manually-funded channels (i.e., /// is_manual_broadcast is true) this will be a dummy empty transaction. funding_transaction: Option, @@ -1986,24 +2025,26 @@ trait InitialRemoteCommitmentReceiver where SP::Target: SignerProvide fn funding(&self) -> &FundingScope; + fn funding_mut(&mut self) -> &mut FundingScope; + fn received_msg(&self) -> &'static str; fn check_counterparty_commitment_signature( &self, sig: &Signature, holder_commitment_point: &mut HolderCommitmentPoint, logger: &L ) -> Result where L::Target: Logger { - let funding_script = self.context().get_funding_redeemscript(); + let funding_script = self.funding().get_funding_redeemscript(); - let keys = self.context().build_holder_transaction_keys(holder_commitment_point.current_point()); + let keys = self.context().build_holder_transaction_keys(&self.funding(), holder_commitment_point.current_point()); let initial_commitment_tx = self.context().build_commitment_transaction(self.funding(), holder_commitment_point.transaction_number(), &keys, true, false, logger).tx; let trusted_tx = initial_commitment_tx.trust(); let initial_commitment_bitcoin_tx = trusted_tx.built_transaction(); let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.funding().channel_value_satoshis); // They sign the holder commitment transaction... log_trace!(logger, "Checking {} tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.", - self.received_msg(), log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context().counterparty_funding_pubkey().serialize()), + self.received_msg(), log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.funding().counterparty_funding_pubkey().serialize()), encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]), encode::serialize_hex(&funding_script), &self.context().channel_id()); - secp_check!(self.context().secp_ctx.verify_ecdsa(&sighash, sig, self.context().counterparty_funding_pubkey()), format!("Invalid {} signature from peer", self.received_msg())); + secp_check!(self.context().secp_ctx.verify_ecdsa(&sighash, sig, self.funding().counterparty_funding_pubkey()), format!("Invalid {} signature from peer", self.received_msg())); Ok(initial_commitment_tx) } @@ -2019,8 +2060,8 @@ trait InitialRemoteCommitmentReceiver where SP::Target: SignerProvide Ok(res) => res, Err(ChannelError::Close(e)) => { // TODO(dual_funding): Update for V2 established channels. - if !self.context().is_outbound() { - self.context_mut().channel_transaction_parameters.funding_outpoint = None; + if !self.funding().is_outbound() { + self.funding_mut().channel_transaction_parameters.funding_outpoint = None; } return Err(ChannelError::Close(e)); }, @@ -2031,7 +2072,7 @@ trait InitialRemoteCommitmentReceiver where SP::Target: SignerProvide } }; let context = self.context(); - let counterparty_keys = context.build_remote_transaction_keys(); + let counterparty_keys = context.build_remote_transaction_keys(self.funding()); let counterparty_initial_commitment_tx = context.build_commitment_transaction(self.funding(), context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx; let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust(); let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction(); @@ -2043,8 +2084,8 @@ trait InitialRemoteCommitmentReceiver where SP::Target: SignerProvide initial_commitment_tx, counterparty_signature, Vec::new(), - &context.get_holder_pubkeys().funding_pubkey, - context.counterparty_funding_pubkey() + &self.funding().get_holder_pubkeys().funding_pubkey, + &self.funding().counterparty_funding_pubkey() ); if context.holder_signer.as_ref().validate_holder_commitment(&holder_commitment_tx, Vec::new()).is_err() { @@ -2072,20 +2113,21 @@ trait InitialRemoteCommitmentReceiver where SP::Target: SignerProvide } let context = self.context(); - let funding_redeemscript = context.get_funding_redeemscript(); - let funding_txo = context.get_funding_txo().unwrap(); + let funding = self.funding(); + let funding_redeemscript = funding.get_funding_redeemscript(); + let funding_txo = funding.get_funding_txo().unwrap(); let funding_txo_script = funding_redeemscript.to_p2wsh(); - let obscure_factor = get_commitment_transaction_number_obscure_factor(&context.get_holder_pubkeys().payment_point, &context.get_counterparty_pubkeys().payment_point, context.is_outbound()); + let obscure_factor = get_commitment_transaction_number_obscure_factor(&funding.get_holder_pubkeys().payment_point, &funding.get_counterparty_pubkeys().payment_point, funding.is_outbound()); let shutdown_script = context.shutdown_scriptpubkey.clone().map(|script| script.into_inner()); - let mut monitor_signer = signer_provider.derive_channel_signer(self.funding().channel_value_satoshis, context.channel_keys_id); - monitor_signer.provide_channel_parameters(&context.channel_transaction_parameters); + let mut monitor_signer = signer_provider.derive_channel_signer(funding.channel_value_satoshis, context.channel_keys_id); + monitor_signer.provide_channel_parameters(&funding.channel_transaction_parameters); // TODO(RBF): When implementing RBF, the funding_txo passed here must only update // ChannelMonitorImp::first_confirmed_funding_txo during channel establishment, not splicing let channel_monitor = ChannelMonitor::new(context.secp_ctx.clone(), monitor_signer, - shutdown_script, context.get_holder_selected_contest_delay(), + shutdown_script, funding.get_holder_selected_contest_delay(), &context.destination_script, (funding_txo, funding_txo_script), - &context.channel_transaction_parameters, context.is_outbound(), - funding_redeemscript.clone(), self.funding().channel_value_satoshis, + &funding.channel_transaction_parameters, funding.is_outbound(), + funding_redeemscript.clone(), funding.channel_value_satoshis, obscure_factor, holder_commitment_tx, best_block, context.counterparty_node_id, context.channel_id()); channel_monitor.provide_initial_counterparty_commitment_tx( @@ -2116,6 +2158,10 @@ impl InitialRemoteCommitmentReceiver for OutboundV1Channel wh &self.funding } + fn funding_mut(&mut self) -> &mut FundingScope { + &mut self.funding + } + fn received_msg(&self) -> &'static str { "funding_signed" } @@ -2134,6 +2180,10 @@ impl InitialRemoteCommitmentReceiver for InboundV1Channel whe &self.funding } + fn funding_mut(&mut self) -> &mut FundingScope { + &mut self.funding + } + fn received_msg(&self) -> &'static str { "funding_created" } @@ -2152,6 +2202,10 @@ impl InitialRemoteCommitmentReceiver for FundedChannel where &self.funding } + fn funding_mut(&mut self) -> &mut FundingScope { + &mut self.funding + } + fn received_msg(&self) -> &'static str { "commitment_signed" } @@ -2238,7 +2292,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { let transaction_number = self.unfunded_context.transaction_number(); let mut output_index = None; - let expected_spk = self.context.get_funding_redeemscript().to_p2wsh(); + let expected_spk = self.funding.get_funding_redeemscript().to_p2wsh(); for (idx, outp) in signing_session.unsigned_tx.outputs().enumerate() { if outp.script_pubkey() == &expected_spk && outp.value() == self.funding.get_value_satoshis() { if output_index.is_some() { @@ -2260,8 +2314,8 @@ impl PendingV2Channel where SP::Target: SignerProvider { ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) }, ))); }; - self.context.channel_transaction_parameters.funding_outpoint = Some(outpoint); - self.context.holder_signer.as_mut().provide_channel_parameters(&self.context.channel_transaction_parameters); + self.funding.channel_transaction_parameters.funding_outpoint = Some(outpoint); + self.context.holder_signer.as_mut().provide_channel_parameters(&self.funding.channel_transaction_parameters); self.context.assert_no_commitment_advancement(transaction_number, "initial commitment_signed"); let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger); @@ -2271,7 +2325,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { commitment_signed }, Err(err) => { - self.context.channel_transaction_parameters.funding_outpoint = None; + self.funding.channel_transaction_parameters.funding_outpoint = None; return Err(ChannelError::Close((err.to_string(), ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) }))); }, }; @@ -2532,6 +2586,18 @@ impl ChannelContext where SP::Target: SignerProvider { next_local_commitment_tx_fee_info_cached: Mutex::new(None), #[cfg(any(test, fuzzing))] next_remote_commitment_tx_fee_info_cached: Mutex::new(None), + + channel_transaction_parameters: ChannelTransactionParameters { + holder_pubkeys: pubkeys, + holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay, + is_outbound_from_holder: false, + counterparty_parameters: Some(CounterpartyChannelTransactionParameters { + selected_contest_delay: open_channel_fields.to_self_delay, + pubkeys: counterparty_pubkeys, + }), + funding_outpoint: None, + channel_type_features: channel_type.clone() + }, }; let channel_context = ChannelContext { user_id, @@ -2613,17 +2679,6 @@ impl ChannelContext where SP::Target: SignerProvider { counterparty_forwarding_info: None, - channel_transaction_parameters: ChannelTransactionParameters { - holder_pubkeys: pubkeys, - holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay, - is_outbound_from_holder: false, - counterparty_parameters: Some(CounterpartyChannelTransactionParameters { - selected_contest_delay: open_channel_fields.to_self_delay, - pubkeys: counterparty_pubkeys, - }), - funding_outpoint: None, - channel_type_features: channel_type.clone() - }, funding_transaction: None, is_batch_funding: None, @@ -2769,6 +2824,15 @@ impl ChannelContext where SP::Target: SignerProvider { next_local_commitment_tx_fee_info_cached: Mutex::new(None), #[cfg(any(test, fuzzing))] next_remote_commitment_tx_fee_info_cached: Mutex::new(None), + + channel_transaction_parameters: ChannelTransactionParameters { + holder_pubkeys: pubkeys, + holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay, + is_outbound_from_holder: true, + counterparty_parameters: None, + funding_outpoint: None, + channel_type_features: channel_type.clone() + }, }; let channel_context = Self { user_id, @@ -2850,14 +2914,6 @@ impl ChannelContext where SP::Target: SignerProvider { counterparty_forwarding_info: None, - channel_transaction_parameters: ChannelTransactionParameters { - holder_pubkeys: pubkeys, - holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay, - is_outbound_from_holder: true, - counterparty_parameters: None, - funding_outpoint: None, - channel_type_features: channel_type.clone() - }, funding_transaction: None, is_batch_funding: None, @@ -2911,10 +2967,6 @@ impl ChannelContext where SP::Target: SignerProvider { self.config.announce_for_forwarding } - pub fn is_outbound(&self) -> bool { - self.channel_transaction_parameters.is_outbound_from_holder - } - /// Gets the fee we'd want to charge for adding an HTLC output to this Channel /// Allowed in any state (including after shutdown) pub fn get_outbound_forwarding_fee_base_msat(&self) -> u32 { @@ -3092,12 +3144,6 @@ impl ChannelContext where SP::Target: SignerProvider { self.outbound_scid_alias = outbound_scid_alias; } - /// Returns the funding_txo we either got from our peer, or were given by - /// get_funding_created. - pub fn get_funding_txo(&self) -> Option { - self.channel_transaction_parameters.funding_outpoint - } - /// Returns the height in which our funding transaction was confirmed. pub fn get_funding_tx_confirmation_height(&self) -> Option { let conf_height = self.funding_tx_confirmation_height; @@ -3118,7 +3164,7 @@ impl ChannelContext where SP::Target: SignerProvider { let peer_limits = if let Some(ref limits) = self.inbound_handshake_limits_override { limits } else { default_limits }; // Check sanity of message fields: - if !self.is_outbound() { + if !funding.is_outbound() { return Err(ChannelError::close("Got an accept_channel message from an inbound peer".to_owned())); } if !matches!(self.channel_state, ChannelState::NegotiatingFunding(flags) if flags == NegotiatingFundingFlags::OUR_INIT_SENT) { @@ -3187,7 +3233,7 @@ impl ChannelContext where SP::Target: SignerProvider { return Err(ChannelError::close("Only static_remote_key is supported for non-negotiated channel types".to_owned())); } self.channel_type = channel_type.clone(); - self.channel_transaction_parameters.channel_type_features = channel_type; + funding.channel_transaction_parameters.channel_type_features = channel_type; } let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() { @@ -3230,7 +3276,7 @@ impl ChannelContext where SP::Target: SignerProvider { htlc_basepoint: HtlcBasepoint::from(common_fields.htlc_basepoint) }; - self.channel_transaction_parameters.counterparty_parameters = Some(CounterpartyChannelTransactionParameters { + funding.channel_transaction_parameters.counterparty_parameters = Some(CounterpartyChannelTransactionParameters { selected_contest_delay: common_fields.to_self_delay, pubkeys: counterparty_pubkeys, }); @@ -3261,23 +3307,6 @@ impl ChannelContext where SP::Target: SignerProvider { height.checked_sub(self.funding_tx_confirmation_height).map_or(0, |c| c + 1) } - fn get_holder_selected_contest_delay(&self) -> u16 { - self.channel_transaction_parameters.holder_selected_contest_delay - } - - fn get_holder_pubkeys(&self) -> &ChannelPublicKeys { - &self.channel_transaction_parameters.holder_pubkeys - } - - pub fn get_counterparty_selected_contest_delay(&self) -> Option { - self.channel_transaction_parameters.counterparty_parameters - .as_ref().map(|params| params.selected_contest_delay) - } - - fn get_counterparty_pubkeys(&self) -> &ChannelPublicKeys { - &self.channel_transaction_parameters.counterparty_parameters.as_ref().unwrap().pubkeys - } - /// Allowed in any state (including after shutdown) pub fn get_counterparty_node_id(&self) -> PublicKey { self.counterparty_node_id @@ -3455,9 +3484,9 @@ impl ChannelContext where SP::Target: SignerProvider { if match update_state { // Note that these match the inclusion criteria when scanning // pending_inbound_htlcs below. - FeeUpdateState::RemoteAnnounced => { debug_assert!(!self.is_outbound()); !generated_by_local }, - FeeUpdateState::AwaitingRemoteRevokeToAnnounce => { debug_assert!(!self.is_outbound()); !generated_by_local }, - FeeUpdateState::Outbound => { assert!(self.is_outbound()); generated_by_local }, + FeeUpdateState::RemoteAnnounced => { debug_assert!(!funding.is_outbound()); !generated_by_local }, + FeeUpdateState::AwaitingRemoteRevokeToAnnounce => { debug_assert!(!funding.is_outbound()); !generated_by_local }, + FeeUpdateState::Outbound => { assert!(funding.is_outbound()); generated_by_local }, } { feerate_per_kw = feerate; } @@ -3465,7 +3494,7 @@ impl ChannelContext where SP::Target: SignerProvider { log_trace!(logger, "Building commitment transaction number {} (really {} xor {}) for channel {} for {}, generated by {} with fee {}...", commitment_number, (INITIAL_COMMITMENT_NUMBER - commitment_number), - get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound()), + get_commitment_transaction_number_obscure_factor(&funding.get_holder_pubkeys().payment_point, &funding.get_counterparty_pubkeys().payment_point, funding.is_outbound()), &self.channel_id, if local { "us" } else { "remote" }, if generated_by_local { "us" } else { "remote" }, feerate_per_kw); @@ -3611,9 +3640,9 @@ impl ChannelContext where SP::Target: SignerProvider { broadcaster_max_commitment_tx_output.1 = cmp::max(broadcaster_max_commitment_tx_output.1, value_to_remote_msat as u64); } - let total_fee_sat = commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), &self.channel_transaction_parameters.channel_type_features); - let anchors_val = if self.channel_transaction_parameters.channel_type_features.supports_anchors_zero_fee_htlc_tx() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } as i64; - let (value_to_self, value_to_remote) = if self.is_outbound() { + let total_fee_sat = commit_tx_fee_sat(feerate_per_kw, included_non_dust_htlcs.len(), &funding.channel_transaction_parameters.channel_type_features); + let anchors_val = if funding.channel_transaction_parameters.channel_type_features.supports_anchors_zero_fee_htlc_tx() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } as i64; + let (value_to_self, value_to_remote) = if funding.is_outbound() { (value_to_self_msat / 1000 - anchors_val - total_fee_sat as i64, value_to_remote_msat / 1000) } else { (value_to_self_msat / 1000, value_to_remote_msat / 1000 - anchors_val - total_fee_sat as i64) @@ -3622,9 +3651,9 @@ impl ChannelContext where SP::Target: SignerProvider { let mut value_to_a = if local { value_to_self } else { value_to_remote }; let mut value_to_b = if local { value_to_remote } else { value_to_self }; let (funding_pubkey_a, funding_pubkey_b) = if local { - (self.get_holder_pubkeys().funding_pubkey, self.get_counterparty_pubkeys().funding_pubkey) + (funding.get_holder_pubkeys().funding_pubkey, funding.get_counterparty_pubkeys().funding_pubkey) } else { - (self.get_counterparty_pubkeys().funding_pubkey, self.get_holder_pubkeys().funding_pubkey) + (funding.get_counterparty_pubkeys().funding_pubkey, funding.get_holder_pubkeys().funding_pubkey) }; if value_to_a >= (broadcaster_dust_limit_satoshis as i64) { @@ -3642,8 +3671,8 @@ impl ChannelContext where SP::Target: SignerProvider { let num_nondust_htlcs = included_non_dust_htlcs.len(); let channel_parameters = - if local { self.channel_transaction_parameters.as_holder_broadcastable() } - else { self.channel_transaction_parameters.as_counterparty_broadcastable() }; + if local { funding.channel_transaction_parameters.as_holder_broadcastable() } + else { funding.channel_transaction_parameters.as_counterparty_broadcastable() }; let tx = CommitmentTransaction::new_with_auxiliary_htlc_data(commitment_number, value_to_a as u64, value_to_b as u64, @@ -3678,10 +3707,10 @@ impl ChannelContext where SP::Target: SignerProvider { /// our counterparty!) /// The result is a transaction which we can revoke broadcastership of (ie a "local" transaction) /// TODO Some magic rust shit to compile-time check this? - fn build_holder_transaction_keys(&self, per_commitment_point: PublicKey) -> TxCreationKeys { - let delayed_payment_base = &self.get_holder_pubkeys().delayed_payment_basepoint; - let htlc_basepoint = &self.get_holder_pubkeys().htlc_basepoint; - let counterparty_pubkeys = self.get_counterparty_pubkeys(); + fn build_holder_transaction_keys(&self, funding: &FundingScope, per_commitment_point: PublicKey) -> TxCreationKeys { + let delayed_payment_base = &funding.get_holder_pubkeys().delayed_payment_basepoint; + let htlc_basepoint = &funding.get_holder_pubkeys().htlc_basepoint; + let counterparty_pubkeys = funding.get_counterparty_pubkeys(); TxCreationKeys::derive_new(&self.secp_ctx, &per_commitment_point, delayed_payment_base, htlc_basepoint, &counterparty_pubkeys.revocation_basepoint, &counterparty_pubkeys.htlc_basepoint) } @@ -3690,25 +3719,14 @@ impl ChannelContext where SP::Target: SignerProvider { /// Creates a set of keys for build_commitment_transaction to generate a transaction which we /// will sign and send to our counterparty. /// If an Err is returned, it is a ChannelError::Close (for get_funding_created) - fn build_remote_transaction_keys(&self) -> TxCreationKeys { - let revocation_basepoint = &self.get_holder_pubkeys().revocation_basepoint; - let htlc_basepoint = &self.get_holder_pubkeys().htlc_basepoint; - let counterparty_pubkeys = self.get_counterparty_pubkeys(); + fn build_remote_transaction_keys(&self, funding: &FundingScope) -> TxCreationKeys { + let revocation_basepoint = &funding.get_holder_pubkeys().revocation_basepoint; + let htlc_basepoint = &funding.get_holder_pubkeys().htlc_basepoint; + let counterparty_pubkeys = funding.get_counterparty_pubkeys(); TxCreationKeys::derive_new(&self.secp_ctx, &self.counterparty_cur_commitment_point.unwrap(), &counterparty_pubkeys.delayed_payment_basepoint, &counterparty_pubkeys.htlc_basepoint, revocation_basepoint, htlc_basepoint) } - /// Gets the redeemscript for the funding transaction output (ie the funding transaction output - /// pays to get_funding_redeemscript().to_p2wsh()). - /// Panics if called before accept_channel/InboundV1Channel::new - pub fn get_funding_redeemscript(&self) -> ScriptBuf { - make_funding_redeemscript(&self.get_holder_pubkeys().funding_pubkey, self.counterparty_funding_pubkey()) - } - - fn counterparty_funding_pubkey(&self) -> &PublicKey { - &self.get_counterparty_pubkeys().funding_pubkey - } - pub fn get_feerate_sat_per_1000_weight(&self) -> u32 { self.feerate_per_kw } @@ -3960,7 +3978,7 @@ impl ChannelContext where SP::Target: SignerProvider { } else { 0 }; - if context.is_outbound() { + if funding.is_outbound() { // We should mind channel commit tx fee when computing how much of the available capacity // can be used in the next htlc. Mirrors the logic in send_htlc. // @@ -4098,10 +4116,10 @@ impl ChannelContext where SP::Target: SignerProvider { /// /// Dust HTLCs are excluded. fn next_local_commit_tx_fee_msat( - &self, _funding: &FundingScope, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>, + &self, funding: &FundingScope, htlc: HTLCCandidate, fee_spike_buffer_htlc: Option<()>, ) -> u64 { let context = &self; - assert!(context.is_outbound()); + assert!(funding.is_outbound()); let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.get_channel_type().supports_anchors_zero_fee_htlc_tx() { (0, 0) @@ -4188,7 +4206,7 @@ impl ChannelContext where SP::Target: SignerProvider { }, feerate: context.feerate_per_kw, }; - *_funding.next_local_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info); + *funding.next_local_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info); } res } @@ -4204,12 +4222,12 @@ impl ChannelContext where SP::Target: SignerProvider { /// /// Dust HTLCs are excluded. fn next_remote_commit_tx_fee_msat( - &self, _funding: &FundingScope, htlc: Option, fee_spike_buffer_htlc: Option<()>, + &self, funding: &FundingScope, htlc: Option, fee_spike_buffer_htlc: Option<()>, ) -> u64 { debug_assert!(htlc.is_some() || fee_spike_buffer_htlc.is_some(), "At least one of the options must be set"); let context = &self; - assert!(!context.is_outbound()); + assert!(!funding.is_outbound()); let (htlc_success_dust_limit, htlc_timeout_dust_limit) = if context.get_channel_type().supports_anchors_zero_fee_htlc_tx() { (0, 0) @@ -4284,7 +4302,7 @@ impl ChannelContext where SP::Target: SignerProvider { }, feerate: context.feerate_per_kw, }; - *_funding.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info); + *funding.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = Some(commitment_tx_info); } res } @@ -4315,9 +4333,9 @@ impl ChannelContext where SP::Target: SignerProvider { /// Returns the transaction ID if there is a pending funding transaction that is yet to be /// broadcast. - pub fn unbroadcasted_funding_txid(&self) -> Option { + pub fn unbroadcasted_funding_txid(&self, funding: &FundingScope) -> Option { self.if_unbroadcasted_funding(|| - self.channel_transaction_parameters.funding_outpoint.map(|txo| txo.txid) + funding.channel_transaction_parameters.funding_outpoint.map(|txo| txo.txid) ) } @@ -4328,8 +4346,8 @@ impl ChannelContext where SP::Target: SignerProvider { /// Returns the transaction ID if there is a pending batch funding transaction that is yet to be /// broadcast. - pub fn unbroadcasted_batch_funding_txid(&self) -> Option { - self.unbroadcasted_funding_txid().filter(|_| self.is_batch_funding()) + pub fn unbroadcasted_batch_funding_txid(&self, funding: &FundingScope) -> Option { + self.unbroadcasted_funding_txid(funding).filter(|_| self.is_batch_funding()) } /// Gets the latest commitment transaction and any dependent transactions for relay (forcing @@ -4356,7 +4374,7 @@ impl ChannelContext where SP::Target: SignerProvider { _ => {} } } - let monitor_update = if let Some(funding_txo) = self.get_funding_txo() { + let monitor_update = if let Some(funding_txo) = funding.get_funding_txo() { // If we haven't yet exchanged funding signatures (ie channel_state < AwaitingChannelReady), // returning a channel monitor update here would imply a channel monitor update before // we even registered the channel monitor to begin with, which is invalid. @@ -4374,7 +4392,7 @@ impl ChannelContext where SP::Target: SignerProvider { })) } else { None } } else { None }; - let unbroadcasted_batch_funding_txid = self.unbroadcasted_batch_funding_txid(); + let unbroadcasted_batch_funding_txid = self.unbroadcasted_batch_funding_txid(&funding); let unbroadcasted_funding_tx = self.unbroadcasted_funding(); self.channel_state = ChannelState::ShutdownComplete; @@ -4390,12 +4408,12 @@ impl ChannelContext where SP::Target: SignerProvider { counterparty_node_id: self.counterparty_node_id, unbroadcasted_funding_tx, is_manual_broadcast: self.is_manual_broadcast, - channel_funding_txo: self.get_funding_txo(), + channel_funding_txo: funding.get_funding_txo(), last_local_balance_msat: funding.value_to_self_msat, } } - /// Only allowed after [`Self::channel_transaction_parameters`] is set. + /// Only allowed after [`FundingScope::channel_transaction_parameters`] is set. fn get_funding_signed_msg( &mut self, logger: &L, counterparty_initial_commitment_tx: CommitmentTransaction ) -> Option where L::Target: Logger { @@ -4435,12 +4453,12 @@ impl ChannelContext where SP::Target: SignerProvider { /// of the channel type we tried, not of our ability to open any channel at all. We can see if a /// downgrade of channel features would be possible so that we can still open the channel. pub(crate) fn maybe_downgrade_channel_features( - &mut self, fee_estimator: &LowerBoundedFeeEstimator + &mut self, funding: &mut FundingScope, fee_estimator: &LowerBoundedFeeEstimator ) -> Result<(), ()> where F::Target: FeeEstimator { - if !self.is_outbound() || + if !funding.is_outbound() || !matches!( self.channel_state, ChannelState::NegotiatingFunding(flags) if flags == NegotiatingFundingFlags::OUR_INIT_SENT @@ -4464,13 +4482,13 @@ impl ChannelContext where SP::Target: SignerProvider { if self.channel_type.supports_anchors_zero_fee_htlc_tx() { self.channel_type.clear_anchors_zero_fee_htlc_tx(); self.feerate_per_kw = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee); - assert!(!self.channel_transaction_parameters.channel_type_features.supports_anchors_nonzero_fee_htlc_tx()); + assert!(!funding.channel_transaction_parameters.channel_type_features.supports_anchors_nonzero_fee_htlc_tx()); } else if self.channel_type.supports_scid_privacy() { self.channel_type.clear_scid_privacy(); } else { self.channel_type = ChannelTypeFeatures::only_static_remote_key(); } - self.channel_transaction_parameters.channel_type_features = self.channel_type.clone(); + funding.channel_transaction_parameters.channel_type_features = self.channel_type.clone(); Ok(()) } @@ -4491,7 +4509,7 @@ impl ChannelContext where SP::Target: SignerProvider { SP::Target: SignerProvider, L::Target: Logger { - let counterparty_keys = self.build_remote_transaction_keys(); + let counterparty_keys = self.build_remote_transaction_keys(funding); let counterparty_initial_commitment_tx = self.build_commitment_transaction( funding, self.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx; match self.holder_signer { @@ -4551,7 +4569,7 @@ impl ChannelContext where SP::Target: SignerProvider { #[cfg(all(test))] pub fn get_initial_counterparty_commitment_signature_for_test( - &mut self, funding: &FundingScope, logger: &L, channel_transaction_parameters: ChannelTransactionParameters, + &mut self, funding: &mut FundingScope, logger: &L, channel_transaction_parameters: ChannelTransactionParameters, counterparty_cur_commitment_point_override: PublicKey, ) -> Result where @@ -4559,7 +4577,7 @@ impl ChannelContext where SP::Target: SignerProvider { L::Target: Logger { self.counterparty_cur_commitment_point = Some(counterparty_cur_commitment_point_override); - self.channel_transaction_parameters = channel_transaction_parameters; + funding.channel_transaction_parameters = channel_transaction_parameters; self.get_initial_counterparty_commitment_signature(funding, logger) } } @@ -4800,7 +4818,7 @@ impl FundedChannel where 2 + // witness marker and flag 1 + // witness element count 4 + // 4 element lengths (2 sigs, multisig dummy, and witness script) - self.context.get_funding_redeemscript().len() as u64 + // funding witness script + self.funding.get_funding_redeemscript().len() as u64 + // funding witness script 2*(1 + 71); // two signatures + sighash type flags if let Some(spk) = a_scriptpubkey { ret += ((8+1) + // output values and script length @@ -4820,14 +4838,14 @@ impl FundedChannel where assert!(self.context.pending_update_fee.is_none()); let mut total_fee_satoshis = proposed_total_fee_satoshis; - let mut value_to_holder: i64 = (self.funding.value_to_self_msat as i64) / 1000 - if self.context.is_outbound() { total_fee_satoshis as i64 } else { 0 }; - let mut value_to_counterparty: i64 = ((self.funding.channel_value_satoshis * 1000 - self.funding.value_to_self_msat) as i64 / 1000) - if self.context.is_outbound() { 0 } else { total_fee_satoshis as i64 }; + let mut value_to_holder: i64 = (self.funding.value_to_self_msat as i64) / 1000 - if self.funding.is_outbound() { total_fee_satoshis as i64 } else { 0 }; + let mut value_to_counterparty: i64 = ((self.funding.channel_value_satoshis * 1000 - self.funding.value_to_self_msat) as i64 / 1000) - if self.funding.is_outbound() { 0 } else { total_fee_satoshis as i64 }; if value_to_holder < 0 { - assert!(self.context.is_outbound()); + assert!(self.funding.is_outbound()); total_fee_satoshis += (-value_to_holder) as u64; } else if value_to_counterparty < 0 { - assert!(!self.context.is_outbound()); + assert!(!self.funding.is_outbound()); total_fee_satoshis += (-value_to_counterparty) as u64; } @@ -4857,7 +4875,7 @@ impl FundedChannel where } fn funding_outpoint(&self) -> OutPoint { - self.context.channel_transaction_parameters.funding_outpoint.unwrap() + self.funding.channel_transaction_parameters.funding_outpoint.unwrap() } /// Claims an HTLC while we're disconnected from a peer, dropping the [`ChannelMonitorUpdate`] @@ -5156,7 +5174,7 @@ impl FundedChannel where debug_assert!(matches!( self.context.channel_state, ChannelState::AwaitingChannelReady(_) )); - self.context.channel_transaction_parameters.funding_outpoint = None; + self.funding.channel_transaction_parameters.funding_outpoint = None; self.context.channel_id = self.context.temporary_channel_id.expect( "temporary_channel_id should be set since unset_funding_info is only called on funded \ channels that were unfunded immediately beforehand" @@ -5313,11 +5331,11 @@ impl FundedChannel where // Check that the remote can afford to pay for this HTLC on-chain at the current // feerate_per_kw, while maintaining their channel reserve (as required by the spec). { - let remote_commit_tx_fee_msat = if self.context.is_outbound() { 0 } else { + let remote_commit_tx_fee_msat = if self.funding.is_outbound() { 0 } else { let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered); self.context.next_remote_commit_tx_fee_msat(&self.funding, Some(htlc_candidate), None) // Don't include the extra fee spike buffer HTLC in calculations }; - let anchor_outputs_value_msat = if !self.context.is_outbound() && self.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() { + let anchor_outputs_value_msat = if !self.funding.is_outbound() && self.context.get_channel_type().supports_anchors_zero_fee_htlc_tx() { ANCHOR_OUTPUT_VALUE_SATOSHI * 2 * 1000 } else { 0 @@ -5335,7 +5353,7 @@ impl FundedChannel where } else { 0 }; - if self.context.is_outbound() { + if self.funding.is_outbound() { // Check that they won't violate our local required channel reserve by adding this HTLC. let htlc_candidate = HTLCCandidate::new(msg.amount_msat, HTLCInitiator::RemoteOffered); let local_commit_tx_fee_msat = self.context.next_local_commit_tx_fee_msat(&self.funding, htlc_candidate, None); @@ -5492,9 +5510,9 @@ impl FundedChannel where return Err(ChannelError::close("Peer sent commitment_signed after we'd started exchanging closing_signeds".to_owned())); } - let funding_script = self.context.get_funding_redeemscript(); + let funding_script = self.funding.get_funding_redeemscript(); - let keys = self.context.build_holder_transaction_keys(self.holder_commitment_point.current_point()); + let keys = self.context.build_holder_transaction_keys(&self.funding, self.holder_commitment_point.current_point()); let commitment_stats = self.context.build_commitment_transaction(&self.funding, self.holder_commitment_point.transaction_number(), &keys, true, false, logger); let commitment_txid = { @@ -5504,9 +5522,9 @@ impl FundedChannel where log_trace!(logger, "Checking commitment tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}", log_bytes!(msg.signature.serialize_compact()[..]), - log_bytes!(self.context.counterparty_funding_pubkey().serialize()), encode::serialize_hex(&bitcoin_tx.transaction), + log_bytes!(self.funding.counterparty_funding_pubkey().serialize()), encode::serialize_hex(&bitcoin_tx.transaction), log_bytes!(sighash[..]), encode::serialize_hex(&funding_script), &self.context.channel_id()); - if let Err(_) = self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.context.counterparty_funding_pubkey()) { + if let Err(_) = self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.funding.counterparty_funding_pubkey()) { return Err(ChannelError::close("Invalid commitment tx signature from peer".to_owned())); } bitcoin_tx.txid @@ -5519,7 +5537,7 @@ impl FundedChannel where update_state == FeeUpdateState::RemoteAnnounced } else { false }; if update_fee { - debug_assert!(!self.context.is_outbound()); + debug_assert!(!self.funding.is_outbound()); let counterparty_reserve_we_require_msat = self.funding.holder_selected_channel_reserve_satoshis * 1000; if commitment_stats.remote_balance_msat < commitment_stats.total_fee_sat * 1000 + counterparty_reserve_we_require_msat { return Err(ChannelError::close("Funding remote cannot afford proposed new fee".to_owned())); @@ -5527,7 +5545,7 @@ impl FundedChannel where } #[cfg(any(test, fuzzing))] { - if self.context.is_outbound() { + if self.funding.is_outbound() { let projected_commit_tx_info = self.funding.next_local_commitment_tx_fee_info_cached.lock().unwrap().take(); *self.funding.next_remote_commitment_tx_fee_info_cached.lock().unwrap() = None; if let Some(info) = projected_commit_tx_info { @@ -5567,7 +5585,7 @@ impl FundedChannel where for (idx, (htlc, mut source_opt)) in htlcs_cloned.drain(..).enumerate() { if let Some(_) = htlc.transaction_output_index { let htlc_tx = chan_utils::build_htlc_transaction(&commitment_txid, commitment_stats.feerate_per_kw, - self.context.get_counterparty_selected_contest_delay().unwrap(), &htlc, &self.context.channel_type, + self.funding.get_counterparty_selected_contest_delay().unwrap(), &htlc, &self.context.channel_type, &keys.broadcaster_delayed_payment_key, &keys.revocation_key); let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &self.context.channel_type, &keys); @@ -5597,8 +5615,8 @@ impl FundedChannel where commitment_stats.tx, msg.signature, msg.htlc_signatures.clone(), - &self.context.get_holder_pubkeys().funding_pubkey, - self.context.counterparty_funding_pubkey() + &self.funding.get_holder_pubkeys().funding_pubkey, + self.funding.counterparty_funding_pubkey() ); self.context.holder_signer.as_ref().validate_holder_commitment(&holder_commitment_tx, commitment_stats.outbound_htlc_preimages) @@ -6063,15 +6081,15 @@ impl FundedChannel where if let Some((feerate, update_state)) = self.context.pending_update_fee { match update_state { FeeUpdateState::Outbound => { - debug_assert!(self.context.is_outbound()); + debug_assert!(self.funding.is_outbound()); log_trace!(logger, " ...promoting outbound fee update {} to Committed", feerate); self.context.feerate_per_kw = feerate; self.context.pending_update_fee = None; self.context.expecting_peer_commitment_signed = true; }, - FeeUpdateState::RemoteAnnounced => { debug_assert!(!self.context.is_outbound()); }, + FeeUpdateState::RemoteAnnounced => { debug_assert!(!self.funding.is_outbound()); }, FeeUpdateState::AwaitingRemoteRevokeToAnnounce => { - debug_assert!(!self.context.is_outbound()); + debug_assert!(!self.funding.is_outbound()); log_trace!(logger, " ...promoting inbound AwaitingRemoteRevokeToAnnounce fee update {} to Committed", feerate); require_commitment = true; self.context.feerate_per_kw = feerate; @@ -6245,7 +6263,7 @@ impl FundedChannel where ) -> Option where F::Target: FeeEstimator, L::Target: Logger { - if !self.context.is_outbound() { + if !self.funding.is_outbound() { panic!("Cannot send fee from inbound channel"); } if !self.context.is_usable() { @@ -6258,7 +6276,7 @@ impl FundedChannel where // Before proposing a feerate update, check that we can actually afford the new fee. let dust_exposure_limiting_feerate = self.context.get_dust_exposure_limiting_feerate(&fee_estimator); let htlc_stats = self.context.get_pending_htlc_stats(Some(feerate_per_kw), dust_exposure_limiting_feerate); - let keys = self.context.build_holder_transaction_keys(self.holder_commitment_point.current_point()); + let keys = self.context.build_holder_transaction_keys(&self.funding, self.holder_commitment_point.current_point()); let commitment_stats = self.context.build_commitment_transaction(&self.funding, self.holder_commitment_point.transaction_number(), &keys, true, true, logger); let buffer_fee_msat = commit_tx_fee_sat(feerate_per_kw, commitment_stats.num_nondust_htlcs + htlc_stats.on_holder_tx_outbound_holding_cell_htlcs_count as usize + CONCURRENT_INBOUND_HTLC_FEE_BUFFER as usize, self.context.get_channel_type()) * 1000; let holder_balance_msat = commitment_stats.local_balance_msat - htlc_stats.outbound_holding_cell_msat; @@ -6362,7 +6380,7 @@ impl FundedChannel where if let Some((_, update_state)) = self.context.pending_update_fee { if update_state == FeeUpdateState::RemoteAnnounced { - debug_assert!(!self.context.is_outbound()); + debug_assert!(!self.funding.is_outbound()); self.context.pending_update_fee = None; } } @@ -6434,7 +6452,7 @@ impl FundedChannel where // first received the funding_signed. let mut funding_broadcastable = None; if let Some(funding_transaction) = &self.context.funding_transaction { - if (self.context.is_outbound() || self.is_v2_established()) && + if (self.funding.is_outbound() || self.is_v2_established()) && (matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(flags) if !flags.is_set(AwaitingChannelReadyFlags::WAITING_FOR_BATCH)) || matches!(self.context.channel_state, ChannelState::ChannelReady(_))) { @@ -6452,7 +6470,7 @@ impl FundedChannel where // the funding transaction confirmed before the monitor was persisted, or // * a 0-conf channel and intended to send the channel_ready before any broadcast at all. let channel_ready = if self.context.monitor_pending_channel_ready { - assert!(!self.context.is_outbound() || self.context.minimum_depth == Some(0), + assert!(!self.funding.is_outbound() || self.context.minimum_depth == Some(0), "Funding transaction broadcast by the local client before it should have - LDK didn't do it!"); self.context.monitor_pending_channel_ready = false; self.get_channel_ready(logger) @@ -6514,7 +6532,7 @@ impl FundedChannel where } pub fn check_for_stale_feerate(&mut self, logger: &L, min_feerate: u32) -> Result<(), ClosureReason> { - if self.context.is_outbound() { + if self.funding.is_outbound() { // While its possible our fee is too low for an outbound channel because we've been // unable to increase the fee, we don't try to force-close directly here. return Ok(()); @@ -6536,7 +6554,7 @@ impl FundedChannel where pub fn update_fee(&mut self, fee_estimator: &LowerBoundedFeeEstimator, msg: &msgs::UpdateFee, logger: &L) -> Result<(), ChannelError> where F::Target: FeeEstimator, L::Target: Logger { - if self.context.is_outbound() { + if self.funding.is_outbound() { return Err(ChannelError::close("Non-funding remote tried to update channel fee".to_owned())); } if self.context.channel_state.is_peer_disconnected() { @@ -6571,8 +6589,8 @@ impl FundedChannel where log_trace!(logger, "Attempting to update holder per-commitment point..."); self.holder_commitment_point.try_resolve_pending(&self.context.holder_signer, &self.context.secp_ctx, logger); } - let funding_signed = if self.context.signer_pending_funding && !self.context.is_outbound() { - let counterparty_keys = self.context.build_remote_transaction_keys(); + let funding_signed = if self.context.signer_pending_funding && !self.funding.is_outbound() { + let counterparty_keys = self.context.build_remote_transaction_keys(&self.funding); let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(&self.funding, self.context.cur_counterparty_commitment_transaction_number + 1, &counterparty_keys, false, false, logger).tx; self.context.get_funding_signed_msg(logger, counterparty_initial_commitment_tx) } else { None }; @@ -6617,10 +6635,10 @@ impl FundedChannel where fee, fee_range.min_fee_satoshis, fee_range.max_fee_satoshis, logger); let signed_tx = if let (Some(ClosingSigned { signature, .. }), Some(counterparty_sig)) = (closing_signed.as_ref(), self.context.last_received_closing_sig) { - let funding_redeemscript = self.context.get_funding_redeemscript(); + let funding_redeemscript = self.funding.get_funding_redeemscript(); let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.funding.channel_value_satoshis); debug_assert!(self.context.secp_ctx.verify_ecdsa(&sighash, &counterparty_sig, - &self.context.get_counterparty_pubkeys().funding_pubkey).is_ok()); + &self.funding.get_counterparty_pubkeys().funding_pubkey).is_ok()); Some(self.build_signed_closing_transaction(&closing_tx, &counterparty_sig, signature)) } else { None }; let shutdown_result = signed_tx.as_ref().map(|_| self.shutdown_result_coop_close()); @@ -6748,7 +6766,7 @@ impl FundedChannel where } } - let update_fee = if self.context.is_outbound() && self.context.pending_update_fee.is_some() { + let update_fee = if self.funding.is_outbound() && self.context.pending_update_fee.is_some() { Some(msgs::UpdateFee { channel_id: self.context.channel_id(), feerate_per_kw: self.context.pending_update_fee.unwrap().0, @@ -7000,7 +7018,7 @@ impl FundedChannel where // Use NonAnchorChannelFee because this should be an estimate for a channel close // that we don't expect to need fee bumping let normal_feerate = fee_estimator.bounded_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee); - let mut proposed_max_feerate = if self.context.is_outbound() { normal_feerate } else { u32::max_value() }; + let mut proposed_max_feerate = if self.funding.is_outbound() { normal_feerate } else { u32::max_value() }; // The spec requires that (when the channel does not have anchors) we only send absolute // channel fees no greater than the absolute channel fee on the current commitment @@ -7009,7 +7027,7 @@ impl FundedChannel where // some force-closure by old nodes, but we wanted to close the channel anyway. if let Some(target_feerate) = self.context.target_closing_feerate_sats_per_kw { - let min_feerate = if self.context.is_outbound() { target_feerate } else { cmp::min(self.context.feerate_per_kw, target_feerate) }; + let min_feerate = if self.funding.is_outbound() { target_feerate } else { cmp::min(self.context.feerate_per_kw, target_feerate) }; proposed_feerate = cmp::max(proposed_feerate, min_feerate); proposed_max_feerate = cmp::max(proposed_max_feerate, min_feerate); } @@ -7023,7 +7041,7 @@ impl FundedChannel where // if the funders' output is dust we have to know the absolute fee we're going to use. let tx_weight = self.get_closing_transaction_weight(Some(&self.get_closing_scriptpubkey()), Some(self.context.counterparty_shutdown_scriptpubkey.as_ref().unwrap())); let proposed_total_fee_satoshis = proposed_feerate as u64 * tx_weight / 1000; - let proposed_max_total_fee_satoshis = if self.context.is_outbound() { + let proposed_max_total_fee_satoshis = if self.funding.is_outbound() { // We always add force_close_avoidance_max_fee_satoshis to our normal // feerate-calculated fee, but allow the max to be overridden if we're using a // target feerate-calculated fee. @@ -7072,7 +7090,7 @@ impl FundedChannel where return Ok((None, None, None)); } - if !self.context.is_outbound() { + if !self.funding.is_outbound() { if let Some(msg) = &self.context.pending_counterparty_closing_signed.take() { return self.closing_signed(fee_estimator, &msg, logger); } @@ -7247,8 +7265,8 @@ impl FundedChannel where tx.input[0].witness.push(Vec::new()); // First is the multisig dummy - let funding_key = self.context.get_holder_pubkeys().funding_pubkey.serialize(); - let counterparty_funding_key = self.context.counterparty_funding_pubkey().serialize(); + let funding_key = self.funding.get_holder_pubkeys().funding_pubkey.serialize(); + let counterparty_funding_key = self.funding.counterparty_funding_pubkey().serialize(); let mut holder_sig = sig.serialize_der().to_vec(); holder_sig.push(EcdsaSighashType::All as u8); let mut cp_sig = counterparty_sig.serialize_der().to_vec(); @@ -7261,7 +7279,7 @@ impl FundedChannel where tx.input[0].witness.push(holder_sig); } - tx.input[0].witness.push(self.context.get_funding_redeemscript().into_bytes()); + tx.input[0].witness.push(self.funding.get_funding_redeemscript().into_bytes()); tx } @@ -7303,14 +7321,14 @@ impl FundedChannel where closure_reason, monitor_update: None, dropped_outbound_htlcs: Vec::new(), - unbroadcasted_batch_funding_txid: self.context.unbroadcasted_batch_funding_txid(), + unbroadcasted_batch_funding_txid: self.context.unbroadcasted_batch_funding_txid(&self.funding), channel_id: self.context.channel_id, user_channel_id: self.context.user_id, channel_capacity_satoshis: self.funding.channel_value_satoshis, counterparty_node_id: self.context.counterparty_node_id, unbroadcasted_funding_tx: self.context.unbroadcasted_funding(), is_manual_broadcast: self.context.is_manual_broadcast, - channel_funding_txo: self.context.get_funding_txo(), + channel_funding_txo: self.funding.get_funding_txo(), last_local_balance_msat: self.funding.value_to_self_msat, } } @@ -7336,7 +7354,7 @@ impl FundedChannel where return Err(ChannelError::close("Remote tried to send us a closing tx with > 21 million BTC fee".to_owned())); } - if self.context.is_outbound() && self.context.last_sent_closing_fee.is_none() { + if self.funding.is_outbound() && self.context.last_sent_closing_fee.is_none() { return Err(ChannelError::close("Remote tried to send a closing_signed when we were supposed to propose the first one".to_owned())); } @@ -7345,7 +7363,7 @@ impl FundedChannel where return Ok((None, None, None)); } - let funding_redeemscript = self.context.get_funding_redeemscript(); + let funding_redeemscript = self.funding.get_funding_redeemscript(); let mut skip_remote_output = false; let (mut closing_tx, used_total_fee) = self.build_closing_transaction(msg.fee_satoshis, skip_remote_output)?; if used_total_fee != msg.fee_satoshis { @@ -7353,7 +7371,7 @@ impl FundedChannel where } let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.funding.channel_value_satoshis); - match self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.context.get_counterparty_pubkeys().funding_pubkey) { + match self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.funding.get_counterparty_pubkeys().funding_pubkey) { Ok(_) => {}, Err(_e) => { // The remote end may have decided to revoke their output due to inconsistent dust @@ -7361,7 +7379,7 @@ impl FundedChannel where skip_remote_output = true; closing_tx = self.build_closing_transaction(msg.fee_satoshis, skip_remote_output)?.0; let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.funding.channel_value_satoshis); - secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, self.context.counterparty_funding_pubkey()), "Invalid closing tx signature from peer".to_owned()); + secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, self.funding.counterparty_funding_pubkey()), "Invalid closing tx signature from peer".to_owned()); }, }; @@ -7423,7 +7441,7 @@ impl FundedChannel where return Err(ChannelError::Warn(format!("Unable to come to consensus about closing feerate, remote's min fee ({} sat) was greater than our max fee ({} sat)", min_fee_satoshis, our_max_fee))); } - if !self.context.is_outbound() { + if !self.funding.is_outbound() { // They have to pay, so pick the highest fee in the overlapping range. // We should never set an upper bound aside from their full balance debug_assert_eq!(our_max_fee, self.funding.channel_value_satoshis - (self.funding.value_to_self_msat + 999) / 1000); @@ -7565,7 +7583,7 @@ impl FundedChannel where let pending_remote_value_msat = self.funding.channel_value_satoshis * 1000 - pending_value_to_self_msat; - if !self.context.is_outbound() { + if !self.funding.is_outbound() { // `Some(())` is for the fee spike buffer we keep for the remote. This deviates from // the spec because the fee spike buffer requirement doesn't exist on the receiver's // side, only on the sender's. Note that with anchor outputs we are no longer as @@ -7716,7 +7734,7 @@ impl FundedChannel where // Because deciding we're awaiting initial broadcast spuriously could result in // funds-loss (as we don't have a monitor, but have the funding transaction confirmed), // we hard-assert here, even in production builds. - if self.context.is_outbound() { assert!(self.context.funding_transaction.is_some()); } + if self.funding.is_outbound() { assert!(self.context.funding_transaction.is_some()); } assert!(self.context.monitor_pending_channel_ready); assert_eq!(self.context.latest_monitor_update_id, 0); return true; @@ -7863,16 +7881,16 @@ impl FundedChannel where L::Target: Logger { let mut msgs = (None, None); - if let Some(funding_txo) = self.context.get_funding_txo() { + if let Some(funding_txo) = self.funding.get_funding_txo() { for &(index_in_block, tx) in txdata.iter() { // Check if the transaction is the expected funding transaction, and if it is, // check that it pays the right amount to the right script. if self.context.funding_tx_confirmation_height == 0 { if tx.compute_txid() == funding_txo.txid { let txo_idx = funding_txo.index as usize; - if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.context.get_funding_redeemscript().to_p2wsh() || + if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.funding.get_funding_redeemscript().to_p2wsh() || tx.output[txo_idx].value.to_sat() != self.funding.channel_value_satoshis { - if self.context.is_outbound() { + if self.funding.is_outbound() { // If we generated the funding transaction and it doesn't match what it // should, the client is really broken and we should just panic and // tell them off. That said, because hash collisions happen with high @@ -7885,7 +7903,7 @@ impl FundedChannel where let err_reason = "funding tx had wrong script/value or output index"; return Err(ClosureReason::ProcessingError { err: err_reason.to_owned() }); } else { - if self.context.is_outbound() { + if self.funding.is_outbound() { if !tx.is_coinbase() { for input in tx.input.iter() { if input.witness.is_empty() { @@ -8013,7 +8031,7 @@ impl FundedChannel where self.context.minimum_depth.unwrap(), funding_tx_confirmations); return Err(ClosureReason::ProcessingError { err: err_reason }); } - } else if !self.context.is_outbound() && self.context.funding_tx_confirmed_in.is_none() && + } else if !self.funding.is_outbound() && self.context.funding_tx_confirmed_in.is_none() && height >= self.context.channel_creation_height + FUNDING_CONF_DEADLINE_BLOCKS { log_info!(logger, "Closing channel {} due to funding timeout", &self.context.channel_id); // If funding_tx_confirmed_in is unset, the channel must not be active @@ -8092,8 +8110,8 @@ impl FundedChannel where short_channel_id, node_id_1: if were_node_one { node_id } else { counterparty_node_id }, node_id_2: if were_node_one { counterparty_node_id } else { node_id }, - bitcoin_key_1: NodeId::from_pubkey(if were_node_one { &self.context.get_holder_pubkeys().funding_pubkey } else { self.context.counterparty_funding_pubkey() }), - bitcoin_key_2: NodeId::from_pubkey(if were_node_one { self.context.counterparty_funding_pubkey() } else { &self.context.get_holder_pubkeys().funding_pubkey }), + bitcoin_key_1: NodeId::from_pubkey(if were_node_one { &self.funding.get_holder_pubkeys().funding_pubkey } else { self.funding.counterparty_funding_pubkey() }), + bitcoin_key_2: NodeId::from_pubkey(if were_node_one { self.funding.counterparty_funding_pubkey() } else { &self.funding.get_holder_pubkeys().funding_pubkey }), excess_data: Vec::new(), }; @@ -8218,10 +8236,10 @@ impl FundedChannel where "Bad announcement_signatures. Failed to verify node_signature. UnsignedChannelAnnouncement used for verification is {:?}. their_node_key is {:?}", &announcement, self.context.get_counterparty_node_id()))); } - if self.context.secp_ctx.verify_ecdsa(&msghash, &msg.bitcoin_signature, self.context.counterparty_funding_pubkey()).is_err() { + if self.context.secp_ctx.verify_ecdsa(&msghash, &msg.bitcoin_signature, self.funding.counterparty_funding_pubkey()).is_err() { return Err(ChannelError::close(format!( "Bad announcement_signatures. Failed to verify bitcoin_signature. UnsignedChannelAnnouncement used for verification is {:?}. their_bitcoin_key is ({:?})", - &announcement, self.context.counterparty_funding_pubkey()))); + &announcement, self.funding.counterparty_funding_pubkey()))); } self.context.announcement_sigs = Some((msg.node_signature, msg.bitcoin_signature)); @@ -8466,7 +8484,7 @@ impl FundedChannel where } if let Some((feerate, update_state)) = self.context.pending_update_fee { if update_state == FeeUpdateState::AwaitingRemoteRevokeToAnnounce { - debug_assert!(!self.context.is_outbound()); + debug_assert!(!self.funding.is_outbound()); log_trace!(logger, " ...promoting inbound AwaitingRemoteRevokeToAnnounce fee update {} to Committed", feerate); self.context.feerate_per_kw = feerate; self.context.pending_update_fee = None; @@ -8507,13 +8525,13 @@ impl FundedChannel where -> (Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>, CommitmentTransaction) where L::Target: Logger { - let counterparty_keys = self.context.build_remote_transaction_keys(); + let counterparty_keys = self.context.build_remote_transaction_keys(&self.funding); let commitment_stats = self.context.build_commitment_transaction(&self.funding, self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger); let counterparty_commitment_tx = commitment_stats.tx; #[cfg(any(test, fuzzing))] { - if !self.context.is_outbound() { + if !self.funding.is_outbound() { let projected_commit_tx_info = self.funding.next_remote_commitment_tx_fee_info_cached.lock().unwrap().take(); *self.funding.next_local_commitment_tx_fee_info_cached.lock().unwrap() = None; if let Some(info) = projected_commit_tx_info { @@ -8539,7 +8557,7 @@ impl FundedChannel where #[cfg(any(test, fuzzing))] self.build_commitment_no_state_update(logger); - let counterparty_keys = self.context.build_remote_transaction_keys(); + let counterparty_keys = self.context.build_remote_transaction_keys(&self.funding); let commitment_stats = self.context.build_commitment_transaction(&self.funding, self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, true, logger); let counterparty_commitment_txid = commitment_stats.tx.trust().txid(); @@ -8564,12 +8582,12 @@ impl FundedChannel where log_trace!(logger, "Signed remote commitment tx {} (txid {}) with redeemscript {} -> {} in channel {}", encode::serialize_hex(&commitment_stats.tx.trust().built_transaction().transaction), - &counterparty_commitment_txid, encode::serialize_hex(&self.context.get_funding_redeemscript()), + &counterparty_commitment_txid, encode::serialize_hex(&self.funding.get_funding_redeemscript()), log_bytes!(signature.serialize_compact()[..]), &self.context.channel_id()); for (ref htlc_sig, ref htlc) in htlc_signatures.iter().zip(htlcs) { log_trace!(logger, "Signed remote HTLC tx {} with redeemscript {} with pubkey {} -> {} in channel {}", - encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.context.get_holder_selected_contest_delay(), htlc, &self.context.channel_type, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)), + encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.funding.get_holder_selected_contest_delay(), htlc, &self.context.channel_type, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)), encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, &self.context.channel_type, &counterparty_keys)), log_bytes!(counterparty_keys.broadcaster_htlc_key.to_public_key().serialize()), log_bytes!(htlc_sig.serialize_compact()[..]), &self.context.channel_id()); @@ -8868,7 +8886,7 @@ impl FundedChannel where let is_holder_initiator = if self.context.channel_state.is_awaiting_quiescence() { // We were also planning to propose quiescence, let the tie-breaker decide the // initiator. - self.context.is_outbound() + self.funding.is_outbound() } else { false }; @@ -8880,7 +8898,7 @@ impl FundedChannel where // We already sent `stfu` and are now processing theirs. It may be in response to ours, or // we happened to both send `stfu` at the same time and a tie-break is needed. - let is_holder_quiescence_initiator = !msg.initiator || self.context.is_outbound(); + let is_holder_quiescence_initiator = !msg.initiator || self.funding.is_outbound(); self.context.is_holder_quiescence_initiator = Some(is_holder_quiescence_initiator); // We were expecting to receive `stfu` because we already sent ours. @@ -9020,9 +9038,9 @@ impl OutboundV1Channel where SP::Target: SignerProvider { Ok(chan) } - /// Only allowed after [`ChannelContext::channel_transaction_parameters`] is set. + /// Only allowed after [`FundingScope::channel_transaction_parameters`] is set. fn get_funding_created_msg(&mut self, logger: &L) -> Option where L::Target: Logger { - let counterparty_keys = self.context.build_remote_transaction_keys(); + let counterparty_keys = self.context.build_remote_transaction_keys(&self.funding); let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(&self.funding, self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx; let signature = match &self.context.holder_signer { // TODO (taproot|arik): move match into calling method for Taproot @@ -9045,8 +9063,8 @@ impl OutboundV1Channel where SP::Target: SignerProvider { signature.map(|signature| msgs::FundingCreated { temporary_channel_id: self.context.temporary_channel_id.unwrap(), - funding_txid: self.context.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().txid, - funding_output_index: self.context.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().index, + funding_txid: self.funding.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().txid, + funding_output_index: self.funding.channel_transaction_parameters.funding_outpoint.as_ref().unwrap().index, signature, #[cfg(taproot)] partial_signature_with_nonce: None, @@ -9064,7 +9082,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { /// If an Err is returned, it is a ChannelError::Close. pub fn get_funding_created(&mut self, funding_transaction: Transaction, funding_txo: OutPoint, is_batch_funding: bool, logger: &L) -> Result, (Self, ChannelError)> where L::Target: Logger { - if !self.context.is_outbound() { + if !self.funding.is_outbound() { panic!("Tried to create outbound funding_created message on an inbound channel!"); } if !matches!( @@ -9075,8 +9093,8 @@ impl OutboundV1Channel where SP::Target: SignerProvider { } self.context.assert_no_commitment_advancement(self.unfunded_context.transaction_number(), "funding_created"); - self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo); - self.context.holder_signer.as_mut().provide_channel_parameters(&self.context.channel_transaction_parameters); + self.funding.channel_transaction_parameters.funding_outpoint = Some(funding_txo); + self.context.holder_signer.as_mut().provide_channel_parameters(&self.funding.channel_transaction_parameters); // Now that we're past error-generating stuff, update our local state: @@ -9109,7 +9127,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { F::Target: FeeEstimator, L::Target: Logger, { - self.context.maybe_downgrade_channel_features(fee_estimator)?; + self.context.maybe_downgrade_channel_features(&mut self.funding, fee_estimator)?; self.get_open_channel(chain_hash, logger).ok_or(()) } @@ -9122,7 +9140,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { pub fn get_open_channel( &mut self, chain_hash: ChainHash, _logger: &L ) -> Option where L::Target: Logger { - if !self.context.is_outbound() { + if !self.funding.is_outbound() { panic!("Tried to open a channel for an inbound channel?"); } if self.context.have_received_message() { @@ -9144,7 +9162,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { return None; } }; - let keys = self.context.get_holder_pubkeys(); + let keys = self.funding.get_holder_pubkeys(); Some(msgs::OpenChannel { common_fields: msgs::CommonOpenChannelFields { @@ -9155,7 +9173,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat, htlc_minimum_msat: self.context.holder_htlc_minimum_msat, commitment_feerate_sat_per_1000_weight: self.context.feerate_per_kw as u32, - to_self_delay: self.context.get_holder_selected_contest_delay(), + to_self_delay: self.funding.get_holder_selected_contest_delay(), max_accepted_htlcs: self.context.holder_max_accepted_htlcs, funding_pubkey: keys.funding_pubkey, revocation_basepoint: keys.revocation_basepoint.to_public_key(), @@ -9194,7 +9212,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { where L::Target: Logger { - if !self.context.is_outbound() { + if !self.funding.is_outbound() { return Err((self, ChannelError::close("Received funding_signed for an inbound channel?".to_owned()))); } if !matches!(self.context.channel_state, ChannelState::FundingNegotiated) { @@ -9250,7 +9268,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { log_trace!(logger, "Attempting to generate open_channel..."); self.get_open_channel(chain_hash, logger) } else { None }; - let funding_created = if self.context.signer_pending_funding && self.context.is_outbound() { + let funding_created = if self.context.signer_pending_funding && self.funding.is_outbound() { log_trace!(logger, "Attempting to generate pending funding created..."); self.get_funding_created_msg(logger) } else { None }; @@ -9364,7 +9382,7 @@ impl InboundV1Channel where SP::Target: SignerProvider { pub fn accept_inbound_channel( &mut self, logger: &L ) -> Option where L::Target: Logger { - if self.context.is_outbound() { + if self.funding.is_outbound() { panic!("Tried to send accept_channel for an outbound channel?"); } if !matches!( @@ -9399,7 +9417,7 @@ impl InboundV1Channel where SP::Target: SignerProvider { return None; } }; - let keys = self.context.get_holder_pubkeys(); + let keys = self.funding.get_holder_pubkeys(); Some(msgs::AcceptChannel { common_fields: msgs::CommonAcceptChannelFields { @@ -9408,7 +9426,7 @@ impl InboundV1Channel where SP::Target: SignerProvider { max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat, htlc_minimum_msat: self.context.holder_htlc_minimum_msat, minimum_depth: self.context.minimum_depth.unwrap(), - to_self_delay: self.context.get_holder_selected_contest_delay(), + to_self_delay: self.funding.get_holder_selected_contest_delay(), max_accepted_htlcs: self.context.holder_max_accepted_htlcs, funding_pubkey: keys.funding_pubkey, revocation_basepoint: keys.revocation_basepoint.to_public_key(), @@ -9445,7 +9463,7 @@ impl InboundV1Channel where SP::Target: SignerProvider { where L::Target: Logger { - if self.context.is_outbound() { + if self.funding.is_outbound() { return Err((self, ChannelError::close("Received funding_created for an outbound channel?".to_owned()))); } if !matches!( @@ -9464,10 +9482,10 @@ impl InboundV1Channel where SP::Target: SignerProvider { self.context.assert_no_commitment_advancement(holder_commitment_point.transaction_number(), "funding_created"); let funding_txo = OutPoint { txid: msg.funding_txid, index: msg.funding_output_index }; - self.context.channel_transaction_parameters.funding_outpoint = Some(funding_txo); + self.funding.channel_transaction_parameters.funding_outpoint = Some(funding_txo); // This is an externally observable change before we finish all our checks. In particular // check_funding_created_signature may fail. - self.context.holder_signer.as_mut().provide_channel_parameters(&self.context.channel_transaction_parameters); + self.context.holder_signer.as_mut().provide_channel_parameters(&self.funding.channel_transaction_parameters); let (channel_monitor, counterparty_initial_commitment_tx) = match self.initial_commitment_signed( ChannelId::v1_from_funding_outpoint(funding_txo), msg.signature, @@ -9608,12 +9626,12 @@ impl PendingV2Channel where SP::Target: SignerProvider { where F::Target: FeeEstimator { - self.context.maybe_downgrade_channel_features(fee_estimator)?; + self.context.maybe_downgrade_channel_features(&mut self.funding, fee_estimator)?; Ok(self.get_open_channel_v2(chain_hash)) } pub fn get_open_channel_v2(&self, chain_hash: ChainHash) -> msgs::OpenChannelV2 { - if !self.context.is_outbound() { + if !self.funding.is_outbound() { debug_assert!(false, "Tried to send open_channel2 for an inbound channel?"); } @@ -9633,7 +9651,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { .get_per_commitment_point(self.unfunded_context.transaction_number() - 1, &self.context.secp_ctx) .expect("TODO: async signing is not yet supported for commitment points in v2 channel establishment"); - let keys = self.context.get_holder_pubkeys(); + let keys = self.funding.get_holder_pubkeys(); msgs::OpenChannelV2 { common_fields: msgs::CommonOpenChannelFields { @@ -9644,7 +9662,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat, htlc_minimum_msat: self.context.holder_htlc_minimum_msat, commitment_feerate_sat_per_1000_weight: self.context.feerate_per_kw, - to_self_delay: self.context.get_holder_selected_contest_delay(), + to_self_delay: self.funding.get_holder_selected_contest_delay(), max_accepted_htlcs: self.context.holder_max_accepted_htlcs, funding_pubkey: keys.funding_pubkey, revocation_basepoint: keys.revocation_basepoint.to_public_key(), @@ -9728,8 +9746,8 @@ impl PendingV2Channel where SP::Target: SignerProvider { msg.common_fields.clone(), )?; let channel_id = ChannelId::v2_from_revocation_basepoints( - &context.get_holder_pubkeys().revocation_basepoint, - &context.get_counterparty_pubkeys().revocation_basepoint); + &funding.get_holder_pubkeys().revocation_basepoint, + &funding.get_counterparty_pubkeys().revocation_basepoint); context.channel_id = channel_id; let dual_funding_context = DualFundingChannelContext { @@ -9750,7 +9768,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { is_initiator: false, inputs_to_contribute: our_funding_inputs, outputs_to_contribute: Vec::new(), - expected_remote_shared_funding_output: Some((context.get_funding_redeemscript().to_p2wsh(), funding.channel_value_satoshis)), + expected_remote_shared_funding_output: Some((funding.get_funding_redeemscript().to_p2wsh(), funding.channel_value_satoshis)), } ).map_err(|_| ChannelError::Close(( "V2 channel rejected due to sender error".into(), @@ -9777,7 +9795,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { /// [`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() { + if self.funding.is_outbound() { debug_assert!(false, "Tried to send accept_channel for an outbound channel?"); } if !matches!( @@ -9806,7 +9824,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { let second_per_commitment_point = self.context.holder_signer.as_ref().get_per_commitment_point( self.unfunded_context.transaction_number() - 1, &self.context.secp_ctx) .expect("TODO: async signing is not yet supported for commitment points in v2 channel establishment"); - let keys = self.context.get_holder_pubkeys(); + let keys = self.funding.get_holder_pubkeys(); msgs::AcceptChannelV2 { common_fields: msgs::CommonAcceptChannelFields { @@ -9815,7 +9833,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat, htlc_minimum_msat: self.context.holder_htlc_minimum_msat, minimum_depth: self.context.minimum_depth.unwrap(), - to_self_delay: self.context.get_holder_selected_contest_delay(), + to_self_delay: self.funding.get_holder_selected_contest_delay(), max_accepted_htlcs: self.context.holder_max_accepted_htlcs, funding_pubkey: keys.funding_pubkey, revocation_basepoint: keys.revocation_basepoint.to_public_key(), @@ -10126,7 +10144,7 @@ impl Writeable for FundedChannel where SP::Target: SignerProvider fail_reason.write(writer)?; } - if self.context.is_outbound() { + if self.funding.is_outbound() { self.context.pending_update_fee.map(|(a, _)| a).write(writer)?; } else if let Some((feerate, FeeUpdateState::AwaitingRemoteRevokeToAnnounce)) = self.context.pending_update_fee { Some(feerate).write(writer)?; @@ -10176,7 +10194,7 @@ impl Writeable for FundedChannel where SP::Target: SignerProvider None => 0u8.write(writer)? } - self.context.channel_transaction_parameters.write(writer)?; + self.funding.channel_transaction_parameters.write(writer)?; self.context.funding_transaction.write(writer)?; self.context.counterparty_cur_commitment_point.write(writer)?; @@ -10762,6 +10780,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch next_local_commitment_tx_fee_info_cached: Mutex::new(None), #[cfg(any(test, fuzzing))] next_remote_commitment_tx_fee_info_cached: Mutex::new(None), + + channel_transaction_parameters: channel_parameters, }, context: ChannelContext { user_id, @@ -10840,7 +10860,6 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch counterparty_forwarding_info, - channel_transaction_parameters: channel_parameters, funding_transaction, is_batch_funding, @@ -11089,7 +11108,7 @@ mod tests { node_a_chan.context.holder_dust_limit_satoshis = 1560; // Node A --> Node B: funding created - let output_script = node_a_chan.context.get_funding_redeemscript(); + let output_script = node_a_chan.funding.get_funding_redeemscript(); let tx = Transaction { version: Version::ONE, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut { value: Amount::from_sat(10000000), script_pubkey: output_script.clone(), }]}; @@ -11136,7 +11155,7 @@ mod tests { // Finally, make sure that when Node A calculates the remote's commitment transaction fees, all // of the HTLCs are seen to be above the dust limit. - node_a_chan.context.channel_transaction_parameters.is_outbound_from_holder = false; + node_a_chan.funding.channel_transaction_parameters.is_outbound_from_holder = false; let remote_commit_fee_3_htlcs = commit_tx_fee_sat(node_a_chan.context.feerate_per_kw, 3, node_a_chan.context.get_channel_type()) * 1000; let htlc_candidate = HTLCCandidate::new(htlc_amount_msat, HTLCInitiator::LocalOffered); let remote_commit_tx_fee = node_a_chan.context.next_remote_commit_tx_fee_msat(&node_a_chan.funding, Some(htlc_candidate), None); @@ -11176,7 +11195,7 @@ mod tests { let commitment_tx_fee = chan.context.next_local_commit_tx_fee_msat(&chan.funding, htlc_candidate, None); assert_eq!(commitment_tx_fee, commitment_tx_fee_0_htlcs); - chan.context.channel_transaction_parameters.is_outbound_from_holder = false; + chan.funding.channel_transaction_parameters.is_outbound_from_holder = false; // If swapped: this HTLC would be counted as non-dust when it shouldn't be. let dust_htlc_amt_above_timeout = ((253 * htlc_timeout_tx_weight(chan.context.get_channel_type()) / 1000) + chan.context.counterparty_dust_limit_satoshis + 1) * 1000; @@ -11219,7 +11238,7 @@ mod tests { node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &channelmanager::provided_init_features(&config)).unwrap(); // Node A --> Node B: funding created - let output_script = node_a_chan.context.get_funding_redeemscript(); + let output_script = node_a_chan.funding.get_funding_redeemscript(); let tx = Transaction { version: Version::ONE, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut { value: Amount::from_sat(10000000), script_pubkey: output_script.clone(), }]}; @@ -11408,7 +11427,7 @@ mod tests { node_a_chan.context.holder_dust_limit_satoshis = 1560; // Node A --> Node B: funding created - let output_script = node_a_chan.context.get_funding_redeemscript(); + let output_script = node_a_chan.funding.get_funding_redeemscript(); let tx = Transaction { version: Version::ONE, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut { value: Amount::from_sat(10000000), script_pubkey: output_script.clone(), }]}; @@ -11478,7 +11497,7 @@ mod tests { ).unwrap(); outbound_chan.accept_channel(&inbound_chan.get_accept_channel_message(&&logger).unwrap(), &config.channel_handshake_limits, &features).unwrap(); let tx = Transaction { version: Version::ONE, lock_time: LockTime::ZERO, input: Vec::new(), output: vec![TxOut { - value: Amount::from_sat(10000000), script_pubkey: outbound_chan.context.get_funding_redeemscript(), + value: Amount::from_sat(10000000), script_pubkey: outbound_chan.funding.get_funding_redeemscript(), }]}; let funding_outpoint = OutPoint{ txid: tx.compute_txid(), index: 0 }; let funding_created = outbound_chan.get_funding_created(tx.clone(), funding_outpoint, false, &&logger).map_err(|_| ()).unwrap().unwrap(); @@ -11639,13 +11658,13 @@ mod tests { delayed_payment_basepoint: DelayedPaymentBasepoint::from(public_from_secret_hex(&secp_ctx, "1552dfba4f6cf29a62a0af13c8d6981d36d0ef8d61ba10fb0fe90da7634d7e13")), htlc_basepoint: HtlcBasepoint::from(public_from_secret_hex(&secp_ctx, "4444444444444444444444444444444444444444444444444444444444444444")) }; - chan.context.channel_transaction_parameters.counterparty_parameters = Some( + chan.funding.channel_transaction_parameters.counterparty_parameters = Some( CounterpartyChannelTransactionParameters { pubkeys: counterparty_pubkeys.clone(), selected_contest_delay: 144 }); - chan.context.channel_transaction_parameters.funding_outpoint = Some(funding_info); - signer.provide_channel_parameters(&chan.context.channel_transaction_parameters); + chan.funding.channel_transaction_parameters.funding_outpoint = Some(funding_info); + signer.provide_channel_parameters(&chan.funding.channel_transaction_parameters); assert_eq!(counterparty_pubkeys.payment_point.serialize()[..], >::from_hex("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]); @@ -11667,14 +11686,14 @@ mod tests { macro_rules! test_commitment { ( $counterparty_sig_hex: expr, $sig_hex: expr, $tx_hex: expr, $($remain:tt)* ) => { - chan.context.channel_transaction_parameters.channel_type_features = ChannelTypeFeatures::only_static_remote_key(); + chan.funding.channel_transaction_parameters.channel_type_features = ChannelTypeFeatures::only_static_remote_key(); test_commitment_common!($counterparty_sig_hex, $sig_hex, $tx_hex, &ChannelTypeFeatures::only_static_remote_key(), $($remain)*); }; } macro_rules! test_commitment_with_anchors { ( $counterparty_sig_hex: expr, $sig_hex: expr, $tx_hex: expr, $($remain:tt)* ) => { - chan.context.channel_transaction_parameters.channel_type_features = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(); + chan.funding.channel_transaction_parameters.channel_type_features = ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(); test_commitment_common!($counterparty_sig_hex, $sig_hex, $tx_hex, &ChannelTypeFeatures::anchors_zero_htlc_fee_and_dependencies(), $($remain)*); }; } @@ -11693,11 +11712,11 @@ mod tests { }; let trusted_tx = commitment_tx.trust(); let unsigned_tx = trusted_tx.built_transaction(); - let redeemscript = chan.context.get_funding_redeemscript(); + let redeemscript = chan.funding.get_funding_redeemscript(); let counterparty_signature = Signature::from_der(&>::from_hex($counterparty_sig_hex).unwrap()[..]).unwrap(); let sighash = unsigned_tx.get_sighash_all(&redeemscript, chan.funding.channel_value_satoshis); log_trace!(logger, "unsigned_tx = {}", serialize(&unsigned_tx.transaction).as_hex()); - assert!(secp_ctx.verify_ecdsa(&sighash, &counterparty_signature, chan.context.counterparty_funding_pubkey()).is_ok(), "verify counterparty commitment sig"); + assert!(secp_ctx.verify_ecdsa(&sighash, &counterparty_signature, chan.funding.counterparty_funding_pubkey()).is_ok(), "verify counterparty commitment sig"); let mut per_htlc: Vec<(HTLCOutputInCommitment, Option)> = Vec::new(); per_htlc.clear(); // Don't warn about excess mut for no-HTLC calls @@ -11715,12 +11734,12 @@ mod tests { counterparty_signature, counterparty_htlc_sigs, &chan.context.holder_signer.as_ref().pubkeys().funding_pubkey, - chan.context.counterparty_funding_pubkey() + chan.funding.counterparty_funding_pubkey() ); let holder_sig = signer.sign_holder_commitment(&holder_commitment_tx, &secp_ctx).unwrap(); assert_eq!(Signature::from_der(&>::from_hex($sig_hex).unwrap()[..]).unwrap(), holder_sig, "holder_sig"); - let funding_redeemscript = chan.context.get_funding_redeemscript(); + let funding_redeemscript = chan.funding.get_funding_redeemscript(); let tx = holder_commitment_tx.add_holder_sig(&funding_redeemscript, holder_sig); assert_eq!(serialize(&tx)[..], >::from_hex($tx_hex).unwrap()[..], "tx"); @@ -11733,7 +11752,7 @@ mod tests { let ref htlc = htlcs[$htlc_idx]; let mut htlc_tx = chan_utils::build_htlc_transaction(&unsigned_tx.txid, chan.context.feerate_per_kw, - chan.context.get_counterparty_selected_contest_delay().unwrap(), + chan.funding.get_counterparty_selected_contest_delay().unwrap(), &htlc, $opt_anchors, &keys.broadcaster_delayed_payment_key, &keys.revocation_key); let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, $opt_anchors, &keys); let htlc_sighashtype = if $opt_anchors.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All }; @@ -11757,7 +11776,7 @@ mod tests { channel_derivation_parameters: ChannelDerivationParameters { value_satoshis: chan.funding.channel_value_satoshis, keys_id: chan.context.channel_keys_id, - transaction_parameters: chan.context.channel_transaction_parameters.clone(), + transaction_parameters: chan.funding.channel_transaction_parameters.clone(), }, commitment_txid: trusted_tx.txid(), per_commitment_number: trusted_tx.commitment_number(), @@ -12602,7 +12621,7 @@ mod tests { ).unwrap(); // Fund the channel with a batch funding transaction. - let output_script = node_a_chan.context.get_funding_redeemscript(); + let output_script = node_a_chan.funding.get_funding_redeemscript(); let tx = Transaction { version: Version::ONE, lock_time: LockTime::ZERO, diff --git a/lightning/src/ln/channel_state.rs b/lightning/src/ln/channel_state.rs index 614160b5a30..2f7d08581ba 100644 --- a/lightning/src/ln/channel_state.rs +++ b/lightning/src/ln/channel_state.rs @@ -506,7 +506,7 @@ impl ChannelDetails { }, outbound_htlc_maximum_msat: context.get_counterparty_htlc_maximum_msat(funding), }, - funding_txo: context.get_funding_txo(), + funding_txo: funding.get_funding_txo(), // Note that accept_channel (or open_channel) is always the first message, so // `have_received_message` indicates that type negotiation has completed. channel_type: if context.have_received_message() { @@ -531,8 +531,8 @@ impl ChannelDetails { user_channel_id: context.get_user_id(), confirmations_required: context.minimum_depth(), confirmations: Some(context.get_funding_tx_confirmations(best_block_height)), - force_close_spend_delay: context.get_counterparty_selected_contest_delay(), - is_outbound: context.is_outbound(), + force_close_spend_delay: funding.get_counterparty_selected_contest_delay(), + is_outbound: funding.is_outbound(), is_channel_ready: context.is_usable(), is_usable: context.is_live(), is_announced: context.should_announce(), diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 1f12e51bf14..13593e54e7b 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -1429,7 +1429,7 @@ impl PeerState where SP::Target: SignerProvider { return false; } } - !self.channel_by_id.iter().any(|(_, channel)| channel.is_funded() || channel.context().is_outbound()) + !self.channel_by_id.iter().any(|(_, channel)| channel.is_funded() || channel.funding().is_outbound()) && self.monitor_update_blocked_actions.is_empty() && self.closed_channel_monitor_update_ids.is_empty() } @@ -3037,7 +3037,7 @@ macro_rules! handle_error { /// Note that this step can be skipped if the channel was never opened (through the creation of a /// [`ChannelMonitor`]/channel funding transaction) to begin with. macro_rules! locked_close_channel { - ($self: ident, $peer_state: expr, $channel_context: expr, $shutdown_res_mut: expr) => {{ + ($self: ident, $peer_state: expr, $channel_context: expr, $channel_funding: expr, $shutdown_res_mut: expr) => {{ if let Some((_, funding_txo, _, update)) = $shutdown_res_mut.monitor_update.take() { handle_new_monitor_update!($self, funding_txo, update, $peer_state, $channel_context, REMAIN_LOCKED_UPDATE_ACTIONS_PROCESSED_LATER); @@ -3051,7 +3051,7 @@ macro_rules! locked_close_channel { let chan_id = $channel_context.channel_id(); $peer_state.closed_channel_monitor_update_ids.insert(chan_id, update_id); } - if let Some(outpoint) = $channel_context.get_funding_txo() { + if let Some(outpoint) = $channel_funding.get_funding_txo() { $self.outpoint_to_peer.lock().unwrap().remove(&outpoint); } let mut short_to_chan_info = $self.short_to_chan_info.write().unwrap(); @@ -3088,7 +3088,7 @@ macro_rules! convert_channel_err { let logger = WithChannelContext::from(&$self.logger, &$context, None); log_error!(logger, "Closing channel {} due to close-required error: {}", $channel_id, msg); let mut shutdown_res = $context.force_shutdown($funding, true, reason); - locked_close_channel!($self, $peer_state, $context, &mut shutdown_res); + locked_close_channel!($self, $peer_state, $context, $funding, &mut shutdown_res); let err = MsgHandleErrInternal::from_finish_shutdown(msg, *$channel_id, shutdown_res, $channel_update); (true, err) @@ -3153,7 +3153,7 @@ macro_rules! remove_channel_entry { ($self: ident, $peer_state: expr, $entry: expr, $shutdown_res_mut: expr) => { { let channel = $entry.remove_entry().1; - locked_close_channel!($self, $peer_state, &channel.context(), $shutdown_res_mut); + locked_close_channel!($self, $peer_state, &channel.context(), channel.funding(), $shutdown_res_mut); channel } } @@ -3202,7 +3202,7 @@ macro_rules! emit_channel_pending_event { former_temporary_channel_id: $channel.context.temporary_channel_id(), counterparty_node_id: $channel.context.get_counterparty_node_id(), user_channel_id: $channel.context.get_user_id(), - funding_txo: $channel.context.get_funding_txo().unwrap().into_bitcoin_outpoint(), + funding_txo: $channel.funding.get_funding_txo().unwrap().into_bitcoin_outpoint(), channel_type: Some($channel.context.get_channel_type().clone()), }, None)); $channel.context.set_channel_pending_event_emitted(); @@ -3259,7 +3259,7 @@ macro_rules! handle_monitor_update_completion { } let channel_id = $chan.context.channel_id(); - let unbroadcasted_batch_funding_txid = $chan.context.unbroadcasted_batch_funding_txid(); + let unbroadcasted_batch_funding_txid = $chan.context.unbroadcasted_batch_funding_txid(&$chan.funding); core::mem::drop($peer_state_lock); core::mem::drop($per_peer_state_lock); @@ -3900,7 +3900,7 @@ where match peer_state.channel_by_id.entry(channel_id.clone()) { hash_map::Entry::Occupied(mut chan_entry) => { if let Some(chan) = chan_entry.get_mut().as_funded_mut() { - let funding_txo_opt = chan.context.get_funding_txo(); + let funding_txo_opt = chan.funding.get_funding_txo(); let their_features = &peer_state.latest_features; let (shutdown_msg, mut monitor_update_opt, htlcs) = chan.get_shutdown(&self.signer_provider, their_features, target_feerate_sats_per_1000_weight, override_shutdown_script)?; @@ -4105,7 +4105,7 @@ where let mut peer_state = peer_state_mutex.lock().unwrap(); if let Some(mut chan) = peer_state.channel_by_id.remove(&channel_id) { let mut close_res = chan.force_shutdown(false, ClosureReason::FundingBatchClosure); - locked_close_channel!(self, &mut *peer_state, chan.context(), close_res); + locked_close_channel!(self, &mut *peer_state, chan.context(), chan.funding(), close_res); shutdown_results.push(close_res); } } @@ -4617,7 +4617,7 @@ where if !chan.context.is_live() { return Err(APIError::ChannelUnavailable{err: "Peer for first hop currently disconnected".to_owned()}); } - let funding_txo = chan.context.get_funding_txo().unwrap(); + let funding_txo = chan.funding.get_funding_txo().unwrap(); let logger = WithChannelContext::from(&self.logger, &chan.context, Some(*payment_hash)); let send_res = chan.send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, HTLCSource::OutboundRoute { @@ -5357,7 +5357,7 @@ where is_batch_funding, |chan| { let mut output_index = None; - let expected_spk = chan.context.get_funding_redeemscript().to_p2wsh(); + let expected_spk = chan.funding.get_funding_redeemscript().to_p2wsh(); let outpoint = match &funding { FundingType::Checked(tx) => { for (idx, outp) in tx.output.iter().enumerate() { @@ -5408,7 +5408,7 @@ where .map(|(mut chan, mut peer_state)| { let closure_reason = ClosureReason::ProcessingError { err: e.clone() }; let mut close_res = chan.force_shutdown(false, closure_reason); - locked_close_channel!(self, peer_state, chan.context(), close_res); + locked_close_channel!(self, peer_state, chan.context(), chan.funding(), close_res); shutdown_results.push(close_res); peer_state.pending_msg_events.push(events::MessageSendEvent::HandleError { node_id: counterparty_node_id, @@ -5689,7 +5689,7 @@ where let incoming_channel_details_opt = self.do_funded_channel_callback(incoming_scid, |chan: &mut FundedChannel| { let counterparty_node_id = chan.context.get_counterparty_node_id(); let channel_id = chan.context.channel_id(); - let funding_txo = chan.context.get_funding_txo().unwrap(); + let funding_txo = chan.funding.get_funding_txo().unwrap(); let user_channel_id = chan.context.get_user_id(); let accept_underpaying_htlcs = chan.context.config().accept_underpaying_htlcs; (counterparty_node_id, channel_id, funding_txo, user_channel_id, accept_underpaying_htlcs) @@ -6480,7 +6480,7 @@ where } fn update_channel_fee(&self, chan_id: &ChannelId, chan: &mut FundedChannel, new_feerate: u32) -> NotifyOption { - if !chan.context.is_outbound() { return NotifyOption::SkipPersistNoEvents; } + if !chan.funding.is_outbound() { return NotifyOption::SkipPersistNoEvents; } let logger = WithChannelContext::from(&self.logger, &chan.context, None); @@ -6661,8 +6661,8 @@ where "Force-closing pending channel with ID {} for not establishing in a timely manner", context.channel_id()); let mut close_res = chan.force_shutdown(false, ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(false) }); - let context = chan.context_mut(); - locked_close_channel!(self, peer_state, context, close_res); + let (funding, context) = chan.funding_and_context_mut(); + locked_close_channel!(self, peer_state, context, funding, close_res); shutdown_channels.push(close_res); pending_msg_events.push(MessageSendEvent::HandleError { node_id: context.get_counterparty_node_id(), @@ -7606,7 +7606,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ if !pending_forwards.is_empty() { htlc_forwards = Some(( short_channel_id, Some(channel.context.get_counterparty_node_id()), - channel.context.get_funding_txo().unwrap(), channel.context.channel_id(), + channel.funding.get_funding_txo().unwrap(), channel.context.channel_id(), channel.context.get_user_id(), pending_forwards )); } @@ -7662,7 +7662,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ if channel.context.is_manual_broadcast() { log_info!(logger, "Not broadcasting funding transaction with txid {} as it is manually managed", tx.compute_txid()); let mut pending_events = self.pending_events.lock().unwrap(); - match channel.context.get_funding_txo() { + match channel.funding.get_funding_txo() { Some(funding_txo) => { emit_funding_tx_broadcast_safe_event!(pending_events, channel, funding_txo.into_bitcoin_outpoint()) }, @@ -7971,7 +7971,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ Some(funded_chan) => { // This covers non-zero-conf inbound `Channel`s that we are currently monitoring, but those // which have not yet had any confirmations on-chain. - if !funded_chan.context.is_outbound() && funded_chan.context.minimum_depth().unwrap_or(1) != 0 && + if !funded_chan.funding.is_outbound() && funded_chan.context.minimum_depth().unwrap_or(1) != 0 && funded_chan.context.get_funding_tx_confirmations(best_block_height) == 0 { num_unfunded_channels += 1; @@ -7979,7 +7979,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ }, None => { // Outbound channels don't contribute to the unfunded count in the DoS context. - if chan.context().is_outbound() { + if chan.funding().is_outbound() { continue; } @@ -8169,7 +8169,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ match chan.get_mut().as_unfunded_outbound_v1_mut() { Some(unfunded_chan) => { try_channel_entry!(self, peer_state, unfunded_chan.accept_channel(msg, &self.default_configuration.channel_handshake_limits, &peer_state.latest_features), chan); - (unfunded_chan.funding.get_value_satoshis(), unfunded_chan.context.get_funding_redeemscript().to_p2wsh(), unfunded_chan.context.get_user_id()) + (unfunded_chan.funding.get_value_satoshis(), unfunded_chan.funding.get_funding_redeemscript().to_p2wsh(), unfunded_chan.context.get_user_id()) }, None => { return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got an unexpected accept_channel message from peer with counterparty_node_id {}", counterparty_node_id), msg.common_fields.temporary_channel_id)); @@ -8692,7 +8692,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ if chan.sent_shutdown() { " after we initiated shutdown" } else { "" }); } - let funding_txo_opt = chan.context.get_funding_txo(); + let funding_txo_opt = chan.funding.get_funding_txo(); let (shutdown, monitor_update_opt, htlcs) = try_channel_entry!(self, peer_state, chan.shutdown(&self.signer_provider, &peer_state.latest_features, &msg), chan_entry); dropped_htlcs = htlcs; @@ -8865,7 +8865,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ // `ReleaseRAAChannelMonitorUpdate` action to the event generated when the // outbound HTLC is claimed. This is guaranteed to all complete before we // process the RAA as messages are processed from single peers serially. - funding_txo = chan.context.get_funding_txo().expect("We won't accept a fulfill until funded"); + funding_txo = chan.funding.get_funding_txo().expect("We won't accept a fulfill until funded"); next_user_channel_id = chan.context.get_user_id(); res } else { @@ -8952,7 +8952,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ hash_map::Entry::Occupied(mut chan_entry) => { let chan = chan_entry.get_mut(); let logger = WithChannelContext::from(&self.logger, &chan.context(), None); - let funding_txo = chan.context().get_funding_txo(); + let funding_txo = chan.funding().get_funding_txo(); let (monitor_opt, monitor_update_opt) = try_channel_entry!( self, peer_state, chan.commitment_signed(msg, best_block, &self.signer_provider, &&logger), chan_entry); @@ -9147,7 +9147,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ if let Some(chan) = peer_state.channel_by_id.get(&channel_id) { return self.raa_monitor_updates_held(&peer_state.actions_blocking_raa_monitor_updates, - chan.context().get_funding_txo().unwrap(), channel_id, counterparty_node_id); + chan.funding().get_funding_txo().unwrap(), channel_id, counterparty_node_id); } } false @@ -9166,7 +9166,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ hash_map::Entry::Occupied(mut chan_entry) => { if let Some(chan) = chan_entry.get_mut().as_funded_mut() { let logger = WithChannelContext::from(&self.logger, &chan.context, None); - let funding_txo_opt = chan.context.get_funding_txo(); + let funding_txo_opt = chan.funding.get_funding_txo(); let mon_update_blocked = if let Some(funding_txo) = funding_txo_opt { self.raa_monitor_updates_held( &peer_state.actions_blocking_raa_monitor_updates, funding_txo, msg.channel_id, @@ -9570,7 +9570,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ .filter_map(|(chan_id, chan)| chan.as_funded_mut().map(|chan| (chan_id, chan))) { let counterparty_node_id = chan.context.get_counterparty_node_id(); - let funding_txo = chan.context.get_funding_txo(); + let funding_txo = chan.funding.get_funding_txo(); let (monitor_opt, holding_cell_failed_htlcs) = chan.maybe_free_holding_cell_htlcs(&self.fee_estimator, &&WithChannelContext::from(&self.logger, &chan.context, None)); if !holding_cell_failed_htlcs.is_empty() { @@ -9707,9 +9707,10 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ }; if let Some(mut shutdown_result) = shutdown_result { let context = &chan.context(); + let funding = chan.funding(); let logger = WithChannelContext::from(&self.logger, context, None); log_trace!(logger, "Removing channel {} now that the signer is unblocked", context.channel_id()); - locked_close_channel!(self, peer_state, context, shutdown_result); + locked_close_channel!(self, peer_state, context, funding, shutdown_result); shutdown_results.push(shutdown_result); false } else { @@ -9751,7 +9752,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ } debug_assert_eq!(shutdown_result_opt.is_some(), funded_chan.is_shutdown()); if let Some(mut shutdown_result) = shutdown_result_opt { - locked_close_channel!(self, peer_state, &funded_chan.context, shutdown_result); + locked_close_channel!(self, peer_state, &funded_chan.context, &funded_chan.funding, shutdown_result); shutdown_results.push(shutdown_result); } if let Some(tx) = tx_opt { @@ -11001,7 +11002,7 @@ where if let hash_map::Entry::Occupied(mut chan_entry) = peer_state.channel_by_id.entry( channel_id) { if let Some(chan) = chan_entry.get_mut().as_funded_mut() { - debug_assert_eq!(chan.context.get_funding_txo().unwrap(), channel_funding_outpoint); + debug_assert_eq!(chan.funding.get_funding_txo().unwrap(), channel_funding_outpoint); if let Some((monitor_update, further_update_exists)) = chan.unblock_next_blocked_monitor_update() { log_debug!(logger, "Unlocking monitor updating for channel {} and updating monitor", channel_id); @@ -11300,7 +11301,7 @@ where let mut peer_state_lock = peer_state_mutex.lock().unwrap(); let peer_state = &mut *peer_state_lock; for chan in peer_state.channel_by_id.values().filter_map(Channel::as_funded) { - let txid_opt = chan.context.get_funding_txo(); + let txid_opt = chan.funding.get_funding_txo(); let height_opt = chan.context.get_funding_tx_confirmation_height(); let hash_opt = chan.context.get_funding_tx_confirmed_in(); if let (Some(funding_txo), Some(conf_height), Some(block_hash)) = (txid_opt, height_opt, hash_opt) { @@ -11316,7 +11317,7 @@ where PersistenceNotifierGuard::optionally_notify_skipping_background_events( self, || -> NotifyOption { NotifyOption::DoPersist }); self.do_chain_event(None, |channel| { - if let Some(funding_txo) = channel.context.get_funding_txo() { + if let Some(funding_txo) = channel.funding.get_funding_txo() { if funding_txo.txid == *txid { channel.funding_transaction_unconfirmed(&&WithChannelContext::from(&self.logger, &channel.context, None)).map(|()| (None, Vec::new(), None)) } else { Ok((None, Vec::new(), None)) } @@ -11451,7 +11452,7 @@ where // reorged out of the main chain. Close the channel. let reason_message = format!("{}", reason); let mut close_res = funded_channel.context.force_shutdown(&funded_channel.funding, true, reason); - locked_close_channel!(self, peer_state, &funded_channel.context, close_res); + locked_close_channel!(self, peer_state, &funded_channel.context, &funded_channel.funding, close_res); failed_channels.push(close_res); if let Ok(update) = self.get_channel_update_for_broadcast(&funded_channel) { let mut pending_broadcast_messages = self.pending_broadcast_messages.lock().unwrap(); @@ -11888,8 +11889,8 @@ where } // Clean up for removal. let mut close_res = chan.force_shutdown(false, ClosureReason::DisconnectedPeer); - let context = chan.context_mut(); - locked_close_channel!(self, peer_state, &context, close_res); + let (funding, context) = chan.funding_and_context_mut(); + locked_close_channel!(self, peer_state, &context, funding, close_res); failed_channels.push(close_res); false }); @@ -13638,7 +13639,7 @@ where let logger = WithChannelContext::from(&args.logger, &channel.context, None); let channel_id = channel.context.channel_id(); channel_id_set.insert(channel_id); - let funding_txo = channel.context.get_funding_txo().ok_or(DecodeError::InvalidValue)?; + let funding_txo = channel.funding.get_funding_txo().ok_or(DecodeError::InvalidValue)?; if let Some(ref mut monitor) = args.channel_monitors.get_mut(&channel_id) { if channel.get_cur_holder_commitment_transaction_number() > monitor.get_cur_holder_commitment_number() || channel.get_revoked_counterparty_commitment_transaction_number() > monitor.get_min_seen_secret() || @@ -13691,7 +13692,7 @@ where reason: ClosureReason::OutdatedChannelManager, counterparty_node_id: Some(channel.context.get_counterparty_node_id()), channel_capacity_sats: Some(channel.funding.get_value_satoshis()), - channel_funding_txo: channel.context.get_funding_txo(), + channel_funding_txo: channel.funding.get_funding_txo(), last_local_balance_msat: Some(channel.funding.get_value_to_self_msat()), }, None)); for (channel_htlc_source, payment_hash) in channel.inflight_htlc_sources() { @@ -13739,7 +13740,7 @@ where reason: ClosureReason::DisconnectedPeer, counterparty_node_id: Some(channel.context.get_counterparty_node_id()), channel_capacity_sats: Some(channel.funding.get_value_satoshis()), - channel_funding_txo: channel.context.get_funding_txo(), + channel_funding_txo: channel.funding.get_funding_txo(), last_local_balance_msat: Some(channel.funding.get_value_to_self_msat()), }, None)); } else { diff --git a/lightning/src/ln/dual_funding_tests.rs b/lightning/src/ln/dual_funding_tests.rs index e07f503e7f9..54bc7ee13dd 100644 --- a/lightning/src/ln/dual_funding_tests.rs +++ b/lightning/src/ln/dual_funding_tests.rs @@ -136,7 +136,9 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession) per_peer_state.get(&nodes[0].node.get_our_node_id()).unwrap().lock().unwrap(); let channel_context = peer_state.channel_by_id.get(&tx_complete_msg.channel_id).unwrap().context(); - (channel_context.get_funding_txo(), channel_context.get_channel_type().clone()) + let channel_funding = + peer_state.channel_by_id.get(&tx_complete_msg.channel_id).unwrap().funding(); + (channel_funding.get_funding_txo(), channel_context.get_channel_type().clone()) }; let channel_transaction_parameters = ChannelTransactionParameters { @@ -183,7 +185,7 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession) signature: channel .context .get_initial_counterparty_commitment_signature_for_test( - &channel.funding, + &mut channel.funding, &&logger_a, channel_transaction_parameters, accept_channel_v2_msg.common_fields.first_per_commitment_point, diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index ff0646bfa6c..618f5b0780a 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -769,7 +769,7 @@ fn test_update_fee_that_funder_cannot_afford() { commit_tx_keys.clone(), non_buffer_feerate + 4, &mut htlcs, - &local_chan.context.channel_transaction_parameters.as_counterparty_broadcastable() + &local_chan.funding.channel_transaction_parameters.as_counterparty_broadcastable() ); local_chan_signer.as_ecdsa().unwrap().sign_counterparty_commitment(&commitment_tx, Vec::new(), Vec::new(), &secp_ctx).unwrap() }; @@ -1512,7 +1512,7 @@ fn test_fee_spike_violation_fails_htlc() { commit_tx_keys.clone(), feerate_per_kw, &mut vec![(accepted_htlc_info, ())], - &local_chan.context.channel_transaction_parameters.as_counterparty_broadcastable() + &local_chan.funding.channel_transaction_parameters.as_counterparty_broadcastable() ); local_chan_signer.as_ecdsa().unwrap().sign_counterparty_commitment(&commitment_tx, Vec::new(), Vec::new(), &secp_ctx).unwrap() }; From fa867f35e02ad2573186ecc1c9e33d22beab1067 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 13 Feb 2025 16:24:30 -0600 Subject: [PATCH 03/20] Move funding_transaction to FundingScope Since the funding transactions changes for each new FudningScope, include it there instead of ChannelContext. --- lightning/src/ln/channel.rs | 37 +++++++++++++++--------------- lightning/src/ln/channelmanager.rs | 4 ++-- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index e799b74bf14..cc38ad3a203 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -1650,6 +1650,10 @@ pub(super) struct FundingScope { next_remote_commitment_tx_fee_info_cached: Mutex>, pub(super) channel_transaction_parameters: ChannelTransactionParameters, + + /// The transaction which funds this channel. Note that for manually-funded channels (i.e., + /// [`ChannelContext::is_manual_broadcast`] is true) this will be a dummy empty transaction. + funding_transaction: Option, } impl FundingScope { @@ -1902,9 +1906,6 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { counterparty_forwarding_info: Option, - /// The transaction which funds this channel. Note that for manually-funded channels (i.e., - /// is_manual_broadcast is true) this will be a dummy empty transaction. - funding_transaction: Option, /// This flag indicates that it is the user's responsibility to validated and broadcast the /// funding transaction. is_manual_broadcast: bool, @@ -2321,7 +2322,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger); let commitment_signed = match commitment_signed { Ok(commitment_signed) => { - self.context.funding_transaction = Some(signing_session.unsigned_tx.build_unsigned_tx()); + self.funding.funding_transaction = Some(signing_session.unsigned_tx.build_unsigned_tx()); commitment_signed }, Err(err) => { @@ -2598,6 +2599,7 @@ impl ChannelContext where SP::Target: SignerProvider { funding_outpoint: None, channel_type_features: channel_type.clone() }, + funding_transaction: None, }; let channel_context = ChannelContext { user_id, @@ -2679,7 +2681,6 @@ impl ChannelContext where SP::Target: SignerProvider { counterparty_forwarding_info: None, - funding_transaction: None, is_batch_funding: None, counterparty_cur_commitment_point: Some(open_channel_fields.first_per_commitment_point), @@ -2833,6 +2834,7 @@ impl ChannelContext where SP::Target: SignerProvider { funding_outpoint: None, channel_type_features: channel_type.clone() }, + funding_transaction: None, }; let channel_context = Self { user_id, @@ -2914,7 +2916,6 @@ impl ChannelContext where SP::Target: SignerProvider { counterparty_forwarding_info: None, - funding_transaction: None, is_batch_funding: None, counterparty_cur_commitment_point: None, @@ -4327,8 +4328,8 @@ impl ChannelContext where SP::Target: SignerProvider { /// /// Note that if [`Self::is_manual_broadcast`] is true the transaction will be a dummy /// transaction. - pub fn unbroadcasted_funding(&self) -> Option { - self.if_unbroadcasted_funding(|| self.funding_transaction.clone()) + pub fn unbroadcasted_funding(&self, funding: &FundingScope) -> Option { + self.if_unbroadcasted_funding(|| funding.funding_transaction.clone()) } /// Returns the transaction ID if there is a pending funding transaction that is yet to be @@ -4392,8 +4393,8 @@ impl ChannelContext where SP::Target: SignerProvider { })) } else { None } } else { None }; - let unbroadcasted_batch_funding_txid = self.unbroadcasted_batch_funding_txid(&funding); - let unbroadcasted_funding_tx = self.unbroadcasted_funding(); + let unbroadcasted_batch_funding_txid = self.unbroadcasted_batch_funding_txid(funding); + let unbroadcasted_funding_tx = self.unbroadcasted_funding(funding); self.channel_state = ChannelState::ShutdownComplete; self.update_time_counter += 1; @@ -6219,7 +6220,7 @@ impl FundedChannel where if funding_tx_opt.is_some() { // We have a finalized funding transaction, so we can set the funding transaction and reset the // signing session fields. - self.context.funding_transaction = funding_tx_opt; + self.funding.funding_transaction = funding_tx_opt; self.context.next_funding_txid = None; self.interactive_tx_signing_session = None; } @@ -6451,7 +6452,7 @@ impl FundedChannel where // try to (re-)broadcast the funding transaction as we may have declined to broadcast it when we // first received the funding_signed. let mut funding_broadcastable = None; - if let Some(funding_transaction) = &self.context.funding_transaction { + if let Some(funding_transaction) = &self.funding.funding_transaction { if (self.funding.is_outbound() || self.is_v2_established()) && (matches!(self.context.channel_state, ChannelState::AwaitingChannelReady(flags) if !flags.is_set(AwaitingChannelReadyFlags::WAITING_FOR_BATCH)) || matches!(self.context.channel_state, ChannelState::ChannelReady(_))) @@ -7326,7 +7327,7 @@ impl FundedChannel where user_channel_id: self.context.user_id, channel_capacity_satoshis: self.funding.channel_value_satoshis, counterparty_node_id: self.context.counterparty_node_id, - unbroadcasted_funding_tx: self.context.unbroadcasted_funding(), + unbroadcasted_funding_tx: self.context.unbroadcasted_funding(&self.funding), is_manual_broadcast: self.context.is_manual_broadcast, channel_funding_txo: self.funding.get_funding_txo(), last_local_balance_msat: self.funding.value_to_self_msat, @@ -7734,7 +7735,7 @@ impl FundedChannel where // Because deciding we're awaiting initial broadcast spuriously could result in // funds-loss (as we don't have a monitor, but have the funding transaction confirmed), // we hard-assert here, even in production builds. - if self.funding.is_outbound() { assert!(self.context.funding_transaction.is_some()); } + if self.funding.is_outbound() { assert!(self.funding.funding_transaction.is_some()); } assert!(self.context.monitor_pending_channel_ready); assert_eq!(self.context.latest_monitor_update_id, 0); return true; @@ -9109,8 +9110,8 @@ impl OutboundV1Channel where SP::Target: SignerProvider { self.context.minimum_depth = Some(COINBASE_MATURITY); } - debug_assert!(self.context.funding_transaction.is_none()); - self.context.funding_transaction = Some(funding_transaction); + debug_assert!(self.funding.funding_transaction.is_none()); + self.funding.funding_transaction = Some(funding_transaction); self.context.is_batch_funding = Some(()).filter(|_| is_batch_funding); let funding_created = self.get_funding_created_msg(logger); @@ -10195,7 +10196,7 @@ impl Writeable for FundedChannel where SP::Target: SignerProvider } self.funding.channel_transaction_parameters.write(writer)?; - self.context.funding_transaction.write(writer)?; + self.funding.funding_transaction.write(writer)?; self.context.counterparty_cur_commitment_point.write(writer)?; self.context.counterparty_prev_commitment_point.write(writer)?; @@ -10782,6 +10783,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch next_remote_commitment_tx_fee_info_cached: Mutex::new(None), channel_transaction_parameters: channel_parameters, + funding_transaction, }, context: ChannelContext { user_id, @@ -10860,7 +10862,6 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch counterparty_forwarding_info, - funding_transaction, is_batch_funding, counterparty_cur_commitment_point, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 13593e54e7b..1d81ec218ed 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -3296,7 +3296,7 @@ macro_rules! handle_monitor_update_completion { .get_mut(&channel_id) .and_then(Channel::as_funded_mut) { - batch_funding_tx = batch_funding_tx.or_else(|| funded_chan.context.unbroadcasted_funding()); + batch_funding_tx = batch_funding_tx.or_else(|| funded_chan.context.unbroadcasted_funding(&funded_chan.funding)); funded_chan.set_batch_ready(); let mut pending_events = $self.pending_events.lock().unwrap(); emit_channel_pending_event!(pending_events, funded_chan); @@ -8531,7 +8531,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ msg: tx_signatures, }); } - if let Some(ref funding_tx) = chan.context.unbroadcasted_funding() { + if let Some(ref funding_tx) = chan.context.unbroadcasted_funding(&chan.funding) { self.tx_broadcaster.broadcast_transactions(&[funding_tx]); { let mut pending_events = self.pending_events.lock().unwrap(); From e23d32dadd839ed4b095798c192691104a5aad99 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 25 Feb 2025 18:48:22 -0600 Subject: [PATCH 04/20] Remove InMemorySigner (de-)serialization support InMemorySigner no longer holds channel_value_satoshis and channel_parameters. Instead of writing 0 and None, respectively, drop (de-)serialization support entirely since InMemorySigner hasn't been serialized since SERIALIZATION_VERSION 2. --- fuzz/src/chanmon_consistency.rs | 13 +-- fuzz/src/full_stack.rs | 10 +- fuzz/src/onion_message.rs | 6 +- lightning/src/ln/channel.rs | 25 +---- lightning/src/ln/channelmanager.rs | 4 +- lightning/src/sign/mod.rs | 98 +------------------ lightning/src/util/test_channel_signer.rs | 13 --- lightning/src/util/test_utils.rs | 20 +--- ...04-upgrades-prior-to-113-not-supported.txt | 2 + 9 files changed, 12 insertions(+), 179 deletions(-) create mode 100644 pending_changelog/3604-upgrades-prior-to-113-not-supported.txt diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index c1bbf8c155e..acb78001d16 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -52,9 +52,7 @@ use lightning::ln::channelmanager::{ }; use lightning::ln::functional_test_utils::*; use lightning::ln::inbound_payment::ExpandedKey; -use lightning::ln::msgs::{ - ChannelMessageHandler, CommitmentUpdate, DecodeError, Init, UpdateAddHTLC, -}; +use lightning::ln::msgs::{ChannelMessageHandler, CommitmentUpdate, Init, UpdateAddHTLC}; use lightning::ln::script::ShutdownScript; use lightning::ln::types::ChannelId; use lightning::offers::invoice::UnsignedBolt12Invoice; @@ -385,15 +383,6 @@ impl SignerProvider for KeyProvider { TestChannelSigner::new_with_revoked(keys, revoked_commitment, false) } - fn read_chan_signer(&self, buffer: &[u8]) -> Result { - let mut reader = lightning::io::Cursor::new(buffer); - - let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?; - let state = self.make_enforcement_state_cell(inner.commitment_seed); - - Ok(TestChannelSigner::new_with_revoked(inner, state, false)) - } - fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result { let secp_ctx = Secp256k1::signing_only(); #[rustfmt::skip] diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 7b9a9ae1d00..804110bb038 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -44,7 +44,6 @@ use lightning::ln::channelmanager::{ }; use lightning::ln::functional_test_utils::*; use lightning::ln::inbound_payment::ExpandedKey; -use lightning::ln::msgs::DecodeError; use lightning::ln::peer_handler::{ IgnoringMessageHandler, MessageHandler, PeerManager, SocketDescriptor, }; @@ -63,7 +62,7 @@ use lightning::util::config::{ChannelConfig, UserConfig}; use lightning::util::errors::APIError; use lightning::util::hash_tables::*; use lightning::util::logger::Logger; -use lightning::util::ser::{Readable, ReadableArgs, Writeable}; +use lightning::util::ser::{Readable, Writeable}; use lightning::util::test_channel_signer::{EnforcementState, TestChannelSigner}; use lightning_invoice::RawBolt11Invoice; @@ -522,13 +521,6 @@ impl SignerProvider for KeyProvider { ) } - fn read_chan_signer(&self, mut data: &[u8]) -> Result { - let inner: InMemorySigner = ReadableArgs::read(&mut data, self)?; - let state = Arc::new(Mutex::new(EnforcementState::new())); - - Ok(TestChannelSigner::new_with_revoked(inner, state, false)) - } - fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result { let secp_ctx = Secp256k1::signing_only(); let channel_monitor_claim_key = SecretKey::from_slice( diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 10a667fb594..7f491c069d3 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -10,7 +10,7 @@ use lightning::blinded_path::message::{ }; use lightning::blinded_path::EmptyNodeIdLookUp; use lightning::ln::inbound_payment::ExpandedKey; -use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler}; +use lightning::ln::msgs::{self, OnionMessageHandler}; use lightning::ln::peer_handler::IgnoringMessageHandler; use lightning::ln::script::ShutdownScript; use lightning::offers::invoice::UnsignedBolt12Invoice; @@ -265,10 +265,6 @@ impl SignerProvider for KeyProvider { unreachable!() } - fn read_chan_signer(&self, _data: &[u8]) -> Result { - unreachable!() - } - fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result { unreachable!() } diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index cc38ad3a203..b223d84644e 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -10297,7 +10297,6 @@ impl Writeable for FundedChannel where SP::Target: SignerProvider } } -const MAX_ALLOC_SIZE: usize = 64*1024; impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c ChannelTypeFeatures)> for FundedChannel where ES::Target: EntropySource, @@ -10330,21 +10329,6 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch let latest_monitor_update_id = Readable::read(reader)?; - let mut keys_data = None; - if ver <= 2 { - // Read the serialize signer bytes. We'll choose to deserialize them or not based on whether - // the `channel_keys_id` TLV is present below. - let keys_len: u32 = Readable::read(reader)?; - keys_data = Some(Vec::with_capacity(cmp::min(keys_len as usize, MAX_ALLOC_SIZE))); - while keys_data.as_ref().unwrap().len() != keys_len as usize { - // Read 1KB at a time to avoid accidentally allocating 4GB on corrupted channel keys - let mut data = [0; 1024]; - let read_slice = &mut data[0..cmp::min(1024, keys_len as usize - keys_data.as_ref().unwrap().len())]; - reader.read_exact(read_slice)?; - keys_data.as_mut().unwrap().extend_from_slice(read_slice); - } - } - // Read the old serialization for shutdown_pubkey, preferring the TLV field later if set. let mut shutdown_scriptpubkey = match ::read(reader) { Ok(pubkey) => Some(ShutdownScript::new_p2wpkh_from_pubkey(pubkey)), @@ -10641,10 +10625,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch } (channel_keys_id, holder_signer) } else { - // `keys_data` can be `None` if we had corrupted data. - let keys_data = keys_data.ok_or(DecodeError::InvalidValue)?; - let holder_signer = signer_provider.read_chan_signer(&keys_data)?; - (holder_signer.channel_keys_id(), holder_signer) + return Err(DecodeError::InvalidValue); }; if let Some(preimages) = preimages_opt { @@ -10931,7 +10912,7 @@ mod tests { use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS}; use crate::types::features::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures}; use crate::ln::msgs; - use crate::ln::msgs::{ChannelUpdate, DecodeError, UnsignedChannelUpdate, MAX_VALUE_MSAT}; + use crate::ln::msgs::{ChannelUpdate, UnsignedChannelUpdate, MAX_VALUE_MSAT}; use crate::ln::script::ShutdownScript; use crate::ln::chan_utils::{self, htlc_success_tx_weight, htlc_timeout_tx_weight}; use crate::chain::BestBlock; @@ -11003,8 +10984,6 @@ mod tests { self.signer.clone() } - fn read_chan_signer(&self, _data: &[u8]) -> Result { panic!(); } - fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result { let secp_ctx = Secp256k1::signing_only(); let channel_monitor_claim_key = SecretKey::from_slice(&>::from_hex("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 1d81ec218ed..e4221cdd809 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -13488,8 +13488,8 @@ where pub node_signer: NS, /// The keys provider which will give us relevant keys. Some keys will be loaded during - /// deserialization and KeysInterface::read_chan_signer will be used to read per-Channel - /// signing data. + /// deserialization and [`SignerProvider::derive_channel_signer`] will be used to derive + /// per-Channel signing data. pub signer_provider: SP, /// The fee_estimator for use in the ChannelManager in the future. diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 3ba950f548d..095ce1b5c6d 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -58,12 +58,10 @@ use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage}; use crate::ln::script::ShutdownScript; use crate::offers::invoice::UnsignedBolt12Invoice; use crate::types::payment::PaymentPreimage; -use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; +use crate::util::ser::Writeable; use crate::util::transaction_utils; use crate::crypto::chacha20::ChaCha20; -use crate::io::{self, Error}; -use crate::ln::msgs::DecodeError; use crate::prelude::*; use crate::sign::ecdsa::EcdsaChannelSigner; #[cfg(taproot)] @@ -811,8 +809,7 @@ pub trait ChannelSigner { /// /// This data is static, and will never change for a channel once set. For a given [`ChannelSigner`] /// instance, LDK will call this method exactly once - either immediately after construction - /// (not including if done via [`SignerProvider::read_chan_signer`]) or when the funding - /// information has been generated. + /// or when the funding information has been generated. /// /// channel_parameters.is_populated() MUST be true. fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters); @@ -983,21 +980,6 @@ pub trait SignerProvider { &self, channel_value_satoshis: u64, channel_keys_id: [u8; 32], ) -> Self::EcdsaSigner; - /// Reads a [`Signer`] for this [`SignerProvider`] from the given input stream. - /// This is only called during deserialization of other objects which contain - /// [`EcdsaChannelSigner`]-implementing objects (i.e., [`ChannelMonitor`]s and [`ChannelManager`]s). - /// The bytes are exactly those which `::write()` writes, and - /// contain no versioning scheme. You may wish to include your own version prefix and ensure - /// you've read all of the provided bytes to ensure no corruption occurred. - /// - /// This method is slowly being phased out -- it will only be called when reading objects - /// written by LDK versions prior to 0.0.113. - /// - /// [`Signer`]: Self::EcdsaSigner - /// [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor - /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager - fn read_chan_signer(&self, reader: &[u8]) -> Result; - /// Get a script pubkey which we send funds to when claiming on-chain contestable outputs. /// /// If this function returns an error, this will result in a channel failing to open. @@ -1789,74 +1771,6 @@ impl TaprootChannelSigner for InMemorySigner { } } -const SERIALIZATION_VERSION: u8 = 1; - -const MIN_SERIALIZATION_VERSION: u8 = 1; - -impl Writeable for InMemorySigner { - fn write(&self, writer: &mut W) -> Result<(), Error> { - write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION); - - self.funding_key.write(writer)?; - self.revocation_base_key.write(writer)?; - self.payment_key.write(writer)?; - self.delayed_payment_base_key.write(writer)?; - self.htlc_base_key.write(writer)?; - self.commitment_seed.write(writer)?; - self.channel_parameters.write(writer)?; - self.channel_value_satoshis.write(writer)?; - self.channel_keys_id.write(writer)?; - - write_tlv_fields!(writer, {}); - - Ok(()) - } -} - -impl ReadableArgs for InMemorySigner -where - ES::Target: EntropySource, -{ - fn read(reader: &mut R, entropy_source: ES) -> Result { - let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION); - - let funding_key = Readable::read(reader)?; - let revocation_base_key = Readable::read(reader)?; - let payment_key = Readable::read(reader)?; - let delayed_payment_base_key = Readable::read(reader)?; - let htlc_base_key = Readable::read(reader)?; - let commitment_seed = Readable::read(reader)?; - let counterparty_channel_data = Readable::read(reader)?; - let channel_value_satoshis = Readable::read(reader)?; - let secp_ctx = Secp256k1::signing_only(); - let holder_channel_pubkeys = InMemorySigner::make_holder_keys( - &secp_ctx, - &funding_key, - &revocation_base_key, - &payment_key, - &delayed_payment_base_key, - &htlc_base_key, - ); - let keys_id = Readable::read(reader)?; - - read_tlv_fields!(reader, {}); - - Ok(InMemorySigner { - funding_key, - revocation_base_key, - payment_key, - delayed_payment_base_key, - htlc_base_key, - commitment_seed, - channel_value_satoshis, - holder_channel_pubkeys, - channel_parameters: counterparty_channel_data, - channel_keys_id: keys_id, - entropy_source: RandomBytes::new(entropy_source.get_secure_random_bytes()), - }) - } -} - /// Simple implementation of [`EntropySource`], [`NodeSigner`], and [`SignerProvider`] that takes a /// 32-byte seed for use as a BIP 32 extended key and derives keys from that. /// @@ -2295,10 +2209,6 @@ impl SignerProvider for KeysManager { self.derive_channel_keys(channel_value_satoshis, &channel_keys_id) } - fn read_chan_signer(&self, reader: &[u8]) -> Result { - InMemorySigner::read(&mut io::Cursor::new(reader), self) - } - fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result { Ok(self.destination_script.clone()) } @@ -2428,10 +2338,6 @@ impl SignerProvider for PhantomKeysManager { self.inner.derive_channel_signer(channel_value_satoshis, channel_keys_id) } - fn read_chan_signer(&self, reader: &[u8]) -> Result { - self.inner.read_chan_signer(reader) - } - fn get_destination_script(&self, channel_keys_id: [u8; 32]) -> Result { self.inner.get_destination_script(channel_keys_id) } diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 3bc095d2ba7..77dd34ffb88 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -31,14 +31,12 @@ use bitcoin::sighash; use bitcoin::sighash::EcdsaSighashType; use bitcoin::transaction::Transaction; -use crate::io::Error; #[cfg(taproot)] use crate::ln::msgs::PartialSignatureWithNonce; #[cfg(taproot)] use crate::sign::taproot::TaprootChannelSigner; use crate::sign::HTLCDescriptor; use crate::types::features::ChannelTypeFeatures; -use crate::util::ser::{Writeable, Writer}; use bitcoin::secp256k1; #[cfg(taproot)] use bitcoin::secp256k1::All; @@ -530,17 +528,6 @@ impl TaprootChannelSigner for TestChannelSigner { } } -impl Writeable for TestChannelSigner { - fn write(&self, writer: &mut W) -> Result<(), Error> { - // TestChannelSigner has two fields - `inner` ([`InMemorySigner`]) and `state` - // ([`EnforcementState`]). `inner` is serialized here and deserialized by - // [`SignerProvider::read_chan_signer`]. `state` is managed by [`SignerProvider`] - // and will be serialized as needed by the implementation of that trait. - self.inner.write(writer)?; - Ok(()) - } -} - impl TestChannelSigner { fn verify_counterparty_commitment_tx<'a, T: secp256k1::Signing + secp256k1::Verification>( &self, commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1, diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 9d02452010d..d50b796b87e 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -75,9 +75,7 @@ use lightning_invoice::RawBolt11Invoice; use crate::io; use crate::prelude::*; -use crate::sign::{ - EntropySource, InMemorySigner, NodeSigner, RandomBytes, Recipient, SignerProvider, -}; +use crate::sign::{EntropySource, NodeSigner, RandomBytes, Recipient, SignerProvider}; use crate::sync::{Arc, Mutex}; use core::cell::RefCell; use core::mem; @@ -370,13 +368,6 @@ impl SignerProvider for OnlyReadsKeysInterface { unreachable!(); } - fn read_chan_signer(&self, mut reader: &[u8]) -> Result { - let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?; - let state = Arc::new(Mutex::new(EnforcementState::new())); - - Ok(TestChannelSigner::new_with_revoked(inner, state, false)) - } - fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result { Err(()) } @@ -1580,15 +1571,6 @@ impl SignerProvider for TestKeysInterface { signer } - fn read_chan_signer(&self, buffer: &[u8]) -> Result { - let mut reader = io::Cursor::new(buffer); - - let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?; - let state = self.make_enforcement_state_cell(inner.commitment_seed); - - Ok(TestChannelSigner::new_with_revoked(inner, state, self.disable_revocation_policy_check)) - } - fn get_destination_script(&self, channel_keys_id: [u8; 32]) -> Result { self.backing.get_destination_script(channel_keys_id) } diff --git a/pending_changelog/3604-upgrades-prior-to-113-not-supported.txt b/pending_changelog/3604-upgrades-prior-to-113-not-supported.txt new file mode 100644 index 00000000000..94d622cda23 --- /dev/null +++ b/pending_changelog/3604-upgrades-prior-to-113-not-supported.txt @@ -0,0 +1,2 @@ +## API Updates (0.2) + * Upgrading from versions prior to 0.0.113 is no longer supported (#3604). From 21ed4778413af700c590b8aaa5e3a14855f38d08 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 19 Feb 2025 18:13:54 -0600 Subject: [PATCH 05/20] Include channel_value_satoshis in ChannelTransactionParameters Since channel_value_satoshis is needed by the signer and may change for each new FundingScope, included it in ChannelTransactionParameters so it can be passed to each signer call in the upcoming commits. --- lightning/src/chain/channelmonitor.rs | 16 ++++++++------ lightning/src/chain/onchaintx.rs | 5 +++-- lightning/src/events/bump_transaction.rs | 2 +- lightning/src/ln/chan_utils.rs | 28 ++++++++++++++++++------ lightning/src/ln/channel.rs | 10 ++++++--- lightning/src/ln/dual_funding_tests.rs | 1 + lightning/src/sign/mod.rs | 8 +++---- lightning/src/util/ser_macros.rs | 9 ++++++++ 8 files changed, 55 insertions(+), 24 deletions(-) diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 4ae10b949e2..0d3c6d1fe75 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -5421,7 +5421,8 @@ mod tests { selected_contest_delay: 67, }), funding_outpoint: Some(funding_outpoint), - channel_type_features: ChannelTypeFeatures::only_static_remote_key() + channel_type_features: ChannelTypeFeatures::only_static_remote_key(), + channel_value_satoshis: 0, }; // Prune with one old state and a holder commitment tx holding a few overlaps with the // old state. @@ -5430,11 +5431,11 @@ mod tests { let monitor = ChannelMonitor::new(Secp256k1::new(), keys, Some(ShutdownScript::new_p2wpkh_from_pubkey(shutdown_pubkey).into_inner()), 0, &ScriptBuf::new(), (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, ScriptBuf::new()), - &channel_parameters, true, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(&mut Vec::new()), + &channel_parameters, true, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(0, &mut Vec::new()), best_block, dummy_key, channel_id); let mut htlcs = preimages_slice_to_htlcs!(preimages[0..10]); - let dummy_commitment_tx = HolderCommitmentTransaction::dummy(&mut htlcs); + let dummy_commitment_tx = HolderCommitmentTransaction::dummy(0, &mut htlcs); monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx.clone(), htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), None)).collect()).unwrap(); @@ -5473,7 +5474,7 @@ mod tests { // Now update holder commitment tx info, pruning only element 18 as we still care about the // previous commitment tx's preimages too let mut htlcs = preimages_slice_to_htlcs!(preimages[0..5]); - let dummy_commitment_tx = HolderCommitmentTransaction::dummy(&mut htlcs); + let dummy_commitment_tx = HolderCommitmentTransaction::dummy(0, &mut htlcs); monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx.clone(), htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), None)).collect()).unwrap(); secret[0..32].clone_from_slice(&>::from_hex("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap()); @@ -5484,7 +5485,7 @@ mod tests { // But if we do it again, we'll prune 5-10 let mut htlcs = preimages_slice_to_htlcs!(preimages[0..3]); - let dummy_commitment_tx = HolderCommitmentTransaction::dummy(&mut htlcs); + let dummy_commitment_tx = HolderCommitmentTransaction::dummy(0, &mut htlcs); monitor.provide_latest_holder_commitment_tx(dummy_commitment_tx, htlcs.into_iter().map(|(htlc, _)| (htlc, Some(dummy_sig), None)).collect()).unwrap(); secret[0..32].clone_from_slice(&>::from_hex("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap()); @@ -5673,14 +5674,15 @@ mod tests { selected_contest_delay: 67, }), funding_outpoint: Some(funding_outpoint), - channel_type_features: ChannelTypeFeatures::only_static_remote_key() + channel_type_features: ChannelTypeFeatures::only_static_remote_key(), + channel_value_satoshis: 0, }; let shutdown_pubkey = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let best_block = BestBlock::from_network(Network::Testnet); let monitor = ChannelMonitor::new(Secp256k1::new(), keys, Some(ShutdownScript::new_p2wpkh_from_pubkey(shutdown_pubkey).into_inner()), 0, &ScriptBuf::new(), (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, ScriptBuf::new()), - &channel_parameters, true, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(&mut Vec::new()), + &channel_parameters, true, ScriptBuf::new(), 46, 0, HolderCommitmentTransaction::dummy(0, &mut Vec::new()), best_block, dummy_key, channel_id); let chan_id = monitor.inner.lock().unwrap().channel_id(); diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index 2a43b006920..8e30cd07522 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -368,7 +368,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP let prev_holder_commitment = Readable::read(reader)?; let _prev_holder_htlc_sigs: Option>> = Readable::read(reader)?; - let channel_parameters = Readable::read(reader)?; + let channel_parameters = ReadableArgs::::read(reader, channel_value_satoshis)?; // Read the serialized signer bytes, but don't deserialize them, as we'll obtain our signer // by re-deriving the private key material. @@ -1355,6 +1355,7 @@ mod tests { }), funding_outpoint: Some(funding_outpoint), channel_type_features: ChannelTypeFeatures::only_static_remote_key(), + channel_value_satoshis: 0, }; // Create an OnchainTxHandler for a commitment containing HTLCs with CLTV expiries of 0, 1, @@ -1374,7 +1375,7 @@ mod tests { (), )); } - let holder_commit = HolderCommitmentTransaction::dummy(&mut htlcs); + let holder_commit = HolderCommitmentTransaction::dummy(1000000, &mut htlcs); let mut tx_handler = OnchainTxHandler::new( 1000000, [0; 32], diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs index 3acb2145e5b..ae7d8ef3c56 100644 --- a/lightning/src/events/bump_transaction.rs +++ b/lightning/src/events/bump_transaction.rs @@ -956,7 +956,7 @@ mod tests { channel_derivation_parameters: ChannelDerivationParameters { value_satoshis: 42_000_000, keys_id: [42; 32], - transaction_parameters: ChannelTransactionParameters::test_dummy(), + transaction_parameters: ChannelTransactionParameters::test_dummy(42_000_000), }, outpoint: OutPoint { txid: Txid::from_byte_array([42; 32]), vout: 0 }, }, diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index a471bd05c7d..52a66913afd 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -30,7 +30,7 @@ use crate::chain::package::WEIGHT_REVOKED_OUTPUT; use crate::sign::EntropySource; use crate::types::payment::{PaymentHash, PaymentPreimage}; use crate::ln::msgs::DecodeError; -use crate::util::ser::{Readable, RequiredWrapper, Writeable, Writer}; +use crate::util::ser::{Readable, ReadableArgs, RequiredWrapper, Writeable, Writer}; use crate::util::transaction_utils; use bitcoin::locktime::absolute::LockTime; @@ -882,7 +882,9 @@ pub struct ChannelTransactionParameters { pub funding_outpoint: Option, /// This channel's type, as negotiated during channel open. For old objects where this field /// wasn't serialized, it will default to static_remote_key at deserialization. - pub channel_type_features: ChannelTypeFeatures + pub channel_type_features: ChannelTypeFeatures, + /// The value locked in the channel, denominated in satoshis. + pub channel_value_satoshis: u64, } /// Late-bound per-channel counterparty data used to build transactions. @@ -930,7 +932,7 @@ impl ChannelTransactionParameters { } #[cfg(test)] - pub fn test_dummy() -> Self { + pub fn test_dummy(channel_value_satoshis: u64) -> Self { let dummy_keys = ChannelPublicKeys { funding_pubkey: PublicKey::from_slice(&[2; 33]).unwrap(), revocation_basepoint: PublicKey::from_slice(&[2; 33]).unwrap().into(), @@ -950,6 +952,7 @@ impl ChannelTransactionParameters { txid: Txid::from_byte_array([42; 32]), index: 0 }), channel_type_features: ChannelTypeFeatures::empty(), + channel_value_satoshis, } } } @@ -970,13 +973,14 @@ impl Writeable for ChannelTransactionParameters { (8, self.funding_outpoint, option), (10, legacy_deserialization_prevention_marker, option), (11, self.channel_type_features, required), + (13, self.channel_value_satoshis, required), }); Ok(()) } } -impl Readable for ChannelTransactionParameters { - fn read(reader: &mut R) -> Result { +impl ReadableArgs for ChannelTransactionParameters { + fn read(reader: &mut R, read_args: u64) -> Result { let mut holder_pubkeys = RequiredWrapper(None); let mut holder_selected_contest_delay = RequiredWrapper(None); let mut is_outbound_from_holder = RequiredWrapper(None); @@ -984,6 +988,7 @@ impl Readable for ChannelTransactionParameters { let mut funding_outpoint = None; let mut _legacy_deserialization_prevention_marker: Option<()> = None; let mut channel_type_features = None; + let mut channel_value_satoshis = None; read_tlv_fields!(reader, { (0, holder_pubkeys, required), @@ -993,8 +998,14 @@ impl Readable for ChannelTransactionParameters { (8, funding_outpoint, option), (10, _legacy_deserialization_prevention_marker, option), (11, channel_type_features, option), + (13, channel_value_satoshis, option), }); + let channel_value_satoshis = channel_value_satoshis.unwrap_or(read_args); + if channel_value_satoshis != read_args { + return Err(DecodeError::InvalidValue); + } + let mut additional_features = ChannelTypeFeatures::empty(); additional_features.set_anchors_nonzero_fee_htlc_tx_required(); chain::package::verify_channel_type_features(&channel_type_features, Some(&additional_features))?; @@ -1005,7 +1016,8 @@ impl Readable for ChannelTransactionParameters { is_outbound_from_holder: is_outbound_from_holder.0.unwrap(), counterparty_parameters, funding_outpoint, - channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key()) + channel_type_features: channel_type_features.unwrap_or(ChannelTypeFeatures::only_static_remote_key()), + channel_value_satoshis, }) } } @@ -1105,7 +1117,7 @@ impl_writeable_tlv_based!(HolderCommitmentTransaction, { impl HolderCommitmentTransaction { #[cfg(test)] - pub fn dummy(htlcs: &mut Vec<(HTLCOutputInCommitment, ())>) -> Self { + pub fn dummy(channel_value_satoshis: u64, htlcs: &mut Vec<(HTLCOutputInCommitment, ())>) -> Self { let secp_ctx = Secp256k1::new(); let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()); let dummy_sig = sign(&secp_ctx, &secp256k1::Message::from_digest([42; 32]), &SecretKey::from_slice(&[42; 32]).unwrap()); @@ -1131,6 +1143,7 @@ impl HolderCommitmentTransaction { counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: channel_pubkeys.clone(), selected_contest_delay: 0 }), funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }), channel_type_features: ChannelTypeFeatures::only_static_remote_key(), + channel_value_satoshis, }; let mut counterparty_htlc_sigs = Vec::new(); for _ in 0..htlcs.len() { @@ -1942,6 +1955,7 @@ mod tests { counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: counterparty_pubkeys.clone(), selected_contest_delay: 0 }), funding_outpoint: Some(chain::transaction::OutPoint { txid: Txid::all_zeros(), index: 0 }), channel_type_features: ChannelTypeFeatures::only_static_remote_key(), + channel_value_satoshis: 3000, }; let htlcs_with_aux = Vec::new(); diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index b223d84644e..14ae0b896fc 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -2597,7 +2597,8 @@ impl ChannelContext where SP::Target: SignerProvider { pubkeys: counterparty_pubkeys, }), funding_outpoint: None, - channel_type_features: channel_type.clone() + channel_type_features: channel_type.clone(), + channel_value_satoshis, }, funding_transaction: None, }; @@ -2832,7 +2833,8 @@ impl ChannelContext where SP::Target: SignerProvider { is_outbound_from_holder: true, counterparty_parameters: None, funding_outpoint: None, - channel_type_features: channel_type.clone() + channel_type_features: channel_type.clone(), + channel_value_satoshis, }, funding_transaction: None, }; @@ -10512,7 +10514,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch _ => return Err(DecodeError::InvalidValue), }; - let mut channel_parameters: ChannelTransactionParameters = Readable::read(reader)?; + let mut channel_parameters: ChannelTransactionParameters = ReadableArgs::::read(reader, channel_value_satoshis)?; let funding_transaction: Option = Readable::read(reader)?; let counterparty_cur_commitment_point = Readable::read(reader)?; @@ -10657,6 +10659,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch // ChannelTransactionParameters may have had an empty features set upon deserialization. // To account for that, we're proactively setting/overriding the field here. channel_parameters.channel_type_features = chan_features.clone(); + // ChannelTransactionParameters::channel_value_satoshis defaults to 0 prior to version 0.2. + channel_parameters.channel_value_satoshis = channel_value_satoshis; let mut secp_ctx = Secp256k1::new(); secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes()); diff --git a/lightning/src/ln/dual_funding_tests.rs b/lightning/src/ln/dual_funding_tests.rs index 54bc7ee13dd..112aedf9d56 100644 --- a/lightning/src/ln/dual_funding_tests.rs +++ b/lightning/src/ln/dual_funding_tests.rs @@ -171,6 +171,7 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession) is_outbound_from_holder: true, funding_outpoint, channel_type_features, + channel_value_satoshis: funding_satoshis, }; channel diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 095ce1b5c6d..0d483b0017d 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -58,7 +58,7 @@ use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage}; use crate::ln::script::ShutdownScript; use crate::offers::invoice::UnsignedBolt12Invoice; use crate::types::payment::PaymentPreimage; -use crate::util::ser::Writeable; +use crate::util::ser::{ReadableArgs, Writeable}; use crate::util::transaction_utils; use crate::crypto::chacha20::ChaCha20; @@ -127,7 +127,7 @@ impl_writeable_tlv_based!(DelayedPaymentOutputDescriptor, { (8, revocation_pubkey, required), (10, channel_keys_id, required), (12, channel_value_satoshis, required), - (13, channel_transaction_parameters, option), + (13, channel_transaction_parameters, (option: ReadableArgs, channel_value_satoshis.0.unwrap())), }); pub(crate) const P2WPKH_WITNESS_WEIGHT: u64 = 1 /* num stack items */ + @@ -196,7 +196,7 @@ impl_writeable_tlv_based!(StaticPaymentOutputDescriptor, { (2, output, required), (4, channel_keys_id, required), (6, channel_value_satoshis, required), - (7, channel_transaction_parameters, option), + (7, channel_transaction_parameters, (option: ReadableArgs, channel_value_satoshis.0.unwrap())), }); /// Describes the necessary information to spend a spendable output. @@ -562,7 +562,7 @@ pub struct ChannelDerivationParameters { impl_writeable_tlv_based!(ChannelDerivationParameters, { (0, value_satoshis, required), (2, keys_id, required), - (4, transaction_parameters, required), + (4, transaction_parameters, (required: ReadableArgs, value_satoshis.0.unwrap())), }); /// A descriptor used to sign for a commitment transaction's HTLC output. diff --git a/lightning/src/util/ser_macros.rs b/lightning/src/util/ser_macros.rs index 5a0ce0b4d4f..692536c5e33 100644 --- a/lightning/src/util/ser_macros.rs +++ b/lightning/src/util/ser_macros.rs @@ -29,6 +29,9 @@ macro_rules! _encode_tlv { BigSize($field.serialized_length() as u64).write($stream)?; $field.write($stream)?; }; + ($stream: expr, $type: expr, $field: expr, (required: $trait: ident $(, $read_arg: expr)?) $(, $self: ident)?) => { + $crate::_encode_tlv!($stream, $type, $field, required); + }; ($stream: expr, $type: expr, $field: expr, required_vec $(, $self: ident)?) => { $crate::_encode_tlv!($stream, $type, $crate::util::ser::WithoutLength(&$field), required); }; @@ -185,6 +188,9 @@ macro_rules! _get_varint_length_prefixed_tlv_length { .expect("No in-memory data may fail to serialize"); $len.0 += field_len; }; + ($len: expr, $type: expr, $field: expr, (required: $trait: ident $(, $read_arg: expr)?) $(, $self: ident)?) => { + $crate::_get_varint_length_prefixed_tlv_length!($len, $type, $field, required); + }; ($len: expr, $type: expr, $field: expr, required_vec $(, $self: ident)?) => { let field = $crate::util::ser::WithoutLength(&$field); $crate::_get_varint_length_prefixed_tlv_length!($len, $type, field, required); @@ -801,6 +807,9 @@ macro_rules! _init_tlv_based_struct_field { ($field: ident, required) => { $field.0.unwrap() }; + ($field: ident, (required: $trait: ident $(, $read_arg: expr)?)) => { + $crate::_init_tlv_based_struct_field!($field, required) + }; ($field: ident, required_vec) => { $field }; From dc995eafcd64104c0123a892730d1610cb64320e Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 19 Feb 2025 18:25:33 -0600 Subject: [PATCH 06/20] Remove channel_value_satoshis from FundingScope Now that ChannelTransactionParameters are in FundingScope, channel_value_satoshis can be dropped from the latter. --- lightning/src/ln/channel.rs | 104 +++++++++++++++++------------------- 1 file changed, 50 insertions(+), 54 deletions(-) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 14ae0b896fc..0597fee693f 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -1622,7 +1622,6 @@ impl UnfundedChannelContext { /// during channel establishment and may be replaced during channel splicing or if the attempted /// funding transaction is replaced using tx_init_rbf. pub(super) struct FundingScope { - channel_value_satoshis: u64, value_to_self_msat: u64, // Excluding all pending_htlcs, fees, and anchor outputs /// minimum channel reserve for self to maintain - set by them. @@ -1658,7 +1657,7 @@ pub(super) struct FundingScope { impl FundingScope { pub fn get_value_satoshis(&self) -> u64 { - self.channel_value_satoshis + self.channel_transaction_parameters.channel_value_satoshis } pub(crate) fn get_value_to_self_msat(&self) -> u64 { @@ -1673,7 +1672,7 @@ impl FundingScope { self.counterparty_selected_channel_reserve_satoshis.map(|counterparty_reserve| { let holder_reserve = self.holder_selected_channel_reserve_satoshis; cmp::min( - (self.channel_value_satoshis - counterparty_reserve - holder_reserve) * 1000, + (self.get_value_satoshis() - counterparty_reserve - holder_reserve) * 1000, party_max_htlc_value_in_flight_msat ) }) @@ -2039,7 +2038,7 @@ trait InitialRemoteCommitmentReceiver where SP::Target: SignerProvide let initial_commitment_tx = self.context().build_commitment_transaction(self.funding(), holder_commitment_point.transaction_number(), &keys, true, false, logger).tx; let trusted_tx = initial_commitment_tx.trust(); let initial_commitment_bitcoin_tx = trusted_tx.built_transaction(); - let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.funding().channel_value_satoshis); + let sighash = initial_commitment_bitcoin_tx.get_sighash_all(&funding_script, self.funding().get_value_satoshis()); // They sign the holder commitment transaction... log_trace!(logger, "Checking {} tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.", self.received_msg(), log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.funding().counterparty_funding_pubkey().serialize()), @@ -2120,7 +2119,7 @@ trait InitialRemoteCommitmentReceiver where SP::Target: SignerProvide let funding_txo_script = funding_redeemscript.to_p2wsh(); let obscure_factor = get_commitment_transaction_number_obscure_factor(&funding.get_holder_pubkeys().payment_point, &funding.get_counterparty_pubkeys().payment_point, funding.is_outbound()); let shutdown_script = context.shutdown_scriptpubkey.clone().map(|script| script.into_inner()); - let mut monitor_signer = signer_provider.derive_channel_signer(funding.channel_value_satoshis, context.channel_keys_id); + let mut monitor_signer = signer_provider.derive_channel_signer(funding.get_value_satoshis(), context.channel_keys_id); monitor_signer.provide_channel_parameters(&funding.channel_transaction_parameters); // TODO(RBF): When implementing RBF, the funding_txo passed here must only update // ChannelMonitorImp::first_confirmed_funding_txo during channel establishment, not splicing @@ -2128,7 +2127,7 @@ trait InitialRemoteCommitmentReceiver where SP::Target: SignerProvide shutdown_script, funding.get_holder_selected_contest_delay(), &context.destination_script, (funding_txo, funding_txo_script), &funding.channel_transaction_parameters, funding.is_outbound(), - funding_redeemscript.clone(), funding.channel_value_satoshis, + funding_redeemscript.clone(), funding.get_value_satoshis(), obscure_factor, holder_commitment_tx, best_block, context.counterparty_node_id, context.channel_id()); channel_monitor.provide_initial_counterparty_commitment_tx( @@ -2573,7 +2572,6 @@ impl ChannelContext where SP::Target: SignerProvider { // TODO(dual_funding): Checks for `funding_feerate_sat_per_1000_weight`? let funding = FundingScope { - channel_value_satoshis, value_to_self_msat, counterparty_selected_channel_reserve_satoshis: Some(msg_channel_reserve_satoshis), holder_selected_channel_reserve_satoshis, @@ -2809,8 +2807,6 @@ impl ChannelContext where SP::Target: SignerProvider { let temporary_channel_id = temporary_channel_id.unwrap_or_else(|| ChannelId::temporary_from_entropy_source(entropy_source)); let funding = FundingScope { - // We'll add our counterparty's `funding_satoshis` when we receive `accept_channel2`. - channel_value_satoshis, value_to_self_msat, counterparty_selected_channel_reserve_satoshis: None, // Filled in in accept_channel holder_selected_channel_reserve_satoshis, @@ -2834,6 +2830,7 @@ impl ChannelContext where SP::Target: SignerProvider { counterparty_parameters: None, funding_outpoint: None, channel_type_features: channel_type.clone(), + // We'll add our counterparty's `funding_satoshis` when we receive `accept_channel2`. channel_value_satoshis, }, funding_transaction: None, @@ -3176,17 +3173,17 @@ impl ChannelContext where SP::Target: SignerProvider { if common_fields.dust_limit_satoshis > 21000000 * 100000000 { return Err(ChannelError::close(format!("Peer never wants payout outputs? dust_limit_satoshis was {}", common_fields.dust_limit_satoshis))); } - if channel_reserve_satoshis > funding.channel_value_satoshis { - return Err(ChannelError::close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", channel_reserve_satoshis, funding.channel_value_satoshis))); + if channel_reserve_satoshis > funding.get_value_satoshis() { + return Err(ChannelError::close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", channel_reserve_satoshis, funding.get_value_satoshis()))); } if common_fields.dust_limit_satoshis > funding.holder_selected_channel_reserve_satoshis { return Err(ChannelError::close(format!("Dust limit ({}) is bigger than our channel reserve ({})", common_fields.dust_limit_satoshis, funding.holder_selected_channel_reserve_satoshis))); } - if channel_reserve_satoshis > funding.channel_value_satoshis - funding.holder_selected_channel_reserve_satoshis { + if channel_reserve_satoshis > funding.get_value_satoshis() - funding.holder_selected_channel_reserve_satoshis { return Err(ChannelError::close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than channel value minus our reserve ({})", - channel_reserve_satoshis, funding.channel_value_satoshis - funding.holder_selected_channel_reserve_satoshis))); + channel_reserve_satoshis, funding.get_value_satoshis() - funding.holder_selected_channel_reserve_satoshis))); } - let full_channel_value_msat = (funding.channel_value_satoshis - channel_reserve_satoshis) * 1000; + let full_channel_value_msat = (funding.get_value_satoshis() - channel_reserve_satoshis) * 1000; if common_fields.htlc_minimum_msat >= full_channel_value_msat { return Err(ChannelError::close(format!("Minimum htlc value ({}) is full channel value ({})", common_fields.htlc_minimum_msat, full_channel_value_msat))); } @@ -3260,7 +3257,7 @@ impl ChannelContext where SP::Target: SignerProvider { } else { None }; self.counterparty_dust_limit_satoshis = common_fields.dust_limit_satoshis; - self.counterparty_max_htlc_value_in_flight_msat = cmp::min(common_fields.max_htlc_value_in_flight_msat, funding.channel_value_satoshis * 1000); + self.counterparty_max_htlc_value_in_flight_msat = cmp::min(common_fields.max_htlc_value_in_flight_msat, funding.get_value_satoshis() * 1000); funding.counterparty_selected_channel_reserve_satoshis = Some(channel_reserve_satoshis); self.counterparty_htlc_minimum_msat = common_fields.htlc_minimum_msat; self.counterparty_max_accepted_htlcs = common_fields.max_accepted_htlcs; @@ -3625,7 +3622,7 @@ impl ChannelContext where SP::Target: SignerProvider { // AwaitingRemoteRevokeToRemove or AwaitingRemovedRemoteRevoke) we may have allowed them to // "violate" their reserve value by couting those against it. Thus, we have to convert // everything to i64 before subtracting as otherwise we can overflow. - let value_to_remote_msat: i64 = (funding.channel_value_satoshis * 1000) as i64 - (funding.value_to_self_msat as i64) - (remote_htlc_total_msat as i64) - value_to_self_msat_offset; + let value_to_remote_msat: i64 = (funding.get_value_satoshis() * 1000) as i64 - (funding.value_to_self_msat as i64) - (remote_htlc_total_msat as i64) - value_to_self_msat_offset; assert!(value_to_remote_msat >= 0); #[cfg(debug_assertions)] @@ -4029,7 +4026,7 @@ impl ChannelContext where SP::Target: SignerProvider { let max_reserved_commit_tx_fee_msat = context.next_remote_commit_tx_fee_msat(&funding, Some(htlc_above_dust), None); let holder_selected_chan_reserve_msat = funding.holder_selected_channel_reserve_satoshis * 1000; - let remote_balance_msat = (funding.channel_value_satoshis * 1000 - funding.value_to_self_msat) + let remote_balance_msat = (funding.get_value_satoshis() * 1000 - funding.value_to_self_msat) .saturating_sub(htlc_stats.pending_inbound_htlcs_value_msat); if remote_balance_msat < max_reserved_commit_tx_fee_msat + holder_selected_chan_reserve_msat + anchor_outputs_value_msat { @@ -4097,7 +4094,7 @@ impl ChannelContext where SP::Target: SignerProvider { #[allow(deprecated)] // TODO: Remove once balance_msat is removed. AvailableBalances { - inbound_capacity_msat: cmp::max(funding.channel_value_satoshis as i64 * 1000 + inbound_capacity_msat: cmp::max(funding.get_value_satoshis() as i64 * 1000 - funding.value_to_self_msat as i64 - htlc_stats.pending_inbound_htlcs_value_msat as i64 - funding.holder_selected_channel_reserve_satoshis as i64 * 1000, @@ -4407,7 +4404,7 @@ impl ChannelContext where SP::Target: SignerProvider { unbroadcasted_batch_funding_txid, channel_id: self.channel_id, user_channel_id: self.user_id, - channel_capacity_satoshis: funding.channel_value_satoshis, + channel_capacity_satoshis: funding.get_value_satoshis(), counterparty_node_id: self.counterparty_node_id, unbroadcasted_funding_tx, is_manual_broadcast: self.is_manual_broadcast, @@ -4842,7 +4839,7 @@ impl FundedChannel where let mut total_fee_satoshis = proposed_total_fee_satoshis; let mut value_to_holder: i64 = (self.funding.value_to_self_msat as i64) / 1000 - if self.funding.is_outbound() { total_fee_satoshis as i64 } else { 0 }; - let mut value_to_counterparty: i64 = ((self.funding.channel_value_satoshis * 1000 - self.funding.value_to_self_msat) as i64 / 1000) - if self.funding.is_outbound() { 0 } else { total_fee_satoshis as i64 }; + let mut value_to_counterparty: i64 = ((self.funding.get_value_satoshis() * 1000 - self.funding.value_to_self_msat) as i64 / 1000) - if self.funding.is_outbound() { 0 } else { total_fee_satoshis as i64 }; if value_to_holder < 0 { assert!(self.funding.is_outbound()); @@ -5283,7 +5280,7 @@ impl FundedChannel where if self.context.channel_state.is_peer_disconnected() { return Err(ChannelError::close("Peer sent update_add_htlc when we needed a channel_reestablish".to_owned())); } - if msg.amount_msat > self.funding.channel_value_satoshis * 1000 { + if msg.amount_msat > self.funding.get_value_satoshis() * 1000 { return Err(ChannelError::close("Remote side tried to send more than the total value of the channel".to_owned())); } if msg.amount_msat == 0 { @@ -5326,7 +5323,7 @@ impl FundedChannel where let pending_value_to_self_msat = self.funding.value_to_self_msat + htlc_stats.pending_inbound_htlcs_value_msat - removed_outbound_total_msat; let pending_remote_value_msat = - self.funding.channel_value_satoshis * 1000 - pending_value_to_self_msat; + self.funding.get_value_satoshis() * 1000 - pending_value_to_self_msat; if pending_remote_value_msat < msg.amount_msat { return Err(ChannelError::close("Remote HTLC add would overdraw remaining funds".to_owned())); } @@ -5521,7 +5518,7 @@ impl FundedChannel where let commitment_txid = { let trusted_tx = commitment_stats.tx.trust(); let bitcoin_tx = trusted_tx.built_transaction(); - let sighash = bitcoin_tx.get_sighash_all(&funding_script, self.funding.channel_value_satoshis); + let sighash = bitcoin_tx.get_sighash_all(&funding_script, self.funding.get_value_satoshis()); log_trace!(logger, "Checking commitment tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}", log_bytes!(msg.signature.serialize_compact()[..]), @@ -6639,7 +6636,7 @@ impl FundedChannel where let signed_tx = if let (Some(ClosingSigned { signature, .. }), Some(counterparty_sig)) = (closing_signed.as_ref(), self.context.last_received_closing_sig) { let funding_redeemscript = self.funding.get_funding_redeemscript(); - let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.funding.channel_value_satoshis); + let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.funding.get_value_satoshis()); debug_assert!(self.context.secp_ctx.verify_ecdsa(&sighash, &counterparty_sig, &self.funding.get_counterparty_pubkeys().funding_pubkey).is_ok()); Some(self.build_signed_closing_transaction(&closing_tx, &counterparty_sig, signature)) @@ -7051,7 +7048,7 @@ impl FundedChannel where cmp::max(normal_feerate as u64 * tx_weight / 1000 + self.context.config.options.force_close_avoidance_max_fee_satoshis, proposed_max_feerate as u64 * tx_weight / 1000) } else { - self.funding.channel_value_satoshis - (self.funding.value_to_self_msat + 999) / 1000 + self.funding.get_value_satoshis() - (self.funding.value_to_self_msat + 999) / 1000 }; self.context.closing_fee_limits = Some((proposed_total_fee_satoshis, proposed_max_total_fee_satoshis)); @@ -7327,7 +7324,7 @@ impl FundedChannel where unbroadcasted_batch_funding_txid: self.context.unbroadcasted_batch_funding_txid(&self.funding), channel_id: self.context.channel_id, user_channel_id: self.context.user_id, - channel_capacity_satoshis: self.funding.channel_value_satoshis, + channel_capacity_satoshis: self.funding.get_value_satoshis(), counterparty_node_id: self.context.counterparty_node_id, unbroadcasted_funding_tx: self.context.unbroadcasted_funding(&self.funding), is_manual_broadcast: self.context.is_manual_broadcast, @@ -7372,7 +7369,7 @@ impl FundedChannel where if used_total_fee != msg.fee_satoshis { return Err(ChannelError::close(format!("Remote sent us a closing_signed with a fee other than the value they can claim. Fee in message: {}. Actual closing tx fee: {}", msg.fee_satoshis, used_total_fee))); } - let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.funding.channel_value_satoshis); + let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.funding.get_value_satoshis()); match self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.funding.get_counterparty_pubkeys().funding_pubkey) { Ok(_) => {}, @@ -7381,7 +7378,7 @@ impl FundedChannel where // limits, so check for that case by re-checking the signature here. skip_remote_output = true; closing_tx = self.build_closing_transaction(msg.fee_satoshis, skip_remote_output)?.0; - let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.funding.channel_value_satoshis); + let sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.funding.get_value_satoshis()); secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, self.funding.counterparty_funding_pubkey()), "Invalid closing tx signature from peer".to_owned()); }, }; @@ -7447,7 +7444,7 @@ impl FundedChannel where if !self.funding.is_outbound() { // They have to pay, so pick the highest fee in the overlapping range. // We should never set an upper bound aside from their full balance - debug_assert_eq!(our_max_fee, self.funding.channel_value_satoshis - (self.funding.value_to_self_msat + 999) / 1000); + debug_assert_eq!(our_max_fee, self.funding.get_value_satoshis() - (self.funding.value_to_self_msat + 999) / 1000); propose_fee!(cmp::min(max_fee_satoshis, our_max_fee)); } else { if msg.fee_satoshis < our_min_fee || msg.fee_satoshis > our_max_fee { @@ -7584,7 +7581,7 @@ impl FundedChannel where let pending_value_to_self_msat = self.funding.value_to_self_msat + htlc_stats.pending_inbound_htlcs_value_msat - removed_outbound_total_msat; let pending_remote_value_msat = - self.funding.channel_value_satoshis * 1000 - pending_value_to_self_msat; + self.funding.get_value_satoshis() * 1000 - pending_value_to_self_msat; if !self.funding.is_outbound() { // `Some(())` is for the fee spike buffer we keep for the remote. This deviates from @@ -7628,7 +7625,7 @@ impl FundedChannel where pub fn get_value_stat(&self) -> ChannelValueStat { ChannelValueStat { value_to_self_msat: self.funding.value_to_self_msat, - channel_value_msat: self.funding.channel_value_satoshis * 1000, + channel_value_msat: self.funding.get_value_satoshis() * 1000, channel_reserve_msat: self.funding.counterparty_selected_channel_reserve_satoshis.unwrap() * 1000, pending_outbound_htlcs_amount_msat: self.context.pending_outbound_htlcs.iter().map(|ref h| h.amount_msat).sum::(), pending_inbound_htlcs_amount_msat: self.context.pending_inbound_htlcs.iter().map(|ref h| h.amount_msat).sum::(), @@ -7892,7 +7889,7 @@ impl FundedChannel where if tx.compute_txid() == funding_txo.txid { let txo_idx = funding_txo.index as usize; if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.funding.get_funding_redeemscript().to_p2wsh() || - tx.output[txo_idx].value.to_sat() != self.funding.channel_value_satoshis { + tx.output[txo_idx].value.to_sat() != self.funding.get_value_satoshis() { if self.funding.is_outbound() { // If we generated the funding transaction and it doesn't match what it // should, the client is really broken and we should just panic and @@ -8381,7 +8378,7 @@ impl FundedChannel where { return Err(ChannelError::Ignore("Cannot send HTLC until channel is fully established and we haven't started shutting down".to_owned())); } - let channel_total_msat = self.funding.channel_value_satoshis * 1000; + let channel_total_msat = self.funding.get_value_satoshis() * 1000; if amount_msat > channel_total_msat { return Err(ChannelError::Ignore(format!("Cannot send amount {}, because it is more than the total value of the channel {}", amount_msat, channel_total_msat))); } @@ -8772,7 +8769,7 @@ impl FundedChannel where // Upper bound by capacity. We make it a bit less than full capacity to prevent attempts // to use full capacity. This is an effort to reduce routing failures, because in many cases // channel might have been used to route very small values (either by honest users or as DoS). - self.funding.channel_value_satoshis * 1000 * 9 / 10, + self.funding.get_value_satoshis() * 1000 * 9 / 10, self.context.counterparty_max_htlc_value_in_flight_msat ); @@ -9171,7 +9168,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { common_fields: msgs::CommonOpenChannelFields { chain_hash, temporary_channel_id: self.context.channel_id, - funding_satoshis: self.funding.channel_value_satoshis, + funding_satoshis: self.funding.get_value_satoshis(), dust_limit_satoshis: self.context.holder_dust_limit_satoshis, max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat, htlc_minimum_msat: self.context.holder_htlc_minimum_msat, @@ -9191,7 +9188,7 @@ impl OutboundV1Channel where SP::Target: SignerProvider { }), channel_type: Some(self.context.channel_type.clone()), }, - push_msat: self.funding.channel_value_satoshis * 1000 - self.funding.value_to_self_msat, + push_msat: self.funding.get_value_satoshis() * 1000 - self.funding.value_to_self_msat, channel_reserve_satoshis: self.funding.holder_selected_channel_reserve_satoshis, }) } @@ -9660,7 +9657,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { common_fields: msgs::CommonOpenChannelFields { chain_hash, temporary_channel_id: self.context.temporary_channel_id.unwrap(), - funding_satoshis: self.funding.channel_value_satoshis, + funding_satoshis: self.funding.get_value_satoshis(), dust_limit_satoshis: self.context.holder_dust_limit_satoshis, max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat, htlc_minimum_msat: self.context.holder_htlc_minimum_msat, @@ -9771,7 +9768,7 @@ impl PendingV2Channel where SP::Target: SignerProvider { is_initiator: false, inputs_to_contribute: our_funding_inputs, outputs_to_contribute: Vec::new(), - expected_remote_shared_funding_output: Some((funding.get_funding_redeemscript().to_p2wsh(), funding.channel_value_satoshis)), + expected_remote_shared_funding_output: Some((funding.get_funding_redeemscript().to_p2wsh(), funding.get_value_satoshis())), } ).map_err(|_| ChannelError::Close(( "V2 channel rejected due to sender error".into(), @@ -9983,7 +9980,7 @@ impl Writeable for FundedChannel where SP::Target: SignerProvider channel_state.set_peer_disconnected(); channel_state.to_u32().write(writer)?; } - self.funding.channel_value_satoshis.write(writer)?; + self.funding.get_value_satoshis().write(writer)?; self.context.latest_monitor_update_id.write(writer)?; @@ -10222,13 +10219,13 @@ impl Writeable for FundedChannel where SP::Target: SignerProvider // a different percentage of the channel value then 10%, which older versions of LDK used // to set it to before the percentage was made configurable. let serialized_holder_selected_reserve = - if self.funding.holder_selected_channel_reserve_satoshis != get_legacy_default_holder_selected_channel_reserve_satoshis(self.funding.channel_value_satoshis) + if self.funding.holder_selected_channel_reserve_satoshis != get_legacy_default_holder_selected_channel_reserve_satoshis(self.funding.get_value_satoshis()) { Some(self.funding.holder_selected_channel_reserve_satoshis) } else { None }; let mut old_max_in_flight_percent_config = UserConfig::default().channel_handshake_config; old_max_in_flight_percent_config.max_inbound_htlc_value_in_flight_percent_of_channel = MAX_IN_FLIGHT_PERCENT_LEGACY; let serialized_holder_htlc_max_in_flight = - if self.context.holder_max_htlc_value_in_flight_msat != get_holder_max_htlc_value_in_flight_msat(self.funding.channel_value_satoshis, &old_max_in_flight_percent_config) + if self.context.holder_max_htlc_value_in_flight_msat != get_holder_max_htlc_value_in_flight_msat(self.funding.get_value_satoshis(), &old_max_in_flight_percent_config) { Some(self.context.holder_max_htlc_value_in_flight_msat) } else { None }; let channel_pending_event_emitted = Some(self.context.channel_pending_event_emitted); @@ -10752,7 +10749,6 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch Ok(FundedChannel { funding: FundingScope { - channel_value_satoshis, value_to_self_msat, counterparty_selected_channel_reserve_satoshis, holder_selected_channel_reserve_satoshis: holder_selected_channel_reserve_satoshis.unwrap(), @@ -11275,12 +11271,12 @@ mod tests { // `holder_max_htlc_value_in_flight_msat`, when configured with a valid percentage value, // which is set to the lower bound + 1 (2%) of the `channel_value`. let mut chan_1 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_2_percent), 10000000, 100000, 42, &config_2_percent, 0, 42, None, &logger).unwrap(); - let chan_1_value_msat = chan_1.funding.channel_value_satoshis * 1000; + let chan_1_value_msat = chan_1.funding.get_value_satoshis() * 1000; assert_eq!(chan_1.context.holder_max_htlc_value_in_flight_msat, (chan_1_value_msat as f64 * 0.02) as u64); // Test with the upper bound - 1 of valid values (99%). let chan_2 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_99_percent), 10000000, 100000, 42, &config_99_percent, 0, 42, None, &logger).unwrap(); - let chan_2_value_msat = chan_2.funding.channel_value_satoshis * 1000; + let chan_2_value_msat = chan_2.funding.get_value_satoshis() * 1000; assert_eq!(chan_2.context.holder_max_htlc_value_in_flight_msat, (chan_2_value_msat as f64 * 0.99) as u64); let chan_1_open_channel_msg = chan_1.get_open_channel(ChainHash::using_genesis_block(network), &&logger).unwrap(); @@ -11289,38 +11285,38 @@ mod tests { // `holder_max_htlc_value_in_flight_msat`, when configured with a valid percentage value, // which is set to the lower bound - 1 (2%) of the `channel_value`. let chan_3 = InboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, inbound_node_id, &channelmanager::provided_channel_type_features(&config_2_percent), &channelmanager::provided_init_features(&config_2_percent), &chan_1_open_channel_msg, 7, &config_2_percent, 0, &&logger, /*is_0conf=*/false).unwrap(); - let chan_3_value_msat = chan_3.funding.channel_value_satoshis * 1000; + let chan_3_value_msat = chan_3.funding.get_value_satoshis() * 1000; assert_eq!(chan_3.context.holder_max_htlc_value_in_flight_msat, (chan_3_value_msat as f64 * 0.02) as u64); // Test with the upper bound - 1 of valid values (99%). let chan_4 = InboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, inbound_node_id, &channelmanager::provided_channel_type_features(&config_99_percent), &channelmanager::provided_init_features(&config_99_percent), &chan_1_open_channel_msg, 7, &config_99_percent, 0, &&logger, /*is_0conf=*/false).unwrap(); - let chan_4_value_msat = chan_4.funding.channel_value_satoshis * 1000; + let chan_4_value_msat = chan_4.funding.get_value_satoshis() * 1000; assert_eq!(chan_4.context.holder_max_htlc_value_in_flight_msat, (chan_4_value_msat as f64 * 0.99) as u64); // Test that `OutboundV1Channel::new` uses the lower bound of the configurable percentage values (1%) // if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a value less than 1. let chan_5 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_0_percent), 10000000, 100000, 42, &config_0_percent, 0, 42, None, &logger).unwrap(); - let chan_5_value_msat = chan_5.funding.channel_value_satoshis * 1000; + let chan_5_value_msat = chan_5.funding.get_value_satoshis() * 1000; assert_eq!(chan_5.context.holder_max_htlc_value_in_flight_msat, (chan_5_value_msat as f64 * 0.01) as u64); // Test that `OutboundV1Channel::new` uses the upper bound of the configurable percentage values // (100%) if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a larger value // than 100. let chan_6 = OutboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&config_101_percent), 10000000, 100000, 42, &config_101_percent, 0, 42, None, &logger).unwrap(); - let chan_6_value_msat = chan_6.funding.channel_value_satoshis * 1000; + let chan_6_value_msat = chan_6.funding.get_value_satoshis() * 1000; assert_eq!(chan_6.context.holder_max_htlc_value_in_flight_msat, chan_6_value_msat); // Test that `InboundV1Channel::new` uses the lower bound of the configurable percentage values (1%) // if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a value less than 1. let chan_7 = InboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, inbound_node_id, &channelmanager::provided_channel_type_features(&config_0_percent), &channelmanager::provided_init_features(&config_0_percent), &chan_1_open_channel_msg, 7, &config_0_percent, 0, &&logger, /*is_0conf=*/false).unwrap(); - let chan_7_value_msat = chan_7.funding.channel_value_satoshis * 1000; + let chan_7_value_msat = chan_7.funding.get_value_satoshis() * 1000; assert_eq!(chan_7.context.holder_max_htlc_value_in_flight_msat, (chan_7_value_msat as f64 * 0.01) as u64); // Test that `InboundV1Channel::new` uses the upper bound of the configurable percentage values // (100%) if `max_inbound_htlc_value_in_flight_percent_of_channel` is set to a larger value // than 100. let chan_8 = InboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider, inbound_node_id, &channelmanager::provided_channel_type_features(&config_101_percent), &channelmanager::provided_init_features(&config_101_percent), &chan_1_open_channel_msg, 7, &config_101_percent, 0, &&logger, /*is_0conf=*/false).unwrap(); - let chan_8_value_msat = chan_8.funding.channel_value_satoshis * 1000; + let chan_8_value_msat = chan_8.funding.get_value_satoshis() * 1000; assert_eq!(chan_8.context.holder_max_htlc_value_in_flight_msat, chan_8_value_msat); } @@ -11361,7 +11357,7 @@ mod tests { outbound_node_config.channel_handshake_config.their_channel_reserve_proportional_millionths = (outbound_selected_channel_reserve_perc * 1_000_000.0) as u32; let mut chan = OutboundV1Channel::<&TestKeysInterface>::new(&&fee_est, &&keys_provider, &&keys_provider, outbound_node_id, &channelmanager::provided_init_features(&outbound_node_config), channel_value_satoshis, 100_000, 42, &outbound_node_config, 0, 42, None, &logger).unwrap(); - let expected_outbound_selected_chan_reserve = cmp::max(MIN_THEIR_CHAN_RESERVE_SATOSHIS, (chan.funding.channel_value_satoshis as f64 * outbound_selected_channel_reserve_perc) as u64); + let expected_outbound_selected_chan_reserve = cmp::max(MIN_THEIR_CHAN_RESERVE_SATOSHIS, (chan.funding.get_value_satoshis() as f64 * outbound_selected_channel_reserve_perc) as u64); assert_eq!(chan.funding.holder_selected_channel_reserve_satoshis, expected_outbound_selected_chan_reserve); let chan_open_channel_msg = chan.get_open_channel(ChainHash::using_genesis_block(network), &&logger).unwrap(); @@ -11371,7 +11367,7 @@ mod tests { if outbound_selected_channel_reserve_perc + inbound_selected_channel_reserve_perc < 1.0 { let chan_inbound_node = InboundV1Channel::<&TestKeysInterface>::new(&&fee_est, &&keys_provider, &&keys_provider, inbound_node_id, &channelmanager::provided_channel_type_features(&inbound_node_config), &channelmanager::provided_init_features(&outbound_node_config), &chan_open_channel_msg, 7, &inbound_node_config, 0, &&logger, /*is_0conf=*/false).unwrap(); - let expected_inbound_selected_chan_reserve = cmp::max(MIN_THEIR_CHAN_RESERVE_SATOSHIS, (chan.funding.channel_value_satoshis as f64 * inbound_selected_channel_reserve_perc) as u64); + let expected_inbound_selected_chan_reserve = cmp::max(MIN_THEIR_CHAN_RESERVE_SATOSHIS, (chan.funding.get_value_satoshis() as f64 * inbound_selected_channel_reserve_perc) as u64); assert_eq!(chan_inbound_node.funding.holder_selected_channel_reserve_satoshis, expected_inbound_selected_chan_reserve); assert_eq!(chan_inbound_node.funding.counterparty_selected_channel_reserve_satoshis.unwrap(), expected_outbound_selected_chan_reserve); @@ -11698,7 +11694,7 @@ mod tests { let unsigned_tx = trusted_tx.built_transaction(); let redeemscript = chan.funding.get_funding_redeemscript(); let counterparty_signature = Signature::from_der(&>::from_hex($counterparty_sig_hex).unwrap()[..]).unwrap(); - let sighash = unsigned_tx.get_sighash_all(&redeemscript, chan.funding.channel_value_satoshis); + let sighash = unsigned_tx.get_sighash_all(&redeemscript, chan.funding.get_value_satoshis()); log_trace!(logger, "unsigned_tx = {}", serialize(&unsigned_tx.transaction).as_hex()); assert!(secp_ctx.verify_ecdsa(&sighash, &counterparty_signature, chan.funding.counterparty_funding_pubkey()).is_ok(), "verify counterparty commitment sig"); @@ -11758,7 +11754,7 @@ mod tests { let htlc_counterparty_sig = htlc_counterparty_sig_iter.next().unwrap(); let htlc_holder_sig = signer.sign_holder_htlc_transaction(&htlc_tx, 0, &HTLCDescriptor { channel_derivation_parameters: ChannelDerivationParameters { - value_satoshis: chan.funding.channel_value_satoshis, + value_satoshis: chan.funding.get_value_satoshis(), keys_id: chan.context.channel_keys_id, transaction_parameters: chan.funding.channel_transaction_parameters.clone(), }, From ee72c4a9b495942443d972e869469b30f9230d22 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 20 Feb 2025 10:17:40 -0600 Subject: [PATCH 07/20] Pass channel params to sign_counterparty_commitment Now that channel_value_satoshis has been moved to ChannelTransactionParameters, pass the entire parameters when calling each method on EcdsaChannelSigner. This will remove the need for ChannelSigner::provide_channel_parameters. Instead, the parameters from the FundingScope will be passed in to each method. This simplifies the interaction with a ChannelSigner when needing to be called for more than one FundingScope, which will be the case for pending splices and RBF attempts. --- lightning/src/ln/chan_utils.rs | 5 +++++ lightning/src/ln/channel.rs | 18 ++++++++++++------ lightning/src/ln/functional_tests.rs | 10 ++++++++-- lightning/src/sign/ecdsa.rs | 5 +++-- lightning/src/sign/mod.rs | 13 ++++++------- lightning/src/util/test_channel_signer.rs | 15 +++++++++------ 6 files changed, 43 insertions(+), 23 deletions(-) diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index 52a66913afd..c4c10a46f16 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -931,6 +931,11 @@ impl ChannelTransactionParameters { } } + /// Returns the counterparty's pubkeys. + pub fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys> { + self.counterparty_parameters.as_ref().map(|params| ¶ms.pubkeys) + } + #[cfg(test)] pub fn test_dummy(channel_value_satoshis: u64) -> Self { let dummy_keys = ChannelPublicKeys { diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 0597fee693f..f77a0b3ecda 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -4415,7 +4415,8 @@ impl ChannelContext where SP::Target: SignerProvider { /// Only allowed after [`FundingScope::channel_transaction_parameters`] is set. fn get_funding_signed_msg( - &mut self, logger: &L, counterparty_initial_commitment_tx: CommitmentTransaction + &mut self, channel_parameters: &ChannelTransactionParameters, logger: &L, + counterparty_initial_commitment_tx: CommitmentTransaction, ) -> Option where L::Target: Logger { let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust(); let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction(); @@ -4426,7 +4427,7 @@ impl ChannelContext where SP::Target: SignerProvider { let signature = match &self.holder_signer { // TODO (arik): move match into calling method for Taproot ChannelSignerType::Ecdsa(ecdsa) => ecdsa.sign_counterparty_commitment( - &counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &self.secp_ctx + channel_parameters, &counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &self.secp_ctx ).ok(), // TODO (taproot|arik) #[cfg(taproot)] @@ -4515,7 +4516,8 @@ impl ChannelContext where SP::Target: SignerProvider { match self.holder_signer { // TODO (taproot|arik): move match into calling method for Taproot ChannelSignerType::Ecdsa(ref ecdsa) => { - ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &self.secp_ctx) + let channel_parameters = &funding.channel_transaction_parameters; + ecdsa.sign_counterparty_commitment(channel_parameters, &counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &self.secp_ctx) .map(|(signature, _)| signature) .map_err(|_| ChannelError::Close( ( @@ -6592,7 +6594,7 @@ impl FundedChannel where let funding_signed = if self.context.signer_pending_funding && !self.funding.is_outbound() { let counterparty_keys = self.context.build_remote_transaction_keys(&self.funding); let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(&self.funding, self.context.cur_counterparty_commitment_transaction_number + 1, &counterparty_keys, false, false, logger).tx; - self.context.get_funding_signed_msg(logger, counterparty_initial_commitment_tx) + self.context.get_funding_signed_msg(&self.funding.channel_transaction_parameters, logger, counterparty_initial_commitment_tx) } else { None }; // Provide a `channel_ready` message if we need to, but only if we're _not_ still pending // funding. @@ -8572,6 +8574,7 @@ impl FundedChannel where } let res = ecdsa.sign_counterparty_commitment( + &self.funding.channel_transaction_parameters, &commitment_stats.tx, commitment_stats.inbound_htlc_preimages, commitment_stats.outbound_htlc_preimages, @@ -9045,7 +9048,8 @@ impl OutboundV1Channel where SP::Target: SignerProvider { let signature = match &self.context.holder_signer { // TODO (taproot|arik): move match into calling method for Taproot ChannelSignerType::Ecdsa(ecdsa) => { - ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &self.context.secp_ctx) + let channel_parameters = &self.funding.channel_transaction_parameters; + ecdsa.sign_counterparty_commitment(channel_parameters, &counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &self.context.secp_ctx) .map(|(sig, _)| sig).ok() }, // TODO (taproot|arik) @@ -9496,7 +9500,9 @@ impl InboundV1Channel where SP::Target: SignerProvider { Err(err) => return Err((self, err)), }; - let funding_signed = self.context.get_funding_signed_msg(logger, counterparty_initial_commitment_tx); + let funding_signed = self.context.get_funding_signed_msg( + &self.funding.channel_transaction_parameters, logger, counterparty_initial_commitment_tx + ); log_info!(logger, "{} funding_signed for peer for channel {}", if funding_signed.is_some() { "Generated" } else { "Waiting for signature on" }, &self.context.channel_id()); diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 618f5b0780a..d0b89198df1 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -771,7 +771,10 @@ fn test_update_fee_that_funder_cannot_afford() { &mut htlcs, &local_chan.funding.channel_transaction_parameters.as_counterparty_broadcastable() ); - local_chan_signer.as_ecdsa().unwrap().sign_counterparty_commitment(&commitment_tx, Vec::new(), Vec::new(), &secp_ctx).unwrap() + local_chan_signer.as_ecdsa().unwrap().sign_counterparty_commitment( + &local_chan.funding.channel_transaction_parameters, &commitment_tx, Vec::new(), + Vec::new(), &secp_ctx, + ).unwrap() }; let commit_signed_msg = msgs::CommitmentSigned { @@ -1514,7 +1517,10 @@ fn test_fee_spike_violation_fails_htlc() { &mut vec![(accepted_htlc_info, ())], &local_chan.funding.channel_transaction_parameters.as_counterparty_broadcastable() ); - local_chan_signer.as_ecdsa().unwrap().sign_counterparty_commitment(&commitment_tx, Vec::new(), Vec::new(), &secp_ctx).unwrap() + local_chan_signer.as_ecdsa().unwrap().sign_counterparty_commitment( + &local_chan.funding.channel_transaction_parameters, &commitment_tx, Vec::new(), + Vec::new(), &secp_ctx, + ).unwrap() }; let commit_signed_msg = msgs::CommitmentSigned { diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index 2f42d332962..3d050c2c389 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -15,7 +15,7 @@ use crate::types::payment::PaymentPreimage; #[allow(unused_imports)] use crate::prelude::*; -use crate::sign::{ChannelSigner, HTLCDescriptor}; +use crate::sign::{ChannelSigner, ChannelTransactionParameters, HTLCDescriptor}; /// A trait to sign Lightning channel transactions as described in /// [BOLT 3](https://github.com/lightning/bolts/blob/master/03-transactions.md). @@ -53,7 +53,8 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// /// [`ChannelManager::signer_unblocked`]: crate::ln::channelmanager::ChannelManager::signer_unblocked fn sign_counterparty_commitment( - &self, commitment_tx: &CommitmentTransaction, inbound_htlc_preimages: Vec, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &CommitmentTransaction, inbound_htlc_preimages: Vec, outbound_htlc_preimages: Vec, secp_ctx: &Secp256k1, ) -> Result<(Signature, Vec), ()>; /// Creates a signature for a holder's commitment transaction. diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 0d483b0017d..553079246d2 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1390,15 +1390,16 @@ const MISSING_PARAMS_ERR: &'static str = impl EcdsaChannelSigner for InMemorySigner { fn sign_counterparty_commitment( - &self, commitment_tx: &CommitmentTransaction, - _inbound_htlc_preimages: Vec, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &CommitmentTransaction, _inbound_htlc_preimages: Vec, _outbound_htlc_preimages: Vec, secp_ctx: &Secp256k1, ) -> Result<(Signature, Vec), ()> { let trusted_tx = commitment_tx.trust(); let keys = trusted_tx.keys(); let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); - let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); + let counterparty_keys = + channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &counterparty_keys.funding_pubkey); @@ -1406,16 +1407,14 @@ impl EcdsaChannelSigner for InMemorySigner { let commitment_sig = built_tx.sign_counterparty_commitment( &self.funding_key, &channel_funding_redeemscript, - self.channel_value_satoshis, + channel_parameters.channel_value_satoshis, secp_ctx, ); let commitment_txid = built_tx.txid; let mut htlc_sigs = Vec::with_capacity(commitment_tx.htlcs().len()); for htlc in commitment_tx.htlcs() { - let channel_parameters = self.get_channel_parameters().expect(MISSING_PARAMS_ERR); - let holder_selected_contest_delay = - self.holder_selected_contest_delay().expect(MISSING_PARAMS_ERR); + let holder_selected_contest_delay = channel_parameters.holder_selected_contest_delay; let chan_type = &channel_parameters.channel_type_features; let htlc_tx = chan_utils::build_htlc_transaction( &commitment_txid, diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 77dd34ffb88..986326baa6a 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -229,10 +229,11 @@ impl ChannelSigner for TestChannelSigner { impl EcdsaChannelSigner for TestChannelSigner { fn sign_counterparty_commitment( - &self, commitment_tx: &CommitmentTransaction, inbound_htlc_preimages: Vec, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &CommitmentTransaction, inbound_htlc_preimages: Vec, outbound_htlc_preimages: Vec, secp_ctx: &Secp256k1, ) -> Result<(Signature, Vec), ()> { - self.verify_counterparty_commitment_tx(commitment_tx, secp_ctx); + self.verify_counterparty_commitment_tx(channel_parameters, commitment_tx, secp_ctx); { #[cfg(test)] @@ -266,6 +267,7 @@ impl EcdsaChannelSigner for TestChannelSigner { Ok(self .inner .sign_counterparty_commitment( + channel_parameters, commitment_tx, inbound_htlc_preimages, outbound_htlc_preimages, @@ -530,13 +532,14 @@ impl TaprootChannelSigner for TestChannelSigner { impl TestChannelSigner { fn verify_counterparty_commitment_tx<'a, T: secp256k1::Signing + secp256k1::Verification>( - &self, commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1, ) -> TrustedCommitmentTransaction<'a> { commitment_tx .verify( - &self.inner.get_channel_parameters().unwrap().as_counterparty_broadcastable(), - self.inner.counterparty_pubkeys().unwrap(), - self.inner.pubkeys(), + &channel_parameters.as_counterparty_broadcastable(), + channel_parameters.counterparty_pubkeys().unwrap(), + &channel_parameters.holder_pubkeys, secp_ctx, ) .expect("derived different per-tx keys or built transaction") From f638ba48d22e91fa9a1516e672148ba3dbaa3ae6 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 20 Feb 2025 14:16:46 -0600 Subject: [PATCH 08/20] Pass channel params to sign_holder_commitment Now that channel_value_satoshis has been moved to ChannelTransactionParameters, pass the entire parameters when calling each method on EcdsaChannelSigner. This will remove the need for ChannelSigner::provide_channel_parameters. Instead, the parameters from the FundingScope will be passed in to each method. This simplifies the interaction with a ChannelSigner when needing to be called for more than one FundingScope, which will be the case for pending splices and RBF attempts. --- lightning/src/chain/onchaintx.rs | 4 ++-- lightning/src/ln/channel.rs | 2 +- lightning/src/sign/ecdsa.rs | 6 ++++-- lightning/src/sign/mod.rs | 16 +++++++++------ lightning/src/util/test_channel_signer.rs | 25 +++++++++++++++-------- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index 8e30cd07522..cc9feb80f3b 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -1188,7 +1188,7 @@ impl OnchainTxHandler { } pub(crate) fn get_maybe_signed_holder_tx(&mut self, funding_redeemscript: &Script) -> MaybeSignedTransaction { - let tx = self.signer.sign_holder_commitment(&self.holder_commitment, &self.secp_ctx) + let tx = self.signer.sign_holder_commitment(&self.channel_transaction_parameters, &self.holder_commitment, &self.secp_ctx) .map(|sig| self.holder_commitment.add_holder_sig(funding_redeemscript, sig)) .unwrap_or_else(|_| self.get_unsigned_holder_commitment_tx().clone()); MaybeSignedTransaction(tx) @@ -1196,7 +1196,7 @@ impl OnchainTxHandler { #[cfg(any(test, feature="unsafe_revoked_tx_signing"))] pub(crate) fn get_fully_signed_copy_holder_tx(&mut self, funding_redeemscript: &Script) -> Transaction { - let sig = self.signer.unsafe_sign_holder_commitment(&self.holder_commitment, &self.secp_ctx).expect("sign holder commitment"); + let sig = self.signer.unsafe_sign_holder_commitment(&self.channel_transaction_parameters, &self.holder_commitment, &self.secp_ctx).expect("sign holder commitment"); self.holder_commitment.add_holder_sig(funding_redeemscript, sig) } diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index f77a0b3ecda..6658db2df94 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -11722,7 +11722,7 @@ mod tests { &chan.context.holder_signer.as_ref().pubkeys().funding_pubkey, chan.funding.counterparty_funding_pubkey() ); - let holder_sig = signer.sign_holder_commitment(&holder_commitment_tx, &secp_ctx).unwrap(); + let holder_sig = signer.sign_holder_commitment(&chan.funding.channel_transaction_parameters, &holder_commitment_tx, &secp_ctx).unwrap(); assert_eq!(Signature::from_der(&>::from_hex($sig_hex).unwrap()[..]).unwrap(), holder_sig, "holder_sig"); let funding_redeemscript = chan.funding.get_funding_redeemscript(); diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index 3d050c2c389..c55214853d9 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -75,7 +75,8 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// [`ChannelMonitor::signer_unblocked`]: crate::chain::channelmonitor::ChannelMonitor::signer_unblocked /// [`ChainMonitor::signer_unblocked`]: crate::chain::chainmonitor::ChainMonitor::signer_unblocked fn sign_holder_commitment( - &self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, ) -> Result; /// Same as [`sign_holder_commitment`], but exists only for tests to get access to holder /// commitment transactions which will be broadcasted later, after the channel has moved on to a @@ -85,7 +86,8 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// This method is *not* async as it is intended only for testing purposes. #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))] fn unsafe_sign_holder_commitment( - &self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, ) -> Result; /// Create a signature for the given input in a transaction spending an HTLC transaction output /// or a commitment transaction `to_local` output when our counterparty broadcasts an old state. diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 553079246d2..24a2549ec9c 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1453,17 +1453,19 @@ impl EcdsaChannelSigner for InMemorySigner { } fn sign_holder_commitment( - &self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, ) -> Result { let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); - let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); + let counterparty_keys = + channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &counterparty_keys.funding_pubkey); let trusted_tx = commitment_tx.trust(); Ok(trusted_tx.built_transaction().sign_holder_commitment( &self.funding_key, &funding_redeemscript, - self.channel_value_satoshis, + channel_parameters.channel_value_satoshis, &self, secp_ctx, )) @@ -1471,17 +1473,19 @@ impl EcdsaChannelSigner for InMemorySigner { #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))] fn unsafe_sign_holder_commitment( - &self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, ) -> Result { let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); - let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); + let counterparty_keys = + channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, &counterparty_keys.funding_pubkey); let trusted_tx = commitment_tx.trust(); Ok(trusted_tx.built_transaction().sign_holder_commitment( &self.funding_key, &funding_redeemscript, - self.channel_value_satoshis, + channel_parameters.channel_value_satoshis, &self, secp_ctx, )) diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 986326baa6a..c87eabf6efe 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -277,13 +277,15 @@ impl EcdsaChannelSigner for TestChannelSigner { } fn sign_holder_commitment( - &self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, ) -> Result { #[cfg(test)] if !self.is_signer_available(SignerOp::SignHolderCommitment) { return Err(()); } - let trusted_tx = self.verify_holder_commitment_tx(commitment_tx, secp_ctx); + let trusted_tx = + self.verify_holder_commitment_tx(channel_parameters, commitment_tx, secp_ctx); let state = self.state.lock().unwrap(); let commitment_number = trusted_tx.commitment_number(); if state.last_holder_revoked_commitment - 1 != commitment_number @@ -294,14 +296,18 @@ impl EcdsaChannelSigner for TestChannelSigner { state.last_holder_revoked_commitment, commitment_number, self.inner.commitment_seed[0]) } } - Ok(self.inner.sign_holder_commitment(commitment_tx, secp_ctx).unwrap()) + Ok(self.inner.sign_holder_commitment(channel_parameters, commitment_tx, secp_ctx).unwrap()) } #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))] fn unsafe_sign_holder_commitment( - &self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, ) -> Result { - Ok(self.inner.unsafe_sign_holder_commitment(commitment_tx, secp_ctx).unwrap()) + Ok(self + .inner + .unsafe_sign_holder_commitment(channel_parameters, commitment_tx, secp_ctx) + .unwrap()) } fn sign_justice_revoked_output( @@ -546,13 +552,14 @@ impl TestChannelSigner { } fn verify_holder_commitment_tx<'a, T: secp256k1::Signing + secp256k1::Verification>( - &self, commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &'a CommitmentTransaction, secp_ctx: &Secp256k1, ) -> TrustedCommitmentTransaction<'a> { commitment_tx .verify( - &self.inner.get_channel_parameters().unwrap().as_holder_broadcastable(), - self.inner.pubkeys(), - self.inner.counterparty_pubkeys().unwrap(), + &channel_parameters.as_holder_broadcastable(), + &channel_parameters.holder_pubkeys, + channel_parameters.counterparty_pubkeys().unwrap(), secp_ctx, ) .expect("derived different per-tx keys or built transaction") From 3e9ab723c3bf4986906807f5ee961220d9dc470b Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 20 Feb 2025 15:05:54 -0600 Subject: [PATCH 09/20] Pass channel params to sign_justice_revoked_output Now that channel_value_satoshis has been moved to ChannelTransactionParameters, pass the entire parameters when calling each method on EcdsaChannelSigner. This will remove the need for ChannelSigner::provide_channel_parameters. Instead, the parameters from the FundingScope will be passed in to each method. This simplifies the interaction with a ChannelSigner when needing to be called for more than one FundingScope, which will be the case for pending splices and RBF attempts. --- lightning/src/chain/channelmonitor.rs | 5 ++++- lightning/src/chain/package.rs | 3 ++- lightning/src/sign/ecdsa.rs | 3 ++- lightning/src/sign/mod.rs | 11 ++++++----- lightning/src/util/test_channel_signer.rs | 4 +++- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 0d3c6d1fe75..19a064820d3 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -3517,8 +3517,11 @@ impl ChannelMonitorImpl { let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.counterparty_commitment_params.on_counterparty_tx_csv, &delayed_key); + let channel_parameters = &self.onchain_tx_handler.channel_transaction_parameters; let sig = self.onchain_tx_handler.signer.sign_justice_revoked_output( - &justice_tx, input_idx, value, &per_commitment_key, &self.onchain_tx_handler.secp_ctx)?; + &channel_parameters, &justice_tx, input_idx, value, &per_commitment_key, + &self.onchain_tx_handler.secp_ctx, + )?; justice_tx.input[input_idx].witness.push_ecdsa_signature(&BitcoinSignature::sighash_all(sig)); justice_tx.input[input_idx].witness.push(&[1u8]); justice_tx.input[input_idx].witness.push(revokeable_redeemscript.as_bytes()); diff --git a/lightning/src/chain/package.rs b/lightning/src/chain/package.rs index ef4f14d8263..76ebbfb3ceb 100644 --- a/lightning/src/chain/package.rs +++ b/lightning/src/chain/package.rs @@ -602,12 +602,13 @@ impl PackageSolvingData { } } fn finalize_input(&self, bumped_tx: &mut Transaction, i: usize, onchain_handler: &mut OnchainTxHandler) -> bool { + let channel_parameters = &onchain_handler.channel_transaction_parameters; match self { PackageSolvingData::RevokedOutput(ref outp) => { let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint); let witness_script = chan_utils::get_revokeable_redeemscript(&chan_keys.revocation_key, outp.on_counterparty_tx_csv, &chan_keys.broadcaster_delayed_payment_key); //TODO: should we panic on signer failure ? - if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_output(&bumped_tx, i, outp.amount.to_sat(), &outp.per_commitment_key, &onchain_handler.secp_ctx) { + if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_output(channel_parameters, &bumped_tx, i, outp.amount.to_sat(), &outp.per_commitment_key, &onchain_handler.secp_ctx) { let mut ser_sig = sig.serialize_der().to_vec(); ser_sig.push(EcdsaSighashType::All as u8); bumped_tx.input[i].witness.push(ser_sig); diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index c55214853d9..2bf4fa6e596 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -112,7 +112,8 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// [`ChannelMonitor::signer_unblocked`]: crate::chain::channelmonitor::ChannelMonitor::signer_unblocked /// [`ChainMonitor::signer_unblocked`]: crate::chain::chainmonitor::ChainMonitor::signer_unblocked fn sign_justice_revoked_output( - &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + &self, channel_parameters: &ChannelTransactionParameters, justice_tx: &Transaction, + input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1, ) -> Result; /// Create a signature for the given input in a transaction spending a commitment transaction diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 24a2549ec9c..565967f04cc 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1492,7 +1492,8 @@ impl EcdsaChannelSigner for InMemorySigner { } fn sign_justice_revoked_output( - &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + &self, channel_parameters: &ChannelTransactionParameters, justice_tx: &Transaction, + input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1, ) -> Result { let revocation_key = chan_utils::derive_private_revocation_key( @@ -1503,13 +1504,13 @@ impl EcdsaChannelSigner for InMemorySigner { let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key); let revocation_pubkey = RevocationKey::from_basepoint( &secp_ctx, - &self.pubkeys().revocation_basepoint, + &channel_parameters.holder_pubkeys.revocation_basepoint, &per_commitment_point, ); let witness_script = { - let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); - let holder_selected_contest_delay = - self.holder_selected_contest_delay().expect(MISSING_PARAMS_ERR); + let counterparty_keys = + channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); + let holder_selected_contest_delay = channel_parameters.holder_selected_contest_delay; let counterparty_delayedpubkey = DelayedPaymentKey::from_basepoint( &secp_ctx, &counterparty_keys.delayed_payment_basepoint, diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index c87eabf6efe..3536688b095 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -311,7 +311,8 @@ impl EcdsaChannelSigner for TestChannelSigner { } fn sign_justice_revoked_output( - &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + &self, channel_parameters: &ChannelTransactionParameters, justice_tx: &Transaction, + input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1, ) -> Result { #[cfg(test)] @@ -320,6 +321,7 @@ impl EcdsaChannelSigner for TestChannelSigner { } Ok(EcdsaChannelSigner::sign_justice_revoked_output( &self.inner, + channel_parameters, justice_tx, input, amount, From a3420d0e058831639e8e08347acfea376f8e9ec9 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 20 Feb 2025 15:56:27 -0600 Subject: [PATCH 10/20] Pass channel params to sign_justice_revoked_htlc Now that channel_value_satoshis has been moved to ChannelTransactionParameters, pass the entire parameters when calling each method on EcdsaChannelSigner. This will remove the need for ChannelSigner::provide_channel_parameters. Instead, the parameters from the FundingScope will be passed in to each method. This simplifies the interaction with a ChannelSigner when needing to be called for more than one FundingScope, which will be the case for pending splices and RBF attempts. --- lightning/src/chain/package.rs | 2 +- lightning/src/sign/ecdsa.rs | 5 +++-- lightning/src/sign/mod.rs | 15 ++++++++------- lightning/src/util/test_channel_signer.rs | 6 ++++-- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/lightning/src/chain/package.rs b/lightning/src/chain/package.rs index 76ebbfb3ceb..caca8be1c26 100644 --- a/lightning/src/chain/package.rs +++ b/lightning/src/chain/package.rs @@ -620,7 +620,7 @@ impl PackageSolvingData { let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint); let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); //TODO: should we panic on signer failure ? - if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_htlc(&bumped_tx, i, outp.amount, &outp.per_commitment_key, &outp.htlc, &onchain_handler.secp_ctx) { + if let Ok(sig) = onchain_handler.signer.sign_justice_revoked_htlc(channel_parameters, &bumped_tx, i, outp.amount, &outp.per_commitment_key, &outp.htlc, &onchain_handler.secp_ctx) { let mut ser_sig = sig.serialize_der().to_vec(); ser_sig.push(EcdsaSighashType::All as u8); bumped_tx.input[i].witness.push(ser_sig); diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index 2bf4fa6e596..4df32d159d9 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -143,8 +143,9 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// [`ChannelMonitor::signer_unblocked`]: crate::chain::channelmonitor::ChannelMonitor::signer_unblocked /// [`ChainMonitor::signer_unblocked`]: crate::chain::chainmonitor::ChainMonitor::signer_unblocked fn sign_justice_revoked_htlc( - &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, - htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, justice_tx: &Transaction, + input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, + secp_ctx: &Secp256k1, ) -> Result; /// Computes the signature for a commitment transaction's HTLC output used as an input within /// `htlc_tx`, which spends the commitment transaction at index `input`. The signature returned diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 565967f04cc..1867d72d3fa 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1537,8 +1537,9 @@ impl EcdsaChannelSigner for InMemorySigner { } fn sign_justice_revoked_htlc( - &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, - htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, justice_tx: &Transaction, + input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, + secp_ctx: &Secp256k1, ) -> Result { let revocation_key = chan_utils::derive_private_revocation_key( &secp_ctx, @@ -1548,11 +1549,12 @@ impl EcdsaChannelSigner for InMemorySigner { let per_commitment_point = PublicKey::from_secret_key(secp_ctx, &per_commitment_key); let revocation_pubkey = RevocationKey::from_basepoint( &secp_ctx, - &self.pubkeys().revocation_basepoint, + &channel_parameters.holder_pubkeys.revocation_basepoint, &per_commitment_point, ); let witness_script = { - let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); + let counterparty_keys = + channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); let counterparty_htlcpubkey = HtlcKey::from_basepoint( &secp_ctx, &counterparty_keys.htlc_basepoint, @@ -1560,13 +1562,12 @@ impl EcdsaChannelSigner for InMemorySigner { ); let holder_htlcpubkey = HtlcKey::from_basepoint( &secp_ctx, - &self.pubkeys().htlc_basepoint, + &channel_parameters.holder_pubkeys.htlc_basepoint, &per_commitment_point, ); - let chan_type = self.channel_type_features().expect(MISSING_PARAMS_ERR); chan_utils::get_htlc_redeemscript_with_explicit_keys( &htlc, - chan_type, + &channel_parameters.channel_type_features, &counterparty_htlcpubkey, &holder_htlcpubkey, &revocation_pubkey, diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 3536688b095..723ffa2862e 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -332,8 +332,9 @@ impl EcdsaChannelSigner for TestChannelSigner { } fn sign_justice_revoked_htlc( - &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, - htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, justice_tx: &Transaction, + input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, + secp_ctx: &Secp256k1, ) -> Result { #[cfg(test)] if !self.is_signer_available(SignerOp::SignJusticeRevokedHtlc) { @@ -341,6 +342,7 @@ impl EcdsaChannelSigner for TestChannelSigner { } Ok(EcdsaChannelSigner::sign_justice_revoked_htlc( &self.inner, + channel_parameters, justice_tx, input, amount, From 18e0d6aa7f086119c52e6903ce5a4d72a8f4bacf Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 20 Feb 2025 17:26:46 -0600 Subject: [PATCH 11/20] Pass channel params to sign_counterparty_htlc_transaction Now that channel_value_satoshis has been moved to ChannelTransactionParameters, pass the entire parameters when calling each method on EcdsaChannelSigner. This will remove the need for ChannelSigner::provide_channel_parameters. Instead, the parameters from the FundingScope will be passed in to each method. This simplifies the interaction with a ChannelSigner when needing to be called for more than one FundingScope, which will be the case for pending splices and RBF attempts. --- lightning/src/chain/package.rs | 4 ++-- lightning/src/sign/ecdsa.rs | 5 +++-- lightning/src/sign/mod.rs | 14 ++++++++------ lightning/src/util/test_channel_signer.rs | 6 ++++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lightning/src/chain/package.rs b/lightning/src/chain/package.rs index caca8be1c26..f7fe3fef92f 100644 --- a/lightning/src/chain/package.rs +++ b/lightning/src/chain/package.rs @@ -632,7 +632,7 @@ impl PackageSolvingData { let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint); let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); - if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(&bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) { + if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(channel_parameters, &bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) { let mut ser_sig = sig.serialize_der().to_vec(); ser_sig.push(EcdsaSighashType::All as u8); bumped_tx.input[i].witness.push(ser_sig); @@ -644,7 +644,7 @@ impl PackageSolvingData { let chan_keys = TxCreationKeys::derive_new(&onchain_handler.secp_ctx, &outp.per_commitment_point, &outp.counterparty_delayed_payment_base_key, &outp.counterparty_htlc_base_key, &onchain_handler.signer.pubkeys().revocation_basepoint, &onchain_handler.signer.pubkeys().htlc_basepoint); let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&outp.htlc, &onchain_handler.channel_type_features(), &chan_keys.broadcaster_htlc_key, &chan_keys.countersignatory_htlc_key, &chan_keys.revocation_key); - if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(&bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) { + if let Ok(sig) = onchain_handler.signer.sign_counterparty_htlc_transaction(channel_parameters, &bumped_tx, i, &outp.htlc.amount_msat / 1000, &outp.per_commitment_point, &outp.htlc, &onchain_handler.secp_ctx) { let mut ser_sig = sig.serialize_der().to_vec(); ser_sig.push(EcdsaSighashType::All as u8); bumped_tx.input[i].witness.push(ser_sig); diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index 4df32d159d9..c4d1897fa83 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -194,8 +194,9 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// [`ChannelMonitor::signer_unblocked`]: crate::chain::channelmonitor::ChannelMonitor::signer_unblocked /// [`ChainMonitor::signer_unblocked`]: crate::chain::chainmonitor::ChainMonitor::signer_unblocked fn sign_counterparty_htlc_transaction( - &self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, - htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, htlc_tx: &Transaction, + input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, + secp_ctx: &Secp256k1, ) -> Result; /// Create a signature for a (proposed) closing transaction. /// diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 1867d72d3fa..702a0189a8b 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1610,25 +1610,27 @@ impl EcdsaChannelSigner for InMemorySigner { } fn sign_counterparty_htlc_transaction( - &self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, - htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, htlc_tx: &Transaction, + input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, + secp_ctx: &Secp256k1, ) -> Result { let htlc_key = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &self.htlc_base_key); let revocation_pubkey = RevocationKey::from_basepoint( &secp_ctx, - &self.pubkeys().revocation_basepoint, + &channel_parameters.holder_pubkeys.revocation_basepoint, &per_commitment_point, ); - let counterparty_keys = self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); + let counterparty_keys = + channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); let counterparty_htlcpubkey = HtlcKey::from_basepoint( &secp_ctx, &counterparty_keys.htlc_basepoint, &per_commitment_point, ); - let htlc_basepoint = self.pubkeys().htlc_basepoint; + let htlc_basepoint = channel_parameters.holder_pubkeys.htlc_basepoint; let htlcpubkey = HtlcKey::from_basepoint(&secp_ctx, &htlc_basepoint, &per_commitment_point); - let chan_type = self.channel_type_features().expect(MISSING_PARAMS_ERR); + let chan_type = &channel_parameters.channel_type_features; let witness_script = chan_utils::get_htlc_redeemscript_with_explicit_keys( &htlc, chan_type, diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 723ffa2862e..16976c1f1c1 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -412,8 +412,9 @@ impl EcdsaChannelSigner for TestChannelSigner { } fn sign_counterparty_htlc_transaction( - &self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, - htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, htlc_tx: &Transaction, + input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, + secp_ctx: &Secp256k1, ) -> Result { #[cfg(test)] if !self.is_signer_available(SignerOp::SignCounterpartyHtlcTransaction) { @@ -421,6 +422,7 @@ impl EcdsaChannelSigner for TestChannelSigner { } Ok(EcdsaChannelSigner::sign_counterparty_htlc_transaction( &self.inner, + channel_parameters, htlc_tx, input, amount, From 8379161ad948a2b306f94badc6aa46c13cf7f1cd Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 20 Feb 2025 18:05:09 -0600 Subject: [PATCH 12/20] Pass channel params to sign_closing_transaction Now that channel_value_satoshis has been moved to ChannelTransactionParameters, pass the entire parameters when calling each method on EcdsaChannelSigner. This will remove the need for ChannelSigner::provide_channel_parameters. Instead, the parameters from the FundingScope will be passed in to each method. This simplifies the interaction with a ChannelSigner when needing to be called for more than one FundingScope, which will be the case for pending splices and RBF attempts. --- lightning/src/ln/async_signer_tests.rs | 5 +++-- lightning/src/ln/channel.rs | 2 +- lightning/src/sign/ecdsa.rs | 3 ++- lightning/src/sign/mod.rs | 15 ++++----------- lightning/src/util/test_channel_signer.rs | 7 ++++--- 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/lightning/src/ln/async_signer_tests.rs b/lightning/src/ln/async_signer_tests.rs index 0cd78738e9b..2ebf75454f4 100644 --- a/lightning/src/ln/async_signer_tests.rs +++ b/lightning/src/ln/async_signer_tests.rs @@ -1022,10 +1022,11 @@ fn do_test_closing_signed(extra_closing_signed: bool, reconnect: bool) { let per_peer_state = nodes[1].node.per_peer_state.read().unwrap(); let mut chan_lock = per_peer_state.get(&nodes[0].node.get_our_node_id()).unwrap().lock().unwrap(); - let context = chan_lock.channel_by_id.get_mut(&chan_id).map(|chan| chan.context_mut()).unwrap(); + let channel = chan_lock.channel_by_id.get_mut(&chan_id).unwrap(); + let (funding, context) = channel.funding_and_context_mut(); let signer = context.get_mut_signer().as_mut_ecdsa().unwrap(); - let signature = signer.sign_closing_transaction(&closing_tx_2, &Secp256k1::new()).unwrap(); + let signature = signer.sign_closing_transaction(&funding.channel_transaction_parameters, &closing_tx_2, &Secp256k1::new()).unwrap(); node_1_closing_signed_2.signature = signature; node_1_closing_signed_2 }; diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 6658db2df94..8af5ff54e6a 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -7292,7 +7292,7 @@ impl FundedChannel where where L::Target: Logger { let sig = match &self.context.holder_signer { - ChannelSignerType::Ecdsa(ecdsa) => ecdsa.sign_closing_transaction(closing_tx, &self.context.secp_ctx).ok(), + ChannelSignerType::Ecdsa(ecdsa) => ecdsa.sign_closing_transaction(&self.funding.channel_transaction_parameters, closing_tx, &self.context.secp_ctx).ok(), // TODO (taproot|arik) #[cfg(taproot)] _ => todo!() diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index c4d1897fa83..ffb93f0ae6c 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -209,7 +209,8 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// /// [`ChannelManager::signer_unblocked`]: crate::ln::channelmanager::ChannelManager::signer_unblocked fn sign_closing_transaction( - &self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, closing_tx: &ClosingTransaction, + secp_ctx: &Secp256k1, ) -> Result; /// Computes the signature for a commitment transaction's anchor output used as an /// input within `anchor_tx`, which spends the commitment transaction, at index `input`. diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 702a0189a8b..827e05d61b8 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1161,14 +1161,6 @@ impl InMemorySigner { self.get_channel_parameters().map(|params| params.is_outbound_from_holder) } - /// Funding outpoint - /// - /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. - /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. - pub fn funding_outpoint(&self) -> Option<&OutPoint> { - self.get_channel_parameters().map(|params| params.funding_outpoint.as_ref()).flatten() - } - /// Returns a [`ChannelTransactionParameters`] for this channel, to be used when verifying or /// building transactions. /// @@ -1653,17 +1645,18 @@ impl EcdsaChannelSigner for InMemorySigner { } fn sign_closing_transaction( - &self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, closing_tx: &ClosingTransaction, + secp_ctx: &Secp256k1, ) -> Result { let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); let counterparty_funding_key = - &self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR).funding_pubkey; + &channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR).funding_pubkey; let channel_funding_redeemscript = make_funding_redeemscript(&funding_pubkey, counterparty_funding_key); Ok(closing_tx.trust().sign( &self.funding_key, &channel_funding_redeemscript, - self.channel_value_satoshis, + channel_parameters.channel_value_satoshis, secp_ctx, )) } diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 16976c1f1c1..d7b83674377 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -434,16 +434,17 @@ impl EcdsaChannelSigner for TestChannelSigner { } fn sign_closing_transaction( - &self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, closing_tx: &ClosingTransaction, + secp_ctx: &Secp256k1, ) -> Result { #[cfg(test)] if !self.is_signer_available(SignerOp::SignClosingTransaction) { return Err(()); } closing_tx - .verify(self.inner.funding_outpoint().unwrap().into_bitcoin_outpoint()) + .verify(channel_parameters.funding_outpoint.as_ref().unwrap().into_bitcoin_outpoint()) .expect("derived different closing transaction"); - Ok(self.inner.sign_closing_transaction(closing_tx, secp_ctx).unwrap()) + Ok(self.inner.sign_closing_transaction(channel_parameters, closing_tx, secp_ctx).unwrap()) } fn sign_holder_anchor_input( From dcea1ac876bdf704efc1ae5459e53590dddf734f Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Fri, 21 Feb 2025 15:27:59 -0600 Subject: [PATCH 13/20] Pass channel params to sign_holder_anchor_input Now that channel_value_satoshis has been moved to ChannelTransactionParameters, pass the entire parameters when calling each method on EcdsaChannelSigner. This will remove the need for ChannelSigner::provide_channel_parameters. Instead, the parameters from the FundingScope will be passed in to each method. This simplifies the interaction with a ChannelSigner when needing to be called for more than one FundingScope, which will be the case for pending splices and RBF attempts. --- lightning/src/events/bump_transaction.rs | 3 ++- lightning/src/sign/ecdsa.rs | 3 ++- lightning/src/sign/mod.rs | 5 +++-- lightning/src/util/test_channel_signer.rs | 11 +++++++++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs index ae7d8ef3c56..2cb10d0e240 100644 --- a/lightning/src/events/bump_transaction.rs +++ b/lightning/src/events/bump_transaction.rs @@ -690,7 +690,8 @@ where anchor_tx = self.utxo_source.sign_psbt(anchor_psbt)?; let signer = anchor_descriptor.derive_channel_signer(&self.signer_provider); - let anchor_sig = signer.sign_holder_anchor_input(&anchor_tx, 0, &self.secp)?; + let channel_parameters = &anchor_descriptor.channel_derivation_parameters.transaction_parameters; + let anchor_sig = signer.sign_holder_anchor_input(channel_parameters, &anchor_tx, 0, &self.secp)?; anchor_tx.input[0].witness = anchor_descriptor.tx_input_witness(&anchor_sig); #[cfg(debug_assertions)] { diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index ffb93f0ae6c..477418a81e7 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -223,7 +223,8 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// [`ChannelMonitor::signer_unblocked`]: crate::chain::channelmonitor::ChannelMonitor::signer_unblocked /// [`ChainMonitor::signer_unblocked`]: crate::chain::chainmonitor::ChainMonitor::signer_unblocked fn sign_holder_anchor_input( - &self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, anchor_tx: &Transaction, + input: usize, secp_ctx: &Secp256k1, ) -> Result; /// Signs a channel announcement message with our funding key proving it comes from one of the /// channel participants. diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 827e05d61b8..0d117abb1c3 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1662,10 +1662,11 @@ impl EcdsaChannelSigner for InMemorySigner { } fn sign_holder_anchor_input( - &self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, anchor_tx: &Transaction, + input: usize, secp_ctx: &Secp256k1, ) -> Result { let witness_script = - chan_utils::get_anchor_redeemscript(&self.holder_channel_pubkeys.funding_pubkey); + chan_utils::get_anchor_redeemscript(&channel_parameters.holder_pubkeys.funding_pubkey); let sighash = sighash::SighashCache::new(&*anchor_tx) .p2wsh_signature_hash( input, diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index d7b83674377..e6a9539de64 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -448,7 +448,8 @@ impl EcdsaChannelSigner for TestChannelSigner { } fn sign_holder_anchor_input( - &self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, anchor_tx: &Transaction, + input: usize, secp_ctx: &Secp256k1, ) -> Result { debug_assert!(MIN_CHAN_DUST_LIMIT_SATOSHIS > ANCHOR_OUTPUT_VALUE_SATOSHI); // As long as our minimum dust limit is enforced and is greater than our anchor output @@ -461,7 +462,13 @@ impl EcdsaChannelSigner for TestChannelSigner { if !self.is_signer_available(SignerOp::SignHolderAnchorInput) { return Err(()); } - EcdsaChannelSigner::sign_holder_anchor_input(&self.inner, anchor_tx, input, secp_ctx) + EcdsaChannelSigner::sign_holder_anchor_input( + &self.inner, + channel_parameters, + anchor_tx, + input, + secp_ctx, + ) } fn sign_channel_announcement_with_funding_key( From e74c698e0b3aa70ce8e17f7fa791c77831f15114 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Fri, 21 Feb 2025 15:52:59 -0600 Subject: [PATCH 14/20] Pass channel params to sign_splicing_funding_input Now that channel_value_satoshis has been moved to ChannelTransactionParameters, pass the entire parameters when calling each method on EcdsaChannelSigner. This will remove the need for ChannelSigner::provide_channel_parameters. Instead, the parameters from the FundingScope will be passed in to each method. This simplifies the interaction with a ChannelSigner when needing to be called for more than one FundingScope, which will be the case for pending splices and RBF attempts. --- lightning/src/sign/ecdsa.rs | 4 ++-- lightning/src/sign/mod.rs | 6 +++--- lightning/src/util/test_channel_signer.rs | 12 +++++++++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index 477418a81e7..6fbf730ae17 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -254,7 +254,7 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// This method is *not* asynchronous. If an `Err` is returned, the channel will be immediately /// closed. fn sign_splicing_funding_input( - &self, tx: &Transaction, input_index: usize, input_value: u64, - secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, tx: &Transaction, + input_index: usize, input_value: u64, secp_ctx: &Secp256k1, ) -> Result; } diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 0d117abb1c3..e561768deb3 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1686,12 +1686,12 @@ impl EcdsaChannelSigner for InMemorySigner { } fn sign_splicing_funding_input( - &self, tx: &Transaction, input_index: usize, input_value: u64, - secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, tx: &Transaction, + input_index: usize, input_value: u64, secp_ctx: &Secp256k1, ) -> Result { let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); let counterparty_funding_key = - &self.counterparty_pubkeys().expect(MISSING_PARAMS_ERR).funding_pubkey; + &channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR).funding_pubkey; let funding_redeemscript = make_funding_redeemscript(&funding_pubkey, counterparty_funding_key); let sighash = &sighash::SighashCache::new(tx) diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index e6a9539de64..b272fade7fa 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -478,10 +478,16 @@ impl EcdsaChannelSigner for TestChannelSigner { } fn sign_splicing_funding_input( - &self, tx: &Transaction, input_index: usize, input_value: u64, - secp_ctx: &Secp256k1, + &self, channel_parameters: &ChannelTransactionParameters, tx: &Transaction, + input_index: usize, input_value: u64, secp_ctx: &Secp256k1, ) -> Result { - self.inner.sign_splicing_funding_input(tx, input_index, input_value, secp_ctx) + self.inner.sign_splicing_funding_input( + channel_parameters, + tx, + input_index, + input_value, + secp_ctx, + ) } } From 6caaa54a2f982d12a7e416965a24fb9e1380e317 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Mon, 24 Feb 2025 15:52:50 -0600 Subject: [PATCH 15/20] Use channel parameters in sign_counterparty_payment_input Now that channel_value_satoshis has been moved to ChannelTransactionParameters, InMemorySigner no longer needs a copy. Remove uses of the copy from sign_counterparty_payment_input. --- lightning/src/sign/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index e561768deb3..e2090532b6d 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1207,11 +1207,10 @@ impl InMemorySigner { } let remotepubkey = bitcoin::PublicKey::new(self.pubkeys().payment_point); - // We cannot always assume that `channel_parameters` is set, so can't just call - // `self.channel_parameters()` or anything that relies on it - let supports_anchors_zero_fee_htlc_tx = self - .channel_type_features() - .map(|features| features.supports_anchors_zero_fee_htlc_tx()) + let supports_anchors_zero_fee_htlc_tx = descriptor + .channel_transaction_parameters + .as_ref() + .map(|params| params.channel_type_features.supports_anchors_zero_fee_htlc_tx()) .unwrap_or(false); let witness_script = if supports_anchors_zero_fee_htlc_tx { From c8df41dc2399ba87d32948b6421fa9e658508139 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Mon, 24 Feb 2025 16:05:02 -0600 Subject: [PATCH 16/20] Use channel parameters in sign_holder_htlc_transaction Now that channel_value_satoshis has been moved to ChannelTransactionParameters, InMemorySigner no longer needs a copy. Remove indirect uses of the copy from TestChannelSigner. --- lightning/src/util/test_channel_signer.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index b272fade7fa..6d71f3a5c8c 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -36,7 +36,6 @@ use crate::ln::msgs::PartialSignatureWithNonce; #[cfg(taproot)] use crate::sign::taproot::TaprootChannelSigner; use crate::sign::HTLCDescriptor; -use crate::types::features::ChannelTypeFeatures; use bitcoin::secp256k1; #[cfg(taproot)] use bitcoin::secp256k1::All; @@ -137,10 +136,6 @@ impl TestChannelSigner { Self { inner, state, disable_revocation_policy_check } } - pub fn channel_type_features(&self) -> &ChannelTypeFeatures { - self.inner.channel_type_features().unwrap() - } - #[cfg(test)] pub fn get_enforcement_state(&self) -> MutexGuard { self.state.lock().unwrap() @@ -374,7 +369,10 @@ impl EcdsaChannelSigner for TestChannelSigner { assert_eq!(htlc_tx.output[input], htlc_descriptor.tx_output(secp_ctx)); { let witness_script = htlc_descriptor.witness_script(secp_ctx); - let sighash_type = if self.channel_type_features().supports_anchors_zero_fee_htlc_tx() { + let channel_parameters = + &htlc_descriptor.channel_derivation_parameters.transaction_parameters; + let channel_type_features = &channel_parameters.channel_type_features; + let sighash_type = if channel_type_features.supports_anchors_zero_fee_htlc_tx() { EcdsaSighashType::SinglePlusAnyoneCanPay } else { EcdsaSighashType::All @@ -389,7 +387,7 @@ impl EcdsaChannelSigner for TestChannelSigner { .unwrap(); let countersignatory_htlc_key = HtlcKey::from_basepoint( &secp_ctx, - &self.inner.counterparty_pubkeys().unwrap().htlc_basepoint, + &channel_parameters.counterparty_pubkeys().unwrap().htlc_basepoint, &htlc_descriptor.per_commitment_point, ); From 88bcf88716219f12c589f746bdd50243c5cf8dcb Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Mon, 24 Feb 2025 16:49:39 -0600 Subject: [PATCH 17/20] Remove ChannelSigner::provide_channel_parameters Now that the copy of ChannelTransactionParameters is no longer used by InMemorySigner, remove it and all remaining uses. Since it was set by ChannelSigner::provide_channel_parameters, this method is no longer needed and can also be removed. --- lightning/src/chain/onchaintx.rs | 5 +- lightning/src/events/bump_transaction.rs | 6 +- lightning/src/ln/channel.rs | 19 +-- lightning/src/ln/dual_funding_tests.rs | 11 +- lightning/src/sign/mod.rs | 136 +++++----------------- lightning/src/sign/type_resolver.rs | 9 -- lightning/src/util/test_channel_signer.rs | 4 - 7 files changed, 38 insertions(+), 152 deletions(-) diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index cc9feb80f3b..b2c45077705 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -25,7 +25,7 @@ use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature}; use bitcoin::secp256k1; use crate::chain::chaininterface::{ConfirmationTarget, compute_feerate_sat_per_1000_weight}; -use crate::sign::{ChannelDerivationParameters, HTLCDescriptor, ChannelSigner, EntropySource, SignerProvider, ecdsa::EcdsaChannelSigner}; +use crate::sign::{ChannelDerivationParameters, HTLCDescriptor, EntropySource, SignerProvider, ecdsa::EcdsaChannelSigner}; use crate::ln::msgs::DecodeError; use crate::types::payment::PaymentPreimage; use crate::ln::chan_utils::{self, ChannelTransactionParameters, HTLCOutputInCommitment, HolderCommitmentTransaction}; @@ -383,8 +383,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP bytes_read += bytes_to_read; } - let mut signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id); - signer.provide_channel_parameters(&channel_parameters); + let signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id); let pending_claim_requests_len: u64 = Readable::read(reader)?; let mut pending_claim_requests = hash_map_with_capacity(cmp::min(pending_claim_requests_len as usize, MAX_ALLOC_SIZE / 128)); diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs index 2cb10d0e240..5b71239d891 100644 --- a/lightning/src/events/bump_transaction.rs +++ b/lightning/src/events/bump_transaction.rs @@ -97,12 +97,10 @@ impl AnchorDescriptor { where SP::Target: SignerProvider { - let mut signer = signer_provider.derive_channel_signer( + signer_provider.derive_channel_signer( self.channel_derivation_parameters.value_satoshis, self.channel_derivation_parameters.keys_id, - ); - signer.provide_channel_parameters(&self.channel_derivation_parameters.transaction_parameters); - signer + ) } } diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 8af5ff54e6a..a6b25c367dc 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -2119,8 +2119,7 @@ trait InitialRemoteCommitmentReceiver where SP::Target: SignerProvide let funding_txo_script = funding_redeemscript.to_p2wsh(); let obscure_factor = get_commitment_transaction_number_obscure_factor(&funding.get_holder_pubkeys().payment_point, &funding.get_counterparty_pubkeys().payment_point, funding.is_outbound()); let shutdown_script = context.shutdown_scriptpubkey.clone().map(|script| script.into_inner()); - let mut monitor_signer = signer_provider.derive_channel_signer(funding.get_value_satoshis(), context.channel_keys_id); - monitor_signer.provide_channel_parameters(&funding.channel_transaction_parameters); + let monitor_signer = signer_provider.derive_channel_signer(funding.get_value_satoshis(), context.channel_keys_id); // TODO(RBF): When implementing RBF, the funding_txo passed here must only update // ChannelMonitorImp::first_confirmed_funding_txo during channel establishment, not splicing let channel_monitor = ChannelMonitor::new(context.secp_ctx.clone(), monitor_signer, @@ -2315,7 +2314,6 @@ impl PendingV2Channel where SP::Target: SignerProvider { ))); }; self.funding.channel_transaction_parameters.funding_outpoint = Some(outpoint); - self.context.holder_signer.as_mut().provide_channel_parameters(&self.funding.channel_transaction_parameters); self.context.assert_no_commitment_advancement(transaction_number, "initial commitment_signed"); let commitment_signed = self.context.get_initial_commitment_signed(&self.funding, logger); @@ -4571,7 +4569,7 @@ impl ChannelContext where SP::Target: SignerProvider { #[cfg(all(test))] pub fn get_initial_counterparty_commitment_signature_for_test( - &mut self, funding: &mut FundingScope, logger: &L, channel_transaction_parameters: ChannelTransactionParameters, + &mut self, funding: &mut FundingScope, logger: &L, counterparty_cur_commitment_point_override: PublicKey, ) -> Result where @@ -4579,7 +4577,6 @@ impl ChannelContext where SP::Target: SignerProvider { L::Target: Logger { self.counterparty_cur_commitment_point = Some(counterparty_cur_commitment_point_override); - funding.channel_transaction_parameters = channel_transaction_parameters; self.get_initial_counterparty_commitment_signature(funding, logger) } } @@ -9098,7 +9095,6 @@ impl OutboundV1Channel where SP::Target: SignerProvider { self.context.assert_no_commitment_advancement(self.unfunded_context.transaction_number(), "funding_created"); self.funding.channel_transaction_parameters.funding_outpoint = Some(funding_txo); - self.context.holder_signer.as_mut().provide_channel_parameters(&self.funding.channel_transaction_parameters); // Now that we're past error-generating stuff, update our local state: @@ -9487,9 +9483,6 @@ impl InboundV1Channel where SP::Target: SignerProvider { let funding_txo = OutPoint { txid: msg.funding_txid, index: msg.funding_output_index }; self.funding.channel_transaction_parameters.funding_outpoint = Some(funding_txo); - // This is an externally observable change before we finish all our checks. In particular - // check_funding_created_signature may fail. - self.context.holder_signer.as_mut().provide_channel_parameters(&self.funding.channel_transaction_parameters); let (channel_monitor, counterparty_initial_commitment_tx) = match self.initial_commitment_signed( ChannelId::v1_from_funding_outpoint(funding_txo), msg.signature, @@ -10622,12 +10615,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch }); let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id { - let mut holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id); - // If we've gotten to the funding stage of the channel, populate the signer with its - // required channel parameters. - if channel_state >= ChannelState::FundingNegotiated { - holder_signer.provide_channel_parameters(&channel_parameters); - } + let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id); (channel_keys_id, holder_signer) } else { return Err(DecodeError::InvalidValue); @@ -11650,7 +11638,6 @@ mod tests { selected_contest_delay: 144 }); chan.funding.channel_transaction_parameters.funding_outpoint = Some(funding_info); - signer.provide_channel_parameters(&chan.funding.channel_transaction_parameters); assert_eq!(counterparty_pubkeys.payment_point.serialize()[..], >::from_hex("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]); diff --git a/lightning/src/ln/dual_funding_tests.rs b/lightning/src/ln/dual_funding_tests.rs index 112aedf9d56..72fa049d6b0 100644 --- a/lightning/src/ln/dual_funding_tests.rs +++ b/lightning/src/ln/dual_funding_tests.rs @@ -23,7 +23,6 @@ use { crate::ln::msgs::{CommitmentSigned, TxAddInput, TxAddOutput, TxComplete, TxSignatures}, crate::ln::types::ChannelId, crate::prelude::*, - crate::sign::ChannelSigner as _, crate::util::ser::TransactionU16LenLimited, crate::util::test_utils, bitcoin::Witness, @@ -141,7 +140,7 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession) (channel_funding.get_funding_txo(), channel_context.get_channel_type().clone()) }; - let channel_transaction_parameters = ChannelTransactionParameters { + channel.funding.channel_transaction_parameters = ChannelTransactionParameters { counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: ChannelPublicKeys { funding_pubkey: accept_channel_v2_msg.common_fields.funding_pubkey, @@ -174,13 +173,6 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession) channel_value_satoshis: funding_satoshis, }; - channel - .context - .get_mut_signer() - .as_mut_ecdsa() - .unwrap() - .provide_channel_parameters(&channel_transaction_parameters); - let msg_commitment_signed_from_0 = CommitmentSigned { channel_id, signature: channel @@ -188,7 +180,6 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession) .get_initial_counterparty_commitment_signature_for_test( &mut channel.funding, &&logger_a, - channel_transaction_parameters, accept_channel_v2_msg.common_fields.first_per_commitment_point, ) .unwrap(), diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index e2090532b6d..20dcaef8667 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -66,7 +66,6 @@ use crate::prelude::*; use crate::sign::ecdsa::EcdsaChannelSigner; #[cfg(taproot)] use crate::sign::taproot::TaprootChannelSigner; -use crate::types::features::ChannelTypeFeatures; use crate::util::atomic_counter::AtomicCounter; use core::convert::TryInto; use core::ops::Deref; @@ -103,7 +102,7 @@ pub struct DelayedPaymentOutputDescriptor { /// The value of the channel which this output originated from, possibly indirectly. pub channel_value_satoshis: u64, /// The channel public keys and other parameters needed to generate a spending transaction or - /// to provide to a re-derived signer through [`ChannelSigner::provide_channel_parameters`]. + /// to provide to a signer. /// /// Added as optional, but always `Some` if the descriptor was produced in v0.0.123 or later. pub channel_transaction_parameters: Option, @@ -154,8 +153,7 @@ pub struct StaticPaymentOutputDescriptor { pub channel_keys_id: [u8; 32], /// The value of the channel which this transactions spends. pub channel_value_satoshis: u64, - /// The necessary channel parameters that need to be provided to the re-derived signer through - /// [`ChannelSigner::provide_channel_parameters`]. + /// The necessary channel parameters that need to be provided to the signer. /// /// Added as optional, but always `Some` if the descriptor was produced in v0.0.117 or later. pub channel_transaction_parameters: Option, @@ -261,8 +259,7 @@ pub enum SpendableOutputDescriptor { /// /// To derive the [`DelayedPaymentOutputDescriptor::revocation_pubkey`] provided here (which is /// used in the witness script generation), you must pass the counterparty - /// [`ChannelPublicKeys::revocation_basepoint`] (which appears in the call to - /// [`ChannelSigner::provide_channel_parameters`]) and the provided + /// [`ChannelPublicKeys::revocation_basepoint`] and the provided /// [`DelayedPaymentOutputDescriptor::per_commitment_point`] to /// [`RevocationKey`]. /// @@ -554,8 +551,7 @@ pub struct ChannelDerivationParameters { pub value_satoshis: u64, /// The unique identifier to re-derive the signer for the associated channel. pub keys_id: [u8; 32], - /// The necessary channel parameters that need to be provided to the re-derived signer through - /// [`ChannelSigner::provide_channel_parameters`]. + /// The necessary channel parameters that need to be provided to the signer. pub transaction_parameters: ChannelTransactionParameters, } @@ -713,13 +709,10 @@ impl HTLCDescriptor { where SP::Target: SignerProvider, { - let mut signer = signer_provider.derive_channel_signer( + signer_provider.derive_channel_signer( self.channel_derivation_parameters.value_satoshis, self.channel_derivation_parameters.keys_id, - ); - signer - .provide_channel_parameters(&self.channel_derivation_parameters.transaction_parameters); - signer + ) } } @@ -803,16 +796,6 @@ pub trait ChannelSigner { /// /// This method is *not* asynchronous. Instead, the value must be cached locally. fn channel_keys_id(&self) -> [u8; 32]; - - /// Set the counterparty static channel data, including basepoints, - /// `counterparty_selected`/`holder_selected_contest_delay` and funding outpoint. - /// - /// This data is static, and will never change for a channel once set. For a given [`ChannelSigner`] - /// instance, LDK will call this method exactly once - either immediately after construction - /// or when the funding information has been generated. - /// - /// channel_parameters.is_populated() MUST be true. - fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters); } /// Specifies the recipient of an invoice. @@ -1031,8 +1014,6 @@ pub struct InMemorySigner { pub commitment_seed: [u8; 32], /// Holder public keys and basepoints. pub(crate) holder_channel_pubkeys: ChannelPublicKeys, - /// Counterparty public keys and counterparty/holder `selected_contest_delay`, populated on channel acceptance. - channel_parameters: Option, /// The total value of this channel. channel_value_satoshis: u64, /// Key derivation parameters. @@ -1050,7 +1031,6 @@ impl PartialEq for InMemorySigner { && self.htlc_base_key == other.htlc_base_key && self.commitment_seed == other.commitment_seed && self.holder_channel_pubkeys == other.holder_channel_pubkeys - && self.channel_parameters == other.channel_parameters && self.channel_value_satoshis == other.channel_value_satoshis && self.channel_keys_id == other.channel_keys_id } @@ -1066,7 +1046,6 @@ impl Clone for InMemorySigner { htlc_base_key: self.htlc_base_key.clone(), commitment_seed: self.commitment_seed.clone(), holder_channel_pubkeys: self.holder_channel_pubkeys.clone(), - channel_parameters: self.channel_parameters.clone(), channel_value_satoshis: self.channel_value_satoshis, channel_keys_id: self.channel_keys_id, entropy_source: RandomBytes::new(self.get_secure_random_bytes()), @@ -1099,7 +1078,6 @@ impl InMemorySigner { commitment_seed, channel_value_satoshis, holder_channel_pubkeys, - channel_parameters: None, channel_keys_id, entropy_source: RandomBytes::new(rand_bytes_unique_start), } @@ -1121,64 +1099,6 @@ impl InMemorySigner { } } - /// Returns the counterparty's pubkeys. - /// - /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. - /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. - pub fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys> { - self.get_channel_parameters().and_then(|params| { - params.counterparty_parameters.as_ref().map(|params| ¶ms.pubkeys) - }) - } - - /// Returns the `contest_delay` value specified by our counterparty and applied on holder-broadcastable - /// transactions, i.e., the amount of time that we have to wait to recover our funds if we - /// broadcast a transaction. - /// - /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. - /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. - pub fn counterparty_selected_contest_delay(&self) -> Option { - self.get_channel_parameters().and_then(|params| { - params.counterparty_parameters.as_ref().map(|params| params.selected_contest_delay) - }) - } - - /// Returns the `contest_delay` value specified by us and applied on transactions broadcastable - /// by our counterparty, i.e., the amount of time that they have to wait to recover their funds - /// if they broadcast a transaction. - /// - /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. - /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. - pub fn holder_selected_contest_delay(&self) -> Option { - self.get_channel_parameters().map(|params| params.holder_selected_contest_delay) - } - - /// Returns whether the holder is the initiator. - /// - /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. - /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. - pub fn is_outbound(&self) -> Option { - self.get_channel_parameters().map(|params| params.is_outbound_from_holder) - } - - /// Returns a [`ChannelTransactionParameters`] for this channel, to be used when verifying or - /// building transactions. - /// - /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. - /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. - pub fn get_channel_parameters(&self) -> Option<&ChannelTransactionParameters> { - self.channel_parameters.as_ref() - } - - /// Returns the channel type features of the channel parameters. Should be helpful for - /// determining a channel's category, i. e. legacy/anchors/taproot/etc. - /// - /// Will return `None` if [`ChannelSigner::provide_channel_parameters`] has not been called. - /// In general, this is safe to `unwrap` only in [`ChannelSigner`] implementation. - pub fn channel_type_features(&self) -> Option<&ChannelTypeFeatures> { - self.get_channel_parameters().map(|params| ¶ms.channel_type_features) - } - /// Sign the single input of `spend_tx` at index `input_idx`, which spends the output described /// by `descriptor`, returning the witness stack for the input. /// @@ -1361,23 +1281,10 @@ impl ChannelSigner for InMemorySigner { fn channel_keys_id(&self) -> [u8; 32] { self.channel_keys_id } - - fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters) { - assert!( - self.channel_parameters.is_none() - || self.channel_parameters.as_ref().unwrap() == channel_parameters - ); - if self.channel_parameters.is_some() { - // The channel parameters were already set and they match, return early. - return; - } - assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); - self.channel_parameters = Some(channel_parameters.clone()); - } } const MISSING_PARAMS_ERR: &'static str = - "ChannelSigner::provide_channel_parameters must be called before signing operations"; + "ChannelTransactionParameters must be populated before signing operations"; impl EcdsaChannelSigner for InMemorySigner { fn sign_counterparty_commitment( @@ -1385,6 +1292,8 @@ impl EcdsaChannelSigner for InMemorySigner { commitment_tx: &CommitmentTransaction, _inbound_htlc_preimages: Vec, _outbound_htlc_preimages: Vec, secp_ctx: &Secp256k1, ) -> Result<(Signature, Vec), ()> { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + let trusted_tx = commitment_tx.trust(); let keys = trusted_tx.keys(); @@ -1447,6 +1356,8 @@ impl EcdsaChannelSigner for InMemorySigner { &self, channel_parameters: &ChannelTransactionParameters, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, ) -> Result { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); let counterparty_keys = channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); @@ -1467,6 +1378,8 @@ impl EcdsaChannelSigner for InMemorySigner { &self, channel_parameters: &ChannelTransactionParameters, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, ) -> Result { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); let counterparty_keys = channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR); @@ -1487,6 +1400,8 @@ impl EcdsaChannelSigner for InMemorySigner { input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1, ) -> Result { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + let revocation_key = chan_utils::derive_private_revocation_key( &secp_ctx, &per_commitment_key, @@ -1532,6 +1447,8 @@ impl EcdsaChannelSigner for InMemorySigner { input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, ) -> Result { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + let revocation_key = chan_utils::derive_private_revocation_key( &secp_ctx, &per_commitment_key, @@ -1582,6 +1499,10 @@ impl EcdsaChannelSigner for InMemorySigner { &self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor, secp_ctx: &Secp256k1, ) -> Result { + let channel_parameters = + &htlc_descriptor.channel_derivation_parameters.transaction_parameters; + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + let witness_script = htlc_descriptor.witness_script(secp_ctx); let sighash = &sighash::SighashCache::new(&*htlc_tx) .p2wsh_signature_hash( @@ -1605,6 +1526,8 @@ impl EcdsaChannelSigner for InMemorySigner { input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, ) -> Result { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + let htlc_key = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &self.htlc_base_key); let revocation_pubkey = RevocationKey::from_basepoint( @@ -1647,6 +1570,8 @@ impl EcdsaChannelSigner for InMemorySigner { &self, channel_parameters: &ChannelTransactionParameters, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1, ) -> Result { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); let counterparty_funding_key = &channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR).funding_pubkey; @@ -1664,6 +1589,8 @@ impl EcdsaChannelSigner for InMemorySigner { &self, channel_parameters: &ChannelTransactionParameters, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1, ) -> Result { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + let witness_script = chan_utils::get_anchor_redeemscript(&channel_parameters.holder_pubkeys.funding_pubkey); let sighash = sighash::SighashCache::new(&*anchor_tx) @@ -1688,6 +1615,8 @@ impl EcdsaChannelSigner for InMemorySigner { &self, channel_parameters: &ChannelTransactionParameters, tx: &Transaction, input_index: usize, input_value: u64, secp_ctx: &Secp256k1, ) -> Result { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + let funding_pubkey = PublicKey::from_secret_key(secp_ctx, &self.funding_key); let counterparty_funding_key = &channel_parameters.counterparty_pubkeys().expect(MISSING_PARAMS_ERR).funding_pubkey; @@ -1988,15 +1917,10 @@ impl KeysManager { if keys_cache.is_none() || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id { - let mut signer = self.derive_channel_keys( + let signer = self.derive_channel_keys( descriptor.channel_value_satoshis, &descriptor.channel_keys_id, ); - if let Some(channel_params) = - descriptor.channel_transaction_parameters.as_ref() - { - signer.provide_channel_parameters(channel_params); - } keys_cache = Some((signer, descriptor.channel_keys_id)); } let witness = keys_cache.as_ref().unwrap().0.sign_counterparty_payment_input( diff --git a/lightning/src/sign/type_resolver.rs b/lightning/src/sign/type_resolver.rs index 9aec6eb8849..b7270a8613b 100644 --- a/lightning/src/sign/type_resolver.rs +++ b/lightning/src/sign/type_resolver.rs @@ -25,15 +25,6 @@ where } } - pub(crate) fn as_mut(&mut self) -> &mut dyn ChannelSigner { - match self { - ChannelSignerType::Ecdsa(ecs) => ecs, - #[cfg(taproot)] - #[allow(unused)] - ChannelSignerType::Taproot(tcs) => tcs, - } - } - #[allow(unused)] pub(crate) fn as_ecdsa(&self) -> Option<&::EcdsaSigner> { match self { diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 6d71f3a5c8c..7c3a687d494 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -216,10 +216,6 @@ impl ChannelSigner for TestChannelSigner { fn channel_keys_id(&self) -> [u8; 32] { self.inner.channel_keys_id() } - - fn provide_channel_parameters(&mut self, channel_parameters: &ChannelTransactionParameters) { - self.inner.provide_channel_parameters(channel_parameters) - } } impl EcdsaChannelSigner for TestChannelSigner { From 9cde57e24fc791f478a00aa1a06746089d8cc0cf Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Mon, 24 Feb 2025 17:16:23 -0600 Subject: [PATCH 18/20] Remove channel_value_satoshis from SignerProvider Now that channel_value_satoshis has been moved to ChannelTransactionParameters, it no longer needs to be used when deriving a signer. This is a breaking API change, though InMemorySigner did not make use of channel_value_satoshis when being derived. --- fuzz/src/chanmon_consistency.rs | 9 +--- fuzz/src/full_stack.rs | 10 +--- fuzz/src/onion_message.rs | 8 +-- lightning/src/chain/channelmonitor.rs | 2 - lightning/src/chain/onchaintx.rs | 3 +- lightning/src/events/bump_transaction.rs | 5 +- lightning/src/ln/chan_utils.rs | 4 +- lightning/src/ln/channel.rs | 23 ++++----- lightning/src/sign/mod.rs | 64 ++++++------------------ lightning/src/util/test_utils.rs | 26 +++------- 10 files changed, 45 insertions(+), 109 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index acb78001d16..1dc274a3b48 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -354,16 +354,12 @@ impl SignerProvider for KeyProvider { #[cfg(taproot)] type TaprootSigner = TestChannelSigner; - fn generate_channel_keys_id( - &self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128, - ) -> [u8; 32] { + fn generate_channel_keys_id(&self, _inbound: bool, _user_channel_id: u128) -> [u8; 32] { let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed) as u8; [id; 32] } - fn derive_channel_signer( - &self, channel_value_satoshis: u64, channel_keys_id: [u8; 32], - ) -> Self::EcdsaSigner { + fn derive_channel_signer(&self, channel_keys_id: [u8; 32]) -> Self::EcdsaSigner { let secp_ctx = Secp256k1::signing_only(); let id = channel_keys_id[0]; #[rustfmt::skip] @@ -375,7 +371,6 @@ impl SignerProvider for KeyProvider { SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, self.node_secret[31]]).unwrap(), SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, self.node_secret[31]]).unwrap(), [id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, self.node_secret[31]], - channel_value_satoshis, channel_keys_id, channel_keys_id, ); diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 804110bb038..802c1094216 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -426,9 +426,7 @@ impl SignerProvider for KeyProvider { #[cfg(taproot)] type TaprootSigner = TestChannelSigner; - fn generate_channel_keys_id( - &self, inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128, - ) -> [u8; 32] { + fn generate_channel_keys_id(&self, inbound: bool, _user_channel_id: u128) -> [u8; 32] { let ctr = self.counter.fetch_add(1, Ordering::Relaxed) as u8; self.signer_state .borrow_mut() @@ -436,9 +434,7 @@ impl SignerProvider for KeyProvider { [ctr; 32] } - fn derive_channel_signer( - &self, channel_value_satoshis: u64, channel_keys_id: [u8; 32], - ) -> Self::EcdsaSigner { + fn derive_channel_signer(&self, channel_keys_id: [u8; 32]) -> Self::EcdsaSigner { let secp_ctx = Secp256k1::signing_only(); let ctr = channel_keys_id[0]; let (inbound, state) = self.signer_state.borrow().get(&ctr).unwrap().clone(); @@ -475,7 +471,6 @@ impl SignerProvider for KeyProvider { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, ctr, ], - channel_value_satoshis, channel_keys_id, channel_keys_id, ) @@ -511,7 +506,6 @@ impl SignerProvider for KeyProvider { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, ctr, ], - channel_value_satoshis, channel_keys_id, channel_keys_id, ) diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 7f491c069d3..c2790d527b0 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -253,15 +253,11 @@ impl SignerProvider for KeyProvider { #[cfg(taproot)] type TaprootSigner = TestChannelSigner; - fn generate_channel_keys_id( - &self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128, - ) -> [u8; 32] { + fn generate_channel_keys_id(&self, _inbound: bool, _user_channel_id: u128) -> [u8; 32] { unreachable!() } - fn derive_channel_signer( - &self, _channel_value_satoshis: u64, _channel_keys_id: [u8; 32], - ) -> Self::EcdsaSigner { + fn derive_channel_signer(&self, _channel_keys_id: [u8; 32]) -> Self::EcdsaSigner { unreachable!() } diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 19a064820d3..df6cf06c061 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -5401,7 +5401,6 @@ mod tests { SecretKey::from_slice(&[41; 32]).unwrap(), SecretKey::from_slice(&[41; 32]).unwrap(), [41; 32], - 0, [0; 32], [0; 32], ); @@ -5654,7 +5653,6 @@ mod tests { SecretKey::from_slice(&[41; 32]).unwrap(), SecretKey::from_slice(&[41; 32]).unwrap(), [41; 32], - 0, [0; 32], [0; 32], ); diff --git a/lightning/src/chain/onchaintx.rs b/lightning/src/chain/onchaintx.rs index b2c45077705..457d0512e4c 100644 --- a/lightning/src/chain/onchaintx.rs +++ b/lightning/src/chain/onchaintx.rs @@ -383,7 +383,7 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP bytes_read += bytes_to_read; } - let signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id); + let signer = signer_provider.derive_channel_signer(channel_keys_id); let pending_claim_requests_len: u64 = Readable::read(reader)?; let mut pending_claim_requests = hash_map_with_capacity(cmp::min(pending_claim_requests_len as usize, MAX_ALLOC_SIZE / 128)); @@ -1314,7 +1314,6 @@ mod tests { SecretKey::from_slice(&[41; 32]).unwrap(), SecretKey::from_slice(&[41; 32]).unwrap(), [41; 32], - 0, [0; 32], [0; 32], ); diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs index 5b71239d891..96aecbacfd7 100644 --- a/lightning/src/events/bump_transaction.rs +++ b/lightning/src/events/bump_transaction.rs @@ -97,10 +97,7 @@ impl AnchorDescriptor { where SP::Target: SignerProvider { - signer_provider.derive_channel_signer( - self.channel_derivation_parameters.value_satoshis, - self.channel_derivation_parameters.keys_id, - ) + signer_provider.derive_channel_signer(self.channel_derivation_parameters.keys_id) } } diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index c4c10a46f16..bbba374834b 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -1944,8 +1944,8 @@ mod tests { let seed = [42; 32]; let network = Network::Testnet; let keys_provider = test_utils::TestKeysInterface::new(&seed, network); - let signer = keys_provider.derive_channel_signer(3000, keys_provider.generate_channel_keys_id(false, 1_000_000, 0)); - let counterparty_signer = keys_provider.derive_channel_signer(3000, keys_provider.generate_channel_keys_id(true, 1_000_000, 1)); + let signer = keys_provider.derive_channel_signer(keys_provider.generate_channel_keys_id(false, 0)); + let counterparty_signer = keys_provider.derive_channel_signer(keys_provider.generate_channel_keys_id(true, 1)); let delayed_payment_base = &signer.pubkeys().delayed_payment_basepoint; let per_commitment_secret = SecretKey::from_slice(&>::from_hex("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100").unwrap()[..]).unwrap(); let per_commitment_point = PublicKey::from_secret_key(&secp_ctx, &per_commitment_secret); diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index a6b25c367dc..379c0d59203 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -2119,7 +2119,7 @@ trait InitialRemoteCommitmentReceiver where SP::Target: SignerProvide let funding_txo_script = funding_redeemscript.to_p2wsh(); let obscure_factor = get_commitment_transaction_number_obscure_factor(&funding.get_holder_pubkeys().payment_point, &funding.get_counterparty_pubkeys().payment_point, funding.is_outbound()); let shutdown_script = context.shutdown_scriptpubkey.clone().map(|script| script.into_inner()); - let monitor_signer = signer_provider.derive_channel_signer(funding.get_value_satoshis(), context.channel_keys_id); + let monitor_signer = signer_provider.derive_channel_signer(context.channel_keys_id); // TODO(RBF): When implementing RBF, the funding_txo passed here must only update // ChannelMonitorImp::first_confirmed_funding_txo during channel establishment, not splicing let channel_monitor = ChannelMonitor::new(context.secp_ctx.clone(), monitor_signer, @@ -2407,8 +2407,8 @@ impl ChannelContext where SP::Target: SignerProvider { let channel_value_satoshis = our_funding_satoshis.saturating_add(open_channel_fields.funding_satoshis); - let channel_keys_id = signer_provider.generate_channel_keys_id(true, channel_value_satoshis, user_id); - let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id); + let channel_keys_id = signer_provider.generate_channel_keys_id(true, user_id); + let holder_signer = signer_provider.derive_channel_signer(channel_keys_id); let pubkeys = holder_signer.pubkeys().clone(); if config.channel_handshake_config.our_to_self_delay < BREAKDOWN_TIMEOUT { @@ -9004,8 +9004,8 @@ impl OutboundV1Channel where SP::Target: SignerProvider { implemention limit dust_limit_satoshis {}", holder_selected_channel_reserve_satoshis) }); } - let channel_keys_id = signer_provider.generate_channel_keys_id(false, channel_value_satoshis, user_id); - let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id); + let channel_keys_id = signer_provider.generate_channel_keys_id(false, user_id); + let holder_signer = signer_provider.derive_channel_signer(channel_keys_id); let pubkeys = holder_signer.pubkeys().clone(); let (funding, context) = ChannelContext::new_for_outbound_channel( @@ -9561,8 +9561,8 @@ impl PendingV2Channel where SP::Target: SignerProvider { F::Target: FeeEstimator, L::Target: Logger, { - let channel_keys_id = signer_provider.generate_channel_keys_id(false, funding_satoshis, user_id); - let holder_signer = signer_provider.derive_channel_signer(funding_satoshis, channel_keys_id); + let channel_keys_id = signer_provider.generate_channel_keys_id(false, user_id); + let holder_signer = signer_provider.derive_channel_signer(channel_keys_id); let pubkeys = holder_signer.pubkeys().clone(); let temporary_channel_id = Some(ChannelId::temporary_v2_from_revocation_basepoint(&pubkeys.revocation_basepoint)); @@ -10615,7 +10615,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch }); let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id { - let holder_signer = signer_provider.derive_channel_signer(channel_value_satoshis, channel_keys_id); + let holder_signer = signer_provider.derive_channel_signer(channel_keys_id); (channel_keys_id, holder_signer) } else { return Err(DecodeError::InvalidValue); @@ -10970,11 +10970,11 @@ mod tests { #[cfg(taproot)] type TaprootSigner = InMemorySigner; - fn generate_channel_keys_id(&self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { + fn generate_channel_keys_id(&self, _inbound: bool, _user_channel_id: u128) -> [u8; 32] { self.signer.channel_keys_id() } - fn derive_channel_signer(&self, _channel_value_satoshis: u64, _channel_keys_id: [u8; 32]) -> Self::EcdsaSigner { + fn derive_channel_signer(&self, _channel_keys_id: [u8; 32]) -> Self::EcdsaSigner { self.signer.clone() } @@ -11597,7 +11597,7 @@ mod tests { let logger : Arc = Arc::new(test_utils::TestLogger::new()); let secp_ctx = Secp256k1::new(); - let mut signer = InMemorySigner::new( + let signer = InMemorySigner::new( &secp_ctx, SecretKey::from_slice(&>::from_hex("30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f3749").unwrap()[..]).unwrap(), SecretKey::from_slice(&>::from_hex("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(), @@ -11607,7 +11607,6 @@ mod tests { // These aren't set in the test vectors: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], - 10_000_000, [0; 32], [0; 32], ); diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 20dcaef8667..7d87f62d34e 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -709,10 +709,7 @@ impl HTLCDescriptor { where SP::Target: SignerProvider, { - signer_provider.derive_channel_signer( - self.channel_derivation_parameters.value_satoshis, - self.channel_derivation_parameters.keys_id, - ) + signer_provider.derive_channel_signer(self.channel_derivation_parameters.keys_id) } } @@ -949,9 +946,7 @@ pub trait SignerProvider { /// `channel_keys_id`. /// /// This method must return a different value each time it is called. - fn generate_channel_keys_id( - &self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128, - ) -> [u8; 32]; + fn generate_channel_keys_id(&self, inbound: bool, user_channel_id: u128) -> [u8; 32]; /// Derives the private key material backing a `Signer`. /// @@ -959,9 +954,7 @@ pub trait SignerProvider { /// [`SignerProvider::generate_channel_keys_id`]. Otherwise, an existing `Signer` can be /// re-derived from its `channel_keys_id`, which can be obtained through its trait method /// [`ChannelSigner::channel_keys_id`]. - fn derive_channel_signer( - &self, channel_value_satoshis: u64, channel_keys_id: [u8; 32], - ) -> Self::EcdsaSigner; + fn derive_channel_signer(&self, channel_keys_id: [u8; 32]) -> Self::EcdsaSigner; /// Get a script pubkey which we send funds to when claiming on-chain contestable outputs. /// @@ -1014,8 +1007,6 @@ pub struct InMemorySigner { pub commitment_seed: [u8; 32], /// Holder public keys and basepoints. pub(crate) holder_channel_pubkeys: ChannelPublicKeys, - /// The total value of this channel. - channel_value_satoshis: u64, /// Key derivation parameters. channel_keys_id: [u8; 32], /// A source of random bytes. @@ -1031,7 +1022,6 @@ impl PartialEq for InMemorySigner { && self.htlc_base_key == other.htlc_base_key && self.commitment_seed == other.commitment_seed && self.holder_channel_pubkeys == other.holder_channel_pubkeys - && self.channel_value_satoshis == other.channel_value_satoshis && self.channel_keys_id == other.channel_keys_id } } @@ -1046,7 +1036,6 @@ impl Clone for InMemorySigner { htlc_base_key: self.htlc_base_key.clone(), commitment_seed: self.commitment_seed.clone(), holder_channel_pubkeys: self.holder_channel_pubkeys.clone(), - channel_value_satoshis: self.channel_value_satoshis, channel_keys_id: self.channel_keys_id, entropy_source: RandomBytes::new(self.get_secure_random_bytes()), } @@ -1058,8 +1047,7 @@ impl InMemorySigner { pub fn new( secp_ctx: &Secp256k1, funding_key: SecretKey, revocation_base_key: SecretKey, payment_key: SecretKey, delayed_payment_base_key: SecretKey, htlc_base_key: SecretKey, - commitment_seed: [u8; 32], channel_value_satoshis: u64, channel_keys_id: [u8; 32], - rand_bytes_unique_start: [u8; 32], + commitment_seed: [u8; 32], channel_keys_id: [u8; 32], rand_bytes_unique_start: [u8; 32], ) -> InMemorySigner { let holder_channel_pubkeys = InMemorySigner::make_holder_keys( secp_ctx, @@ -1076,7 +1064,6 @@ impl InMemorySigner { delayed_payment_base_key, htlc_base_key, commitment_seed, - channel_value_satoshis, holder_channel_pubkeys, channel_keys_id, entropy_source: RandomBytes::new(rand_bytes_unique_start), @@ -1831,9 +1818,7 @@ impl KeysManager { } /// Derive an old [`EcdsaChannelSigner`] containing per-channel secrets based on a key derivation parameters. - pub fn derive_channel_keys( - &self, channel_value_satoshis: u64, params: &[u8; 32], - ) -> InMemorySigner { + pub fn derive_channel_keys(&self, params: &[u8; 32]) -> InMemorySigner { let chan_id = u64::from_be_bytes(params[0..8].try_into().unwrap()); let mut unique_start = Sha256::engine(); unique_start.input(params); @@ -1885,7 +1870,6 @@ impl KeysManager { delayed_payment_base_key, htlc_base_key, commitment_seed, - channel_value_satoshis, params.clone(), prng_seed, ) @@ -1917,10 +1901,7 @@ impl KeysManager { if keys_cache.is_none() || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id { - let signer = self.derive_channel_keys( - descriptor.channel_value_satoshis, - &descriptor.channel_keys_id, - ); + let signer = self.derive_channel_keys(&descriptor.channel_keys_id); keys_cache = Some((signer, descriptor.channel_keys_id)); } let witness = keys_cache.as_ref().unwrap().0.sign_counterparty_payment_input( @@ -1937,10 +1918,7 @@ impl KeysManager { || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id { keys_cache = Some(( - self.derive_channel_keys( - descriptor.channel_value_satoshis, - &descriptor.channel_keys_id, - ), + self.derive_channel_keys(&descriptor.channel_keys_id), descriptor.channel_keys_id, )); } @@ -2109,9 +2087,7 @@ impl SignerProvider for KeysManager { #[cfg(taproot)] type TaprootSigner = InMemorySigner; - fn generate_channel_keys_id( - &self, _inbound: bool, _channel_value_satoshis: u64, user_channel_id: u128, - ) -> [u8; 32] { + fn generate_channel_keys_id(&self, _inbound: bool, user_channel_id: u128) -> [u8; 32] { let child_idx = self.channel_child_index.fetch_add(1, Ordering::AcqRel); // `child_idx` is the only thing guaranteed to make each channel unique without a restart // (though `user_channel_id` should help, depending on user behavior). If it manages to @@ -2127,10 +2103,8 @@ impl SignerProvider for KeysManager { id } - fn derive_channel_signer( - &self, channel_value_satoshis: u64, channel_keys_id: [u8; 32], - ) -> Self::EcdsaSigner { - self.derive_channel_keys(channel_value_satoshis, &channel_keys_id) + fn derive_channel_signer(&self, channel_keys_id: [u8; 32]) -> Self::EcdsaSigner { + self.derive_channel_keys(&channel_keys_id) } fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result { @@ -2250,16 +2224,12 @@ impl SignerProvider for PhantomKeysManager { #[cfg(taproot)] type TaprootSigner = InMemorySigner; - fn generate_channel_keys_id( - &self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128, - ) -> [u8; 32] { - self.inner.generate_channel_keys_id(inbound, channel_value_satoshis, user_channel_id) + fn generate_channel_keys_id(&self, inbound: bool, user_channel_id: u128) -> [u8; 32] { + self.inner.generate_channel_keys_id(inbound, user_channel_id) } - fn derive_channel_signer( - &self, channel_value_satoshis: u64, channel_keys_id: [u8; 32], - ) -> Self::EcdsaSigner { - self.inner.derive_channel_signer(channel_value_satoshis, channel_keys_id) + fn derive_channel_signer(&self, channel_keys_id: [u8; 32]) -> Self::EcdsaSigner { + self.inner.derive_channel_signer(channel_keys_id) } fn get_destination_script(&self, channel_keys_id: [u8; 32]) -> Result { @@ -2303,10 +2273,8 @@ impl PhantomKeysManager { } /// See [`KeysManager::derive_channel_keys`] for documentation on this method. - pub fn derive_channel_keys( - &self, channel_value_satoshis: u64, params: &[u8; 32], - ) -> InMemorySigner { - self.inner.derive_channel_keys(channel_value_satoshis, params) + pub fn derive_channel_keys(&self, params: &[u8; 32]) -> InMemorySigner { + self.inner.derive_channel_keys(params) } /// Gets the "node_id" secret key used to sign gossip announcements, decode onion data, etc. diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index d50b796b87e..55ae3e0a8b6 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -356,15 +356,11 @@ impl SignerProvider for OnlyReadsKeysInterface { #[cfg(taproot)] type TaprootSigner = TestChannelSigner; - fn generate_channel_keys_id( - &self, _inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128, - ) -> [u8; 32] { + fn generate_channel_keys_id(&self, _inbound: bool, _user_channel_id: u128) -> [u8; 32] { unreachable!(); } - fn derive_channel_signer( - &self, _channel_value_satoshis: u64, _channel_keys_id: [u8; 32], - ) -> Self::EcdsaSigner { + fn derive_channel_signer(&self, _channel_keys_id: [u8; 32]) -> Self::EcdsaSigner { unreachable!(); } @@ -1545,16 +1541,12 @@ impl SignerProvider for TestKeysInterface { #[cfg(taproot)] type TaprootSigner = TestChannelSigner; - fn generate_channel_keys_id( - &self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128, - ) -> [u8; 32] { - self.backing.generate_channel_keys_id(inbound, channel_value_satoshis, user_channel_id) + fn generate_channel_keys_id(&self, inbound: bool, user_channel_id: u128) -> [u8; 32] { + self.backing.generate_channel_keys_id(inbound, user_channel_id) } - fn derive_channel_signer( - &self, channel_value_satoshis: u64, channel_keys_id: [u8; 32], - ) -> TestChannelSigner { - let keys = self.backing.derive_channel_signer(channel_value_satoshis, channel_keys_id); + fn derive_channel_signer(&self, channel_keys_id: [u8; 32]) -> TestChannelSigner { + let keys = self.backing.derive_channel_signer(channel_keys_id); let state = self.make_enforcement_state_cell(keys.commitment_seed); let signer = TestChannelSigner::new_with_revoked(keys, state, self.disable_revocation_policy_check); @@ -1611,10 +1603,8 @@ impl TestKeysInterface { self } - pub fn derive_channel_keys( - &self, channel_value_satoshis: u64, id: &[u8; 32], - ) -> TestChannelSigner { - self.derive_channel_signer(channel_value_satoshis, *id) + pub fn derive_channel_keys(&self, id: &[u8; 32]) -> TestChannelSigner { + self.derive_channel_signer(*id) } fn make_enforcement_state_cell( From e0a8eeed1816b310878fe1db3a908dfc16eb981e Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Tue, 25 Feb 2025 19:06:25 -0600 Subject: [PATCH 19/20] Remove custom derive_channel_signer methods The custom derive_channel_signer methods on AnchorDescriptor and HTLCDescriptor simply delegate to the passed SignerProvider now that providing ChannelTransactionParameters is no longer needed. Drop these methods and replace them with the method bodies at the call sites. --- lightning/src/events/bump_transaction.rs | 19 ++++++------------- lightning/src/ln/monitor_tests.rs | 4 ++-- lightning/src/sign/mod.rs | 9 --------- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/lightning/src/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs index 96aecbacfd7..ab0854bfd66 100644 --- a/lightning/src/events/bump_transaction.rs +++ b/lightning/src/events/bump_transaction.rs @@ -91,14 +91,6 @@ impl AnchorDescriptor { let channel_params = self.channel_derivation_parameters.transaction_parameters.as_holder_broadcastable(); chan_utils::build_anchor_input_witness(&channel_params.broadcaster_pubkeys().funding_pubkey, signature) } - - /// Derives the channel signer required to sign the anchor input. - pub fn derive_channel_signer(&self, signer_provider: &SP) -> S - where - SP::Target: SignerProvider - { - signer_provider.derive_channel_signer(self.channel_derivation_parameters.keys_id) - } } /// Represents the different types of transactions, originating from LDK, to be bumped. @@ -118,7 +110,7 @@ pub enum BumpTransactionEvent { /// /// The consumer should be able to sign for any of the additional inputs included within the /// child anchor transaction. To sign its anchor input, an [`EcdsaChannelSigner`] should be - /// re-derived through [`AnchorDescriptor::derive_channel_signer`]. The anchor input signature + /// re-derived through [`SignerProvider::derive_channel_signer`]. The anchor input signature /// can be computed with [`EcdsaChannelSigner::sign_holder_anchor_input`], which can then be /// provided to [`build_anchor_input_witness`] along with the `funding_pubkey` to obtain the /// full witness required to spend. @@ -183,7 +175,7 @@ pub enum BumpTransactionEvent { /// /// The consumer should be able to sign for any of the non-HTLC inputs added to the resulting /// HTLC transaction. To sign HTLC inputs, an [`EcdsaChannelSigner`] should be re-derived - /// through [`HTLCDescriptor::derive_channel_signer`]. Each HTLC input's signature can be + /// through [`SignerProvider::derive_channel_signer`]. Each HTLC input's signature can be /// computed with [`EcdsaChannelSigner::sign_holder_htlc_transaction`], which can then be /// provided to [`HTLCDescriptor::tx_input_witness`] to obtain the fully signed witness required /// to spend. @@ -684,7 +676,7 @@ where log_debug!(self.logger, "Signing anchor transaction {}", anchor_txid); anchor_tx = self.utxo_source.sign_psbt(anchor_psbt)?; - let signer = anchor_descriptor.derive_channel_signer(&self.signer_provider); + let signer = self.signer_provider.derive_channel_signer(anchor_descriptor.channel_derivation_parameters.keys_id); let channel_parameters = &anchor_descriptor.channel_derivation_parameters.transaction_parameters; let anchor_sig = signer.sign_holder_anchor_input(channel_parameters, &anchor_tx, 0, &self.secp)?; anchor_tx.input[0].witness = anchor_descriptor.tx_input_witness(&anchor_sig); @@ -787,8 +779,9 @@ where let mut signers = BTreeMap::new(); for (idx, htlc_descriptor) in htlc_descriptors.iter().enumerate() { - let signer = signers.entry(htlc_descriptor.channel_derivation_parameters.keys_id) - .or_insert_with(|| htlc_descriptor.derive_channel_signer(&self.signer_provider)); + let keys_id = htlc_descriptor.channel_derivation_parameters.keys_id; + let signer = signers.entry(keys_id) + .or_insert_with(|| self.signer_provider.derive_channel_signer(keys_id)); let htlc_sig = signer.sign_holder_htlc_transaction(&htlc_tx, idx, htlc_descriptor, &self.secp)?; let witness_script = htlc_descriptor.witness_script(&self.secp); htlc_tx.input[idx].witness = htlc_descriptor.tx_input_witness(&htlc_sig, &witness_script); diff --git a/lightning/src/ln/monitor_tests.rs b/lightning/src/ln/monitor_tests.rs index 95958e81c38..d5b60b00e63 100644 --- a/lightning/src/ln/monitor_tests.rs +++ b/lightning/src/ln/monitor_tests.rs @@ -9,7 +9,7 @@ //! Further functional tests which test blockchain reorganizations. -use crate::sign::{ecdsa::EcdsaChannelSigner, OutputSpender, SpendableOutputDescriptor}; +use crate::sign::{ecdsa::EcdsaChannelSigner, OutputSpender, SignerProvider, SpendableOutputDescriptor}; use crate::chain::channelmonitor::{ANTI_REORG_DELAY, ARCHIVAL_DELAY_BLOCKS,LATENCY_GRACE_PERIOD_BLOCKS, COUNTERPARTY_CLAIMABLE_WITHIN_BLOCKS_PINNABLE, Balance, BalanceSource, ChannelMonitorUpdateStep}; use crate::chain::transaction::OutPoint; use crate::chain::chaininterface::{ConfirmationTarget, LowerBoundedFeeEstimator, compute_feerate_sat_per_1000_weight}; @@ -2921,7 +2921,7 @@ fn test_anchors_aggregated_revoked_htlc_tx() { } for (idx, htlc_descriptor) in descriptors.into_iter().enumerate() { let htlc_input_idx = idx + 1; - let signer = htlc_descriptor.derive_channel_signer(&nodes[1].keys_manager); + let signer = nodes[1].keys_manager.derive_channel_signer(htlc_descriptor.channel_derivation_parameters.keys_id); let our_sig = signer.sign_holder_htlc_transaction(&htlc_tx, htlc_input_idx, &htlc_descriptor, &secp).unwrap(); let witness_script = htlc_descriptor.witness_script(&secp); htlc_tx.input[htlc_input_idx].witness = htlc_descriptor.tx_input_witness(&our_sig, &witness_script); diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 7d87f62d34e..df7c2c79dec 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -68,7 +68,6 @@ use crate::sign::ecdsa::EcdsaChannelSigner; use crate::sign::taproot::TaprootChannelSigner; use crate::util::atomic_counter::AtomicCounter; use core::convert::TryInto; -use core::ops::Deref; use core::sync::atomic::{AtomicUsize, Ordering}; #[cfg(taproot)] use musig2::types::{PartialSignature, PublicNonce}; @@ -703,14 +702,6 @@ impl HTLCDescriptor { &self.channel_derivation_parameters.transaction_parameters.channel_type_features, ) } - - /// Derives the channel signer required to sign the HTLC input. - pub fn derive_channel_signer(&self, signer_provider: &SP) -> S - where - SP::Target: SignerProvider, - { - signer_provider.derive_channel_signer(self.channel_derivation_parameters.keys_id) - } } /// A trait to handle Lightning channel key material without concretizing the channel type or From 0d127cfe22a2206eebbca8a12e7717ef2027b744 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Mon, 24 Feb 2025 18:56:01 -0600 Subject: [PATCH 20/20] Move get_funding_redeemscript implementation --- lightning/src/ln/chan_utils.rs | 7 +++++++ lightning/src/ln/channel.rs | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lightning/src/ln/chan_utils.rs b/lightning/src/ln/chan_utils.rs index bbba374834b..2447386b72b 100644 --- a/lightning/src/ln/chan_utils.rs +++ b/lightning/src/ln/chan_utils.rs @@ -931,6 +931,13 @@ impl ChannelTransactionParameters { } } + pub(crate) fn make_funding_redeemscript(&self) -> ScriptBuf { + make_funding_redeemscript( + &self.holder_pubkeys.funding_pubkey, + &self.counterparty_parameters.as_ref().unwrap().pubkeys.funding_pubkey + ) + } + /// Returns the counterparty's pubkeys. pub fn counterparty_pubkeys(&self) -> Option<&ChannelPublicKeys> { self.counterparty_parameters.as_ref().map(|params| ¶ms.pubkeys) diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 379c0d59203..3ba98562901 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -42,7 +42,7 @@ use crate::ln::channel_state::{ChannelShutdownState, CounterpartyForwardingInfo, use crate::ln::channelmanager::{self, OpenChannelMessage, PendingHTLCStatus, HTLCSource, SentHTLCId, HTLCFailureMsg, PendingHTLCInfo, RAACommitmentOrder, PaymentClaimDetails, BREAKDOWN_TIMEOUT, MIN_CLTV_EXPIRY_DELTA, MAX_LOCAL_BREAKDOWN_TIMEOUT}; use crate::ln::chan_utils::{ CounterpartyCommitmentSecrets, TxCreationKeys, HTLCOutputInCommitment, htlc_success_tx_weight, - htlc_timeout_tx_weight, make_funding_redeemscript, ChannelPublicKeys, CommitmentTransaction, + htlc_timeout_tx_weight, ChannelPublicKeys, CommitmentTransaction, HolderCommitmentTransaction, ChannelTransactionParameters, CounterpartyChannelTransactionParameters, MAX_HTLCS, get_commitment_transaction_number_obscure_factor, @@ -1709,7 +1709,7 @@ impl FundingScope { /// pays to get_funding_redeemscript().to_p2wsh()). /// Panics if called before accept_channel/InboundV1Channel::new pub fn get_funding_redeemscript(&self) -> ScriptBuf { - make_funding_redeemscript(&self.get_holder_pubkeys().funding_pubkey, self.counterparty_funding_pubkey()) + self.channel_transaction_parameters.make_funding_redeemscript() } fn counterparty_funding_pubkey(&self) -> &PublicKey {