diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index c1bbf8c155e..1dc274a3b48 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; @@ -356,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] @@ -377,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, ); @@ -385,15 +378,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..802c1094216 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; @@ -427,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() @@ -437,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(); @@ -476,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, ) @@ -512,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, ) @@ -522,13 +515,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..c2790d527b0 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; @@ -253,19 +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 { - unreachable!() - } - - fn read_chan_signer(&self, _data: &[u8]) -> Result { + 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 4ae10b949e2..df6cf06c061 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()); @@ -5398,7 +5401,6 @@ mod tests { SecretKey::from_slice(&[41; 32]).unwrap(), SecretKey::from_slice(&[41; 32]).unwrap(), [41; 32], - 0, [0; 32], [0; 32], ); @@ -5421,7 +5423,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 +5433,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 +5476,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 +5487,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()); @@ -5650,7 +5653,6 @@ mod tests { SecretKey::from_slice(&[41; 32]).unwrap(), SecretKey::from_slice(&[41; 32]).unwrap(), [41; 32], - 0, [0; 32], [0; 32], ); @@ -5673,14 +5675,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..457d0512e4c 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}; @@ -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. @@ -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_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)); @@ -1188,7 +1187,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 +1195,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) } @@ -1315,7 +1314,6 @@ mod tests { SecretKey::from_slice(&[41; 32]).unwrap(), SecretKey::from_slice(&[41; 32]).unwrap(), [41; 32], - 0, [0; 32], [0; 32], ); @@ -1355,6 +1353,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 +1373,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/chain/package.rs b/lightning/src/chain/package.rs index ef4f14d8263..f7fe3fef92f 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); @@ -619,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); @@ -631,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); @@ -643,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/events/bump_transaction.rs b/lightning/src/events/bump_transaction.rs index 3acb2145e5b..ab0854bfd66 100644 --- a/lightning/src/events/bump_transaction.rs +++ b/lightning/src/events/bump_transaction.rs @@ -91,19 +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 - { - let mut 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 - } } /// Represents the different types of transactions, originating from LDK, to be bumped. @@ -123,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. @@ -188,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. @@ -689,8 +676,9 @@ 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 anchor_sig = signer.sign_holder_anchor_input(&anchor_tx, 0, &self.secp)?; + 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); #[cfg(debug_assertions)] { @@ -791,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); @@ -956,7 +945,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/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/chan_utils.rs b/lightning/src/ln/chan_utils.rs index a471bd05c7d..2447386b72b 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. @@ -929,8 +931,20 @@ 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) + } + #[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 +964,7 @@ impl ChannelTransactionParameters { txid: Txid::from_byte_array([42; 32]), index: 0 }), channel_type_features: ChannelTypeFeatures::empty(), + channel_value_satoshis, } } } @@ -970,13 +985,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 +1000,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 +1010,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 +1028,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 +1129,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 +1155,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() { @@ -1926,8 +1951,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); @@ -1942,6 +1967,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 01feaf017df..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, @@ -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 { @@ -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. @@ -1648,11 +1647,17 @@ 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, + + /// 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 { 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 { @@ -1667,11 +1672,49 @@ 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 ) }) } + + 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 { + self.channel_transaction_parameters.make_funding_redeemscript() + } + + fn counterparty_funding_pubkey(&self) -> &PublicKey { + &self.get_counterparty_pubkeys().funding_pubkey + } } /// Contains everything about the channel including state, and various flags. @@ -1862,10 +1905,6 @@ pub(super) struct ChannelContext where SP::Target: SignerProvider { counterparty_forwarding_info: Option, - pub(crate) 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, /// This flag indicates that it is the user's responsibility to validated and broadcast the /// funding transaction. is_manual_broadcast: bool, @@ -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); + 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.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,20 @@ 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 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, - 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.get_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 +2157,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 +2179,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 +2201,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 +2291,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,18 +2313,17 @@ 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.assert_no_commitment_advancement(transaction_number, "initial commitment_signed"); 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) => { - 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) }))); }, }; @@ -2355,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 { @@ -2518,7 +2570,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, @@ -2532,6 +2583,20 @@ 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(), + channel_value_satoshis, + }, + funding_transaction: None, }; let channel_context = ChannelContext { user_id, @@ -2613,18 +2678,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, counterparty_cur_commitment_point: Some(open_channel_fields.first_per_commitment_point), @@ -2752,8 +2805,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, @@ -2769,6 +2820,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: true, + 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, }; let channel_context = Self { user_id, @@ -2850,15 +2913,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, counterparty_cur_commitment_point: None, @@ -2911,10 +2965,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 +3142,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 +3162,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) { @@ -3127,17 +3171,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))); } @@ -3187,7 +3231,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() { @@ -3211,7 +3255,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; @@ -3230,7 +3274,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 +3305,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 +3482,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 +3492,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); @@ -3593,7 +3620,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)] @@ -3611,9 +3638,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 +3649,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 +3669,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 +3705,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 +3717,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 +3976,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. // @@ -4008,7 +4024,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 { @@ -4076,7 +4092,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, @@ -4098,10 +4114,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 +4204,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 +4220,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 +4300,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 } @@ -4309,15 +4325,15 @@ 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 /// 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 +4344,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 +4372,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,8 +4390,8 @@ impl ChannelContext where SP::Target: SignerProvider { })) } else { None } } else { None }; - let unbroadcasted_batch_funding_txid = self.unbroadcasted_batch_funding_txid(); - 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; @@ -4386,18 +4402,19 @@ 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, - 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 + &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(); @@ -4408,7 +4425,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)] @@ -4435,12 +4452,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 +4481,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,13 +4508,14 @@ 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 { // 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( ( @@ -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, counterparty_cur_commitment_point_override: PublicKey, ) -> Result where @@ -4559,7 +4577,6 @@ 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; self.get_initial_counterparty_commitment_signature(funding, logger) } } @@ -4800,7 +4817,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 +4837,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.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.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 +4874,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 +5173,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" @@ -5262,7 +5279,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 { @@ -5305,7 +5322,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())); } @@ -5313,11 +5330,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 +5352,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,21 +5509,21 @@ 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 = { 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()[..]), - 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 +5536,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 +5544,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 +5584,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 +5614,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 +6080,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; @@ -6201,7 +6218,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; } @@ -6245,7 +6262,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 +6275,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 +6379,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; } } @@ -6433,8 +6450,8 @@ 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 (self.context.is_outbound() || self.is_v2_established()) && + 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(_))) { @@ -6452,7 +6469,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 +6531,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 +6553,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,10 +6588,10 @@ 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) + 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. @@ -6617,10 +6634,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 sighash = closing_tx.trust().get_sighash_all(&funding_redeemscript, self.funding.channel_value_satoshis); + let funding_redeemscript = self.funding.get_funding_redeemscript(); + 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.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 +6765,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 +7017,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 +7026,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,14 +7040,14 @@ 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. 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)); @@ -7072,7 +7089,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 +7264,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 +7278,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 } @@ -7272,7 +7289,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!() @@ -7303,14 +7320,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, + channel_capacity_satoshis: self.funding.get_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.context.get_funding_txo(), + channel_funding_txo: self.funding.get_funding_txo(), last_local_balance_msat: self.funding.value_to_self_msat, } } @@ -7336,7 +7353,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,23 +7362,23 @@ 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 { 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.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 // 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); - secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, self.context.counterparty_funding_pubkey()), "Invalid closing tx signature from peer".to_owned()); + 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()); }, }; @@ -7423,10 +7440,10 @@ 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); + 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 { @@ -7563,9 +7580,9 @@ 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.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 @@ -7607,7 +7624,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::(), @@ -7716,7 +7733,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.funding.funding_transaction.is_some()); } assert!(self.context.monitor_pending_channel_ready); assert_eq!(self.context.latest_monitor_update_id, 0); return true; @@ -7863,16 +7880,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() || - tx.output[txo_idx].value.to_sat() != self.funding.channel_value_satoshis { - if self.context.is_outbound() { + 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.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 // tell them off. That said, because hash collisions happen with high @@ -7885,7 +7902,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 +8030,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 +8109,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 +8235,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)); @@ -8360,7 +8377,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))); } @@ -8466,7 +8483,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 +8524,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 +8556,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(); @@ -8554,6 +8571,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, @@ -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()); @@ -8751,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 ); @@ -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. @@ -8986,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( @@ -9020,14 +9038,15 @@ 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 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) @@ -9045,8 +9064,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 +9083,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 +9094,7 @@ 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); // Now that we're past error-generating stuff, update our local state: @@ -9091,8 +9109,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); @@ -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,18 +9162,18 @@ 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 { 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, 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(), @@ -9170,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, }) } @@ -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,7 @@ 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); - // 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.funding.channel_transaction_parameters.funding_outpoint = Some(funding_txo); let (channel_monitor, counterparty_initial_commitment_tx) = match self.initial_commitment_signed( ChannelId::v1_from_funding_outpoint(funding_txo), msg.signature, @@ -9478,7 +9493,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()); @@ -9544,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)); @@ -9608,12 +9625,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,18 +9650,18 @@ 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 { 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, 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 +9745,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 +9767,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.get_value_satoshis())), } ).map_err(|_| ChannelError::Close(( "V2 channel rejected due to sender error".into(), @@ -9777,7 +9794,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 +9823,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 +9832,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(), @@ -9962,7 +9979,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)?; @@ -10126,7 +10143,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,8 +10193,8 @@ impl Writeable for FundedChannel where SP::Target: SignerProvider None => 0u8.write(writer)? } - self.context.channel_transaction_parameters.write(writer)?; - self.context.funding_transaction.write(writer)?; + self.funding.channel_transaction_parameters.write(writer)?; + self.funding.funding_transaction.write(writer)?; self.context.counterparty_cur_commitment_point.write(writer)?; self.context.counterparty_prev_commitment_point.write(writer)?; @@ -10201,13 +10218,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); @@ -10278,7 +10295,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, @@ -10311,21 +10327,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)), @@ -10509,7 +10510,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)?; @@ -10614,18 +10615,10 @@ 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_keys_id); (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 { @@ -10657,6 +10650,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()); @@ -10748,7 +10743,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(), @@ -10762,6 +10756,9 @@ 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, + funding_transaction, }, context: ChannelContext { user_id, @@ -10840,8 +10837,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, counterparty_cur_commitment_point, @@ -10911,7 +10906,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; @@ -10975,16 +10970,14 @@ 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() } - 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(); @@ -11089,7 +11082,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 +11129,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 +11169,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 +11212,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(), }]}; @@ -11272,12 +11265,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(); @@ -11286,38 +11279,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); } @@ -11358,7 +11351,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(); @@ -11368,7 +11361,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); @@ -11408,7 +11401,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 +11471,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(); @@ -11604,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(), @@ -11614,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], ); @@ -11639,13 +11631,12 @@ 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); assert_eq!(counterparty_pubkeys.payment_point.serialize()[..], >::from_hex("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()[..]); @@ -11667,14 +11658,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 +11684,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); + 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.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 +11706,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(); + 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.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 +11724,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 }; @@ -11755,9 +11746,9 @@ 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.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 +12593,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..e4221cdd809 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); @@ -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); @@ -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)); @@ -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(); @@ -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 }); @@ -13487,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. @@ -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..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, @@ -136,10 +135,12 @@ 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 { + channel.funding.channel_transaction_parameters = ChannelTransactionParameters { counterparty_parameters: Some(CounterpartyChannelTransactionParameters { pubkeys: ChannelPublicKeys { funding_pubkey: accept_channel_v2_msg.common_fields.funding_pubkey, @@ -169,23 +170,16 @@ fn do_test_v2_channel_establishment(session: V2ChannelEstablishmentTestSession) is_outbound_from_holder: true, funding_outpoint, channel_type_features, + 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 .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, ) .unwrap(), diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index ff0646bfa6c..d0b89198df1 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -769,9 +769,12 @@ 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() + 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 { @@ -1512,9 +1515,12 @@ 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() + 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/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/ecdsa.rs b/lightning/src/sign/ecdsa.rs index 2f42d332962..6fbf730ae17 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. @@ -74,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 @@ -84,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. @@ -109,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 @@ -139,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 @@ -189,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. /// @@ -203,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`. @@ -216,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. @@ -246,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 3ba950f548d..df7c2c79dec 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -58,20 +58,16 @@ 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::{ReadableArgs, 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)] use crate::sign::taproot::TaprootChannelSigner; -use crate::types::features::ChannelTypeFeatures; 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}; @@ -105,7 +101,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, @@ -129,7 +125,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 */ + @@ -156,8 +152,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, @@ -198,7 +193,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. @@ -263,8 +258,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`]. /// @@ -556,15 +550,14 @@ 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, } 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. @@ -709,20 +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, - { - let mut 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 - } } /// A trait to handle Lightning channel key material without concretizing the channel type or @@ -805,17 +784,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 - /// (not including if done via [`SignerProvider::read_chan_signer`]) 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. @@ -969,9 +937,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`. /// @@ -979,24 +945,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; - - /// 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; + 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. /// @@ -1049,10 +998,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. channel_keys_id: [u8; 32], /// A source of random bytes. @@ -1068,8 +1013,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 } } @@ -1084,8 +1027,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()), } @@ -1097,8 +1038,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, @@ -1115,9 +1055,7 @@ impl InMemorySigner { delayed_payment_base_key, htlc_base_key, commitment_seed, - channel_value_satoshis, holder_channel_pubkeys, - channel_parameters: None, channel_keys_id, entropy_source: RandomBytes::new(rand_bytes_unique_start), } @@ -1139,72 +1077,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) - } - - /// 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. - /// - /// 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. /// @@ -1233,11 +1105,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 { @@ -1388,35 +1259,25 @@ 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( - &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), ()> { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + 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); @@ -1424,16 +1285,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, @@ -1472,17 +1331,21 @@ 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 { + 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 = 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, )) @@ -1490,26 +1353,33 @@ 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 { + 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 = 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, )) } 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 { + 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, @@ -1518,13 +1388,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, @@ -1551,9 +1421,12 @@ 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 { + 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, @@ -1562,11 +1435,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, @@ -1574,13 +1448,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, @@ -1604,6 +1477,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( @@ -1623,25 +1500,29 @@ 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 { + 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( &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, @@ -1664,26 +1545,32 @@ 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 { + 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 = - &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, )) } 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 { + assert!(channel_parameters.is_populated(), "Channel parameters must be fully populated"); + 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, @@ -1703,12 +1590,14 @@ 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 { + 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 = - &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) @@ -1789,74 +1678,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. /// @@ -1988,9 +1809,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); @@ -2042,7 +1861,6 @@ impl KeysManager { delayed_payment_base_key, htlc_base_key, commitment_seed, - channel_value_satoshis, params.clone(), prng_seed, ) @@ -2074,15 +1892,7 @@ impl KeysManager { if keys_cache.is_none() || keys_cache.as_ref().unwrap().1 != descriptor.channel_keys_id { - let mut 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); - } + 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( @@ -2099,10 +1909,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, )); } @@ -2271,9 +2078,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 @@ -2289,14 +2094,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 read_chan_signer(&self, reader: &[u8]) -> Result { - InMemorySigner::read(&mut io::Cursor::new(reader), self) + 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 { @@ -2416,20 +2215,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 read_chan_signer(&self, reader: &[u8]) -> Result { - self.inner.read_chan_signer(reader) + 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 { @@ -2473,10 +2264,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/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/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 }; diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 3bc095d2ba7..7c3a687d494 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -31,14 +31,11 @@ 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; @@ -139,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() @@ -223,18 +216,15 @@ 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 { 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)] @@ -268,6 +258,7 @@ impl EcdsaChannelSigner for TestChannelSigner { Ok(self .inner .sign_counterparty_commitment( + channel_parameters, commitment_tx, inbound_htlc_preimages, outbound_htlc_preimages, @@ -277,13 +268,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,18 +287,23 @@ 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( - &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)] @@ -314,6 +312,7 @@ impl EcdsaChannelSigner for TestChannelSigner { } Ok(EcdsaChannelSigner::sign_justice_revoked_output( &self.inner, + channel_parameters, justice_tx, input, amount, @@ -324,8 +323,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) { @@ -333,6 +333,7 @@ impl EcdsaChannelSigner for TestChannelSigner { } Ok(EcdsaChannelSigner::sign_justice_revoked_htlc( &self.inner, + channel_parameters, justice_tx, input, amount, @@ -364,7 +365,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 @@ -379,7 +383,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, ); @@ -402,8 +406,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) { @@ -411,6 +416,7 @@ impl EcdsaChannelSigner for TestChannelSigner { } Ok(EcdsaChannelSigner::sign_counterparty_htlc_transaction( &self.inner, + channel_parameters, htlc_tx, input, amount, @@ -422,20 +428,22 @@ 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( - &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 @@ -448,7 +456,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( @@ -458,10 +472,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, + ) } } @@ -530,39 +550,30 @@ 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, + &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") } 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") diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 9d02452010d..55ae3e0a8b6 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; @@ -358,25 +356,14 @@ 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!(); } - 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(()) } @@ -1554,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); @@ -1580,15 +1563,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) } @@ -1629,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( 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).