diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index 6fbf730ae17..e84cd80a0be 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -84,7 +84,7 @@ pub trait EcdsaChannelSigner: ChannelSigner { /// only ever get called once. /// /// This method is *not* async as it is intended only for testing purposes. - #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))] + #[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))] fn unsafe_sign_holder_commitment( &self, channel_parameters: &ChannelTransactionParameters, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 1a85fce5718..9f04968198a 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -31,7 +31,6 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature}; use bitcoin::secp256k1::schnorr; -#[cfg(taproot)] use bitcoin::secp256k1::All; use bitcoin::secp256k1::{Keypair, PublicKey, Scalar, Secp256k1, SecretKey, Signing}; use bitcoin::{secp256k1, Psbt, Sequence, Txid, WPubkeyHash, Witness}; @@ -898,10 +897,10 @@ pub trait OutputSpender { /// Returns `Err(())` if the output value is greater than the input value minus required fee, /// if a descriptor was duplicated, or if an output descriptor `script_pubkey` /// does not match the one we can spend. - fn spend_spendable_outputs( + fn spend_spendable_outputs( &self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, - locktime: Option, secp_ctx: &Secp256k1, + locktime: Option, secp_ctx: &Secp256k1, ) -> Result; } @@ -1351,7 +1350,7 @@ impl EcdsaChannelSigner for InMemorySigner { )) } - #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))] + #[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))] fn unsafe_sign_holder_commitment( &self, channel_parameters: &ChannelTransactionParameters, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, @@ -2044,10 +2043,10 @@ impl OutputSpender for KeysManager { /// /// May panic if the [`SpendableOutputDescriptor`]s were not generated by channels which used /// this [`KeysManager`] or one of the [`InMemorySigner`] created by this [`KeysManager`]. - fn spend_spendable_outputs( + fn spend_spendable_outputs( &self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, - locktime: Option, secp_ctx: &Secp256k1, + locktime: Option, secp_ctx: &Secp256k1, ) -> Result { let (mut psbt, expected_max_weight) = SpendableOutputDescriptor::create_spendable_outputs_psbt( @@ -2194,10 +2193,10 @@ impl NodeSigner for PhantomKeysManager { impl OutputSpender for PhantomKeysManager { /// See [`OutputSpender::spend_spendable_outputs`] and [`KeysManager::spend_spendable_outputs`] /// for documentation on this method. - fn spend_spendable_outputs( + fn spend_spendable_outputs( &self, descriptors: &[&SpendableOutputDescriptor], outputs: Vec, change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, - locktime: Option, secp_ctx: &Secp256k1, + locktime: Option, secp_ctx: &Secp256k1, ) -> Result { self.inner.spend_spendable_outputs( descriptors, diff --git a/lightning/src/util/dyn_signer.rs b/lightning/src/util/dyn_signer.rs new file mode 100644 index 00000000000..74920fa4b0a --- /dev/null +++ b/lightning/src/util/dyn_signer.rs @@ -0,0 +1,330 @@ +//! A dynamically dispatched signer + +use crate::prelude::*; + +use core::any::Any; + +use crate::ln::chan_utils::{ + ChannelPublicKeys, ChannelTransactionParameters, ClosingTransaction, CommitmentTransaction, + HTLCOutputInCommitment, HolderCommitmentTransaction, +}; +use crate::ln::inbound_payment::ExpandedKey; +use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage}; +use crate::ln::script::ShutdownScript; +use crate::sign::ecdsa::EcdsaChannelSigner; +#[cfg(taproot)] +use crate::sign::taproot::TaprootChannelSigner; +use crate::sign::ChannelSigner; +use crate::sign::InMemorySigner; +use crate::sign::{EntropySource, HTLCDescriptor, OutputSpender, PhantomKeysManager}; +use crate::sign::{NodeSigner, Recipient, SignerProvider, SpendableOutputDescriptor}; +use bitcoin; +use bitcoin::absolute::LockTime; +use bitcoin::secp256k1::All; +use bitcoin::{secp256k1, ScriptBuf, Transaction, TxOut}; +use lightning_invoice::RawBolt11Invoice; +#[cfg(taproot)] +use musig2::types::{PartialSignature, PublicNonce}; +use secp256k1::ecdsa::RecoverableSignature; +use secp256k1::{ecdh::SharedSecret, ecdsa::Signature, PublicKey, Scalar, Secp256k1, SecretKey}; +use types::payment::PaymentPreimage; + +#[cfg(not(taproot))] +/// A super-trait for all the traits that a dyn signer backing implements +pub trait DynSignerTrait: EcdsaChannelSigner + Send + Sync {} + +#[cfg(taproot)] +/// A super-trait for all the traits that a dyn signer backing implements +pub trait DynSignerTrait: EcdsaChannelSigner + TaprootChannelSigner + Send + Sync {} + +/// Helper to allow DynSigner to clone itself +pub trait InnerSign: DynSignerTrait { + /// Clone into a Box + fn box_clone(&self) -> Box; + /// Cast to Any for runtime type checking + fn as_any(&self) -> &dyn Any; +} + +/// A ChannelSigner derived struct allowing run-time selection of a signer +pub struct DynSigner { + /// The inner signer + pub inner: Box, +} + +impl DynSigner { + /// Create a new DynSigner + pub fn new(inner: S) -> Self { + DynSigner { inner: Box::new(inner) } + } +} + +#[cfg(taproot)] +#[allow(unused_variables)] +impl TaprootChannelSigner for DynSigner { + fn generate_local_nonce_pair( + &self, commitment_number: u64, secp_ctx: &Secp256k1, + ) -> PublicNonce { + todo!() + } + + fn partially_sign_counterparty_commitment( + &self, counterparty_nonce: PublicNonce, commitment_tx: &CommitmentTransaction, + inbound_htlc_preimages: Vec, + outbound_htlc_preimages: Vec, secp_ctx: &Secp256k1, + ) -> Result<(crate::ln::msgs::PartialSignatureWithNonce, Vec), ()> + { + todo!(); + } + + fn finalize_holder_commitment( + &self, commitment_tx: &HolderCommitmentTransaction, + counterparty_partial_signature: crate::ln::msgs::PartialSignatureWithNonce, + secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn sign_justice_revoked_output( + &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn sign_justice_revoked_htlc( + &self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn sign_holder_htlc_transaction( + &self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor, + secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn sign_counterparty_htlc_transaction( + &self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, + htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn partially_sign_closing_transaction( + &self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } + + fn sign_holder_anchor_input( + &self, anchor_tx: &Transaction, input: usize, secp_ctx: &Secp256k1, + ) -> Result { + todo!(); + } +} + +impl Clone for DynSigner { + fn clone(&self) -> Self { + DynSigner { inner: self.inner.box_clone() } + } +} + +delegate!(DynSigner, EcdsaChannelSigner, inner, + fn sign_holder_commitment(, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &HolderCommitmentTransaction, + secp_ctx: &Secp256k1) -> Result, + #[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))] + fn unsafe_sign_holder_commitment(, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &HolderCommitmentTransaction, + secp_ctx: &Secp256k1) -> Result, + fn sign_counterparty_commitment(, channel_parameters: &ChannelTransactionParameters, + commitment_tx: &CommitmentTransaction, inbound_htlc_preimages: Vec, + outbound_htlc_preimages: Vec, + secp_ctx: &Secp256k1) -> Result<(Signature, Vec), ()>, + fn sign_justice_revoked_output(, channel_parameters: &ChannelTransactionParameters, + justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + secp_ctx: &Secp256k1) -> Result, + fn sign_justice_revoked_htlc(, channel_parameters: &ChannelTransactionParameters, + justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, + htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result, + fn sign_counterparty_htlc_transaction(, channel_parameters: &ChannelTransactionParameters, + htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, + htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1) -> Result, + fn sign_closing_transaction(, channel_parameters: &ChannelTransactionParameters, + closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1) -> Result, + fn sign_channel_announcement_with_funding_key(, msg: &UnsignedChannelAnnouncement, + secp_ctx: &Secp256k1) -> Result, + fn sign_holder_anchor_input(, channel_parameters: &ChannelTransactionParameters, + anchor_tx: &Transaction, input: usize, + secp_ctx: &Secp256k1) -> Result, + fn sign_holder_htlc_transaction(, htlc_tx: &Transaction, input: usize, + htlc_descriptor: &HTLCDescriptor, secp_ctx: &Secp256k1) -> Result, + fn sign_splicing_funding_input(, channel_parameters: &ChannelTransactionParameters, + tx: &Transaction, input_index: usize, input_value: u64, + secp_ctx: &Secp256k1) -> Result +); + +delegate!(DynSigner, ChannelSigner, + inner, + fn get_per_commitment_point(, + idx: u64, + secp_ctx: &Secp256k1 + ) -> Result, + fn release_commitment_secret(, idx: u64) -> Result<[u8; 32], ()>, + fn validate_holder_commitment(, + holder_tx: &HolderCommitmentTransaction, + preimages: Vec + ) -> Result<(), ()>, + fn pubkeys(,) -> &ChannelPublicKeys, + fn channel_keys_id(,) -> [u8; 32], + fn validate_counterparty_revocation(, idx: u64, secret: &SecretKey) -> Result<(), ()> +); + +impl DynSignerTrait for InMemorySigner {} + +impl InnerSign for InMemorySigner { + fn box_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn as_any(&self) -> &dyn Any { + self + } +} + +/// A convenience wrapper for DynKeysInterfaceTrait +pub struct DynKeysInterface { + /// The inner dyn keys interface + pub inner: Box, +} + +impl DynKeysInterface { + /// Create a new DynKeysInterface + pub fn new(inner: Box) -> Self { + DynKeysInterface { inner } + } +} + +delegate!(DynKeysInterface, NodeSigner, +inner, + fn get_node_id(, recipient: Recipient) -> Result, + fn sign_gossip_message(, msg: UnsignedGossipMessage) -> Result, + fn ecdh(, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result, + fn sign_invoice(, invoice: &RawBolt11Invoice, recipient: Recipient) -> Result, + fn sign_bolt12_invoice(, + invoice: &crate::offers::invoice::UnsignedBolt12Invoice + ) -> Result, + fn get_inbound_payment_key(,) -> ExpandedKey +); + +delegate!(DynKeysInterface, SignerProvider, + inner, + fn get_destination_script(, channel_keys_id: [u8; 32]) -> Result, + fn get_shutdown_scriptpubkey(,) -> Result, + fn generate_channel_keys_id(, _inbound: bool, _user_channel_id: u128) -> [u8; 32], + fn derive_channel_signer(, _channel_keys_id: [u8; 32]) -> Self::EcdsaSigner; + type EcdsaSigner = DynSigner, + #[cfg(taproot)] + type TaprootSigner = DynSigner +); + +delegate!(DynKeysInterface, EntropySource, inner, + fn get_secure_random_bytes(,) -> [u8; 32] +); + +delegate!(DynKeysInterface, OutputSpender, inner, + fn spend_spendable_outputs(, + descriptors: &[&SpendableOutputDescriptor], outputs: Vec, + change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, + locktime: Option, secp_ctx: &Secp256k1 + ) -> Result +); +#[cfg(not(taproot))] +/// A supertrait for all the traits that a keys interface implements +pub trait DynKeysInterfaceTrait: + NodeSigner + OutputSpender + SignerProvider + EntropySource + Send + Sync +{ + #[cfg(test)] + fn set_counter(&self, _count: u64) {} +} + +#[cfg(taproot)] +/// A supertrait for all the traits that a keys interface implements +pub trait DynKeysInterfaceTrait: + NodeSigner + + OutputSpender + + SignerProvider + + EntropySource + + Send + + Sync +{ + #[cfg(test)] + fn set_counter(&self, _count: u64) {} +} + +/// A dyn wrapper for PhantomKeysManager +pub struct DynPhantomKeysInterface { + inner: Box, +} + +impl DynPhantomKeysInterface { + /// Create a new DynPhantomKeysInterface + pub fn new(inner: PhantomKeysManager) -> Self { + DynPhantomKeysInterface { inner: Box::new(inner) } + } +} + +delegate!(DynPhantomKeysInterface, NodeSigner, + inner, + fn get_node_id(, recipient: Recipient) -> Result, + fn sign_gossip_message(, msg: UnsignedGossipMessage) -> Result, + fn ecdh(, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result, + fn sign_invoice(, invoice: &RawBolt11Invoice, recipient: Recipient) -> Result, + fn sign_bolt12_invoice(, invoice: &crate::offers::invoice::UnsignedBolt12Invoice + ) -> Result, + fn get_inbound_payment_key(,) -> ExpandedKey +); + +impl SignerProvider for DynPhantomKeysInterface { + type EcdsaSigner = DynSigner; + #[cfg(taproot)] + type TaprootSigner = DynSigner; + + fn get_destination_script(&self, channel_keys_id: [u8; 32]) -> Result { + self.inner.get_destination_script(channel_keys_id) + } + + fn get_shutdown_scriptpubkey(&self) -> Result { + self.inner.get_shutdown_scriptpubkey() + } + + 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_keys_id: [u8; 32]) -> Self::EcdsaSigner { + let inner = self.inner.derive_channel_signer(channel_keys_id); + DynSigner::new(inner) + } +} + +delegate!(DynPhantomKeysInterface, EntropySource, inner, + fn get_secure_random_bytes(,) -> [u8; 32] +); + +delegate!(DynPhantomKeysInterface, OutputSpender, inner, + fn spend_spendable_outputs(, + descriptors: &[&SpendableOutputDescriptor], outputs: Vec, + change_destination_script: ScriptBuf, feerate_sat_per_1000_weight: u32, + locktime: Option, secp_ctx: &Secp256k1 + ) -> Result +); + +impl DynKeysInterfaceTrait for DynPhantomKeysInterface { + #[cfg(test)] + fn set_counter(&self, count: u64) { + self.inner.inner.entropy_source.set_counter(count); + } +} diff --git a/lightning/src/util/mod.rs b/lightning/src/util/mod.rs index 22e6c1ffc12..e4b8b0b4429 100644 --- a/lightning/src/util/mod.rs +++ b/lightning/src/util/mod.rs @@ -67,3 +67,48 @@ pub mod string { //! [`lightning::types::string`]: crate::types::string pub use lightning_types::string::{PrintableString, UntrustedString}; } + +/// A macro to delegate trait implementations to a field of a struct. +/// +/// For example: +/// ```ignore +/// use lightning::delegate; +/// delegate!(A, T, inner, +/// fn b(, c: u64) -> u64, +/// fn m(mut, d: u64) -> (), +/// fn o(, ) -> u64, +/// #[cfg(debug_assertions)] +/// fn t(,) -> (), +/// ; +/// type O = u64, +/// #[cfg(debug_assertions)] +/// type T = (), +/// ); +/// ``` +/// +/// where T is the trait to be implemented, A is the struct +/// to implement the trait for, and inner is the field of A +/// to delegate the trait implementation to. +#[cfg(any(test, feature = "_test_utils"))] +macro_rules! delegate { + ($N: ident, $T: ident, $ref: ident, + $($(#[$fpat: meta])? fn $f: ident($($mu: ident)?, $($n: ident: $t: ty),*) -> $r: ty),* $(,)? + $(;$($(#[$tpat: meta])? type $TN: ident = $TT: ty),*)? $(,)? + ) => { + impl $T for $N { + $( + $(#[$fpat])? + fn $f(&$($mu)? self, $($n: $t),*) -> $r { + $T::$f(&$($mu)? *self.$ref, $($n),*) + } + )* + $($( + $(#[$tpat])? + type $TN = $TT; + )*)? + } + }; +} + +#[cfg(any(test, feature = "_test_utils"))] +pub mod dyn_signer; diff --git a/lightning/src/util/test_channel_signer.rs b/lightning/src/util/test_channel_signer.rs index 7c3a687d494..b65560fb9c4 100644 --- a/lightning/src/util/test_channel_signer.rs +++ b/lightning/src/util/test_channel_signer.rs @@ -21,7 +21,7 @@ use crate::types::payment::PaymentPreimage; #[allow(unused_imports)] use crate::prelude::*; -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] use crate::sync::MutexGuard; use crate::sync::{Arc, Mutex}; use core::cmp; @@ -136,17 +136,17 @@ impl TestChannelSigner { Self { inner, state, disable_revocation_policy_check } } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn get_enforcement_state(&self) -> MutexGuard { self.state.lock().unwrap() } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn enable_op(&self, signer_op: SignerOp) { self.get_enforcement_state().disabled_signer_ops.remove(&signer_op); } - #[cfg(test)] + #[cfg(any(test, feature = "_test_utils"))] pub fn disable_op(&self, signer_op: SignerOp) { self.get_enforcement_state().disabled_signer_ops.insert(signer_op); } @@ -284,13 +284,13 @@ impl EcdsaChannelSigner for TestChannelSigner { { if !self.disable_revocation_policy_check { panic!("can only sign the next two unrevoked commitment numbers, revoked={} vs requested={} for {}", - state.last_holder_revoked_commitment, commitment_number, self.inner.commitment_seed[0]) + state.last_holder_revoked_commitment, commitment_number, self.inner.channel_keys_id()[0]) } } Ok(self.inner.sign_holder_commitment(channel_parameters, commitment_tx, secp_ctx).unwrap()) } - #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))] + #[cfg(any(test, feature = "_test_utils", feature = "unsafe_revoked_tx_signing"))] fn unsafe_sign_holder_commitment( &self, channel_parameters: &ChannelTransactionParameters, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1, @@ -358,7 +358,7 @@ impl EcdsaChannelSigner for TestChannelSigner { { if !self.disable_revocation_policy_check { panic!("can only sign the next two unrevoked commitment numbers, revoked={} vs requested={} for {}", - state.last_holder_revoked_commitment, htlc_descriptor.per_commitment_number, self.inner.commitment_seed[0]) + state.last_holder_revoked_commitment, htlc_descriptor.per_commitment_number, self.inner.channel_keys_id()[0]) } } assert_eq!(htlc_tx.input[input], htlc_descriptor.unsigned_tx_input()); diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 55ae3e0a8b6..b214e9d94d0 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -13,7 +13,7 @@ use crate::blinded_path::payment::{BlindedPaymentPath, ReceiveTlvs}; use crate::chain; use crate::chain::chaininterface; use crate::chain::chaininterface::ConfirmationTarget; -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] use crate::chain::chaininterface::FEERATE_FLOOR_SATS_PER_KW; use crate::chain::chainmonitor::{ChainMonitor, Persist}; use crate::chain::channelmonitor::{ @@ -23,7 +23,7 @@ use crate::chain::transaction::OutPoint; use crate::chain::WatchedOutput; use crate::events; use crate::events::bump_transaction::{Utxo, WalletSource}; -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] use crate::ln::chan_utils::CommitmentTransaction; use crate::ln::channel_state::ChannelDetails; use crate::ln::channelmanager; @@ -46,13 +46,17 @@ use crate::routing::router::{ use crate::routing::scoring::{ChannelUsage, ScoreLookUp, ScoreUpdate}; use crate::routing::utxo::{UtxoLookup, UtxoLookupError, UtxoResult}; use crate::sign; +use crate::sign::ChannelSigner; use crate::sync::RwLock; use crate::types::features::{ChannelFeatures, InitFeatures, NodeFeatures}; use crate::util::config::UserConfig; use crate::util::logger::{Logger, Record}; +#[cfg(feature = "std")] +use crate::util::mut_global::MutGlobal; use crate::util::persist::{KVStore, MonitorName}; use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer}; use crate::util::test_channel_signer::{EnforcementState, TestChannelSigner}; +use crate::util::dyn_signer::{DynPhantomKeysInterface, DynSigner, DynKeysInterfaceTrait}; use bitcoin::amount::Amount; use bitcoin::block::Block; @@ -505,14 +509,14 @@ impl<'a> chain::Watch for TestChainMonitor<'a> { } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] struct JusticeTxData { justice_tx: Transaction, value: Amount, commitment_number: u64, } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] pub(crate) struct WatchtowerPersister { persister: TestPersister, /// Upon a new commitment_signed, we'll get a @@ -526,9 +530,8 @@ pub(crate) struct WatchtowerPersister { destination_script: ScriptBuf, } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] impl WatchtowerPersister { - #[cfg(test)] pub(crate) fn new(destination_script: ScriptBuf) -> Self { let unsigned_justice_tx_data = Mutex::new(new_hash_map()); let watchtower_state = Mutex::new(new_hash_map()); @@ -540,7 +543,6 @@ impl WatchtowerPersister { } } - #[cfg(test)] pub(crate) fn justice_tx( &self, channel_id: ChannelId, commitment_txid: &Txid, ) -> Option { @@ -571,7 +573,7 @@ impl WatchtowerPersister { } } -#[cfg(test)] +#[cfg(any(test, feature = "_test_utils"))] impl Persist for WatchtowerPersister { fn persist_new_channel( &self, monitor_name: MonitorName, data: &ChannelMonitor, @@ -1547,7 +1549,7 @@ impl SignerProvider for TestKeysInterface { 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 state = self.make_enforcement_state_cell(keys.channel_keys_id()); let signer = TestChannelSigner::new_with_revoked(keys, state, self.disable_revocation_policy_check); #[cfg(test)] @@ -1578,6 +1580,26 @@ impl SignerProvider for TestKeysInterface { } } +#[cfg(feature = "std")] +pub static SIGNER_FACTORY: MutGlobal> = MutGlobal::new(|| { Arc::new(DefaultSignerFactory()) }); + +pub trait TestSignerFactory: Send + Sync { + /// Make a dynamic signer + fn make_signer(&self, seed: &[u8; 32], now: Duration) -> Box>; +} + +#[derive(Clone)] +struct DefaultSignerFactory(); + +impl TestSignerFactory for DefaultSignerFactory { + fn make_signer(&self, seed: &[u8; 32], now: Duration) -> Box> { + let phantom = sign::PhantomKeysManager::new(seed, now.as_secs(), now.subsec_nanos(), seed); + let dphantom = DynPhantomKeysInterface::new(phantom); + let backing = Box::new(dphantom) as Box>; + backing + } +} + impl TestKeysInterface { pub fn new(seed: &[u8; 32], network: Network) -> Self { let now = Duration::from_secs(genesis_block(network).header.time as u64); @@ -1607,15 +1629,13 @@ impl TestKeysInterface { self.derive_channel_signer(*id) } - fn make_enforcement_state_cell( - &self, commitment_seed: [u8; 32], - ) -> Arc> { + fn make_enforcement_state_cell(&self, keys_id: [u8; 32]) -> Arc> { let mut states = self.enforcement_states.lock().unwrap(); - if !states.contains_key(&commitment_seed) { + if !states.contains_key(&keys_id) { let state = EnforcementState::new(); - states.insert(commitment_seed, Arc::new(Mutex::new(state))); + states.insert(keys_id, Arc::new(Mutex::new(state))); } - let cell = states.get(&commitment_seed).unwrap(); + let cell = states.get(&keys_id).unwrap(); Arc::clone(cell) } }