]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Allow toggling specific signing methods in test channel signer
authorAlec Chen <alecchendev@gmail.com>
Mon, 10 Jun 2024 22:01:11 +0000 (15:01 -0700)
committerAlec Chen <alecchendev@gmail.com>
Mon, 17 Jun 2024 23:32:06 +0000 (16:32 -0700)
fuzz/src/chanmon_consistency.rs
lightning/src/chain/channelmonitor.rs
lightning/src/ln/channel.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/util/test_channel_signer.rs
lightning/src/util/test_utils.rs

index c4d179e745cd6ed125f99fa578f501e78c47bc7c..423e69eb8f6f39ed94e61c8a565d366569724b2e 100644 (file)
@@ -396,12 +396,7 @@ impl SignerProvider for KeyProvider {
                let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?;
                let state = self.make_enforcement_state_cell(inner.commitment_seed);
 
-               Ok(TestChannelSigner {
-                       inner,
-                       state,
-                       disable_revocation_policy_check: false,
-                       available: Arc::new(Mutex::new(true)),
-               })
+               Ok(TestChannelSigner::new_with_revoked(inner, state, false))
        }
 
        fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result<ScriptBuf, ()> {
index cd6061a20307650e87d126afab9cc0f65aa1bbf5..5cc8030a6a1dc33b8ad58c1bb877ee808f34a6a0 100644 (file)
@@ -1928,6 +1928,12 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
                let inner = self.inner.lock().unwrap();
                f(&inner.onchain_tx_handler.signer);
        }
+
+       #[cfg(test)]
+       pub fn do_mut_signer_call<F: FnMut(&mut Signer) -> ()>(&self, mut f: F) {
+               let mut inner = self.inner.lock().unwrap();
+               f(&mut inner.onchain_tx_handler.signer);
+       }
 }
 
 impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
index 57fbe51626bec580a111f62335dfdc63d70771d5..b6004debd7aabb3404991d4f6de9b86414269ee8 100644 (file)
@@ -2122,6 +2122,12 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
                return &self.holder_signer
        }
 
+       /// Returns the holder signer for this channel.
+       #[cfg(test)]
+       pub fn get_mut_signer(&mut self) -> &mut ChannelSignerType<SP> {
+               return &mut self.holder_signer
+       }
+
        /// Only allowed immediately after deserialization if get_outbound_scid_alias returns 0,
        /// indicating we were written by LDK prior to 0.0.106 which did not set outbound SCID aliases
        /// or prior to any channel actions during `Channel` initialization.
index 7e57f20595a5b05630ace9de66b6a854043c7f56..d46588b105ade84cb22c4f1620c4c5c03fead11f 100644 (file)
@@ -31,6 +31,8 @@ use crate::util::errors::APIError;
 use crate::util::logger::Logger;
 use crate::util::scid_utils;
 use crate::util::test_channel_signer::TestChannelSigner;
+#[cfg(test)]
+use crate::util::test_channel_signer::SignerOp;
 use crate::util::test_utils;
 use crate::util::test_utils::{panicking, TestChainMonitor, TestScorer, TestKeysInterface};
 use crate::util::ser::{ReadableArgs, Writeable};
@@ -523,6 +525,75 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
                                .insert(channel_keys_id.unwrap());
                }
        }
+
+       /// Toggles this node's signer to be available for the given signer operation.
+       /// This is useful for testing behavior for restoring an async signer that previously
+       /// could not return a signature immediately.
+       #[cfg(test)]
+       pub fn enable_channel_signer_op(&self, peer_id: &PublicKey, chan_id: &ChannelId, signer_op: SignerOp) {
+               self.set_channel_signer_ops(peer_id, chan_id, signer_op, true);
+       }
+
+       /// Toggles this node's signer to be unavailable, returning `Err` for the given signer operation.
+       /// This is useful for testing behavior for an async signer that cannot return a signature
+       /// immediately.
+       #[cfg(test)]
+       pub fn disable_channel_signer_op(&self, peer_id: &PublicKey, chan_id: &ChannelId, signer_op: SignerOp) {
+               self.set_channel_signer_ops(peer_id, chan_id, signer_op, false);
+       }
+
+       /// Changes the channel signer's availability for the specified peer, channel, and signer
+       /// operation.
+       ///
+       /// For the specified signer operation, when `available` is set to `true`, the channel signer
+       /// will behave normally, returning `Ok`. When set to `false`, and the channel signer will
+       /// act like an off-line remote signer, returning `Err`. This applies to the signer in all
+       /// relevant places, i.e. the channel manager, chain monitor, and the keys manager.
+       #[cfg(test)]
+       fn set_channel_signer_ops(&self, peer_id: &PublicKey, chan_id: &ChannelId, signer_op: SignerOp, available: bool) {
+               use crate::sign::ChannelSigner;
+               log_debug!(self.logger, "Setting channel signer for {} as available={}", chan_id, available);
+
+               let per_peer_state = self.node.per_peer_state.read().unwrap();
+               let mut chan_lock = per_peer_state.get(peer_id).unwrap().lock().unwrap();
+
+               let mut channel_keys_id = None;
+               if let Some(chan) = chan_lock.channel_by_id.get_mut(chan_id).map(|phase| phase.context_mut()) {
+                       let signer = chan.get_mut_signer().as_mut_ecdsa().unwrap();
+                       if available {
+                               signer.enable_op(signer_op);
+                       } else {
+                               signer.disable_op(signer_op);
+                       }
+                       channel_keys_id = Some(chan.channel_keys_id);
+               }
+
+               let monitor = self.chain_monitor.chain_monitor.list_monitors().into_iter()
+                       .find(|(_, channel_id)| *channel_id == *chan_id)
+                       .and_then(|(funding_txo, _)| self.chain_monitor.chain_monitor.get_monitor(funding_txo).ok());
+               if let Some(monitor) = monitor {
+                       monitor.do_mut_signer_call(|signer| {
+                               channel_keys_id = channel_keys_id.or(Some(signer.inner.channel_keys_id()));
+                               if available {
+                                       signer.enable_op(signer_op);
+                               } else {
+                                       signer.disable_op(signer_op);
+                               }
+                       });
+               }
+
+               let channel_keys_id = channel_keys_id.unwrap();
+               let mut unavailable_signers_ops = self.keys_manager.unavailable_signers_ops.lock().unwrap();
+               let entry = unavailable_signers_ops.entry(channel_keys_id).or_insert(new_hash_set());
+               if available {
+                       entry.remove(&signer_op);
+                       if entry.is_empty() {
+                               unavailable_signers_ops.remove(&channel_keys_id);
+                       }
+               } else {
+                       entry.insert(signer_op);
+               };
+       }
 }
 
 /// If we need an unsafe pointer to a `Node` (ie to reference it in a thread
index 2009e4d0b08a9a22fd68941b8290bfabffe75203..2ee6a3a68f51179fb18e14a77f761c01d58bf9ad 100644 (file)
@@ -18,7 +18,7 @@ use crate::sign::ecdsa::EcdsaChannelSigner;
 #[allow(unused_imports)]
 use crate::prelude::*;
 
-use core::cmp;
+use core::{cmp, fmt};
 use crate::sync::{Mutex, Arc};
 #[cfg(test)] use crate::sync::MutexGuard;
 
@@ -74,6 +74,46 @@ pub struct TestChannelSigner {
        /// When `true` (the default), the signer will respond immediately with signatures. When `false`,
        /// the signer will return an error indicating that it is unavailable.
        pub available: Arc<Mutex<bool>>,
+       /// Set of signer operations that are disabled. If an operation is disabled,
+       /// the signer will return `Err` when the corresponding method is called.
+       pub disabled_signer_ops: Arc<Mutex<HashSet<SignerOp>>>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum SignerOp {
+       GetPerCommitmentPoint,
+       ReleaseCommitmentSecret,
+       ValidateHolderCommitment,
+       SignCounterpartyCommitment,
+       ValidateCounterpartyRevocation,
+       SignHolderCommitment,
+       SignJusticeRevokedOutput,
+       SignJusticeRevokedHtlc,
+       SignHolderHtlcTransaction,
+       SignCounterpartyHtlcTransaction,
+       SignClosingTransaction,
+       SignHolderAnchorInput,
+       SignChannelAnnouncementWithFundingKey,
+}
+
+impl fmt::Display for SignerOp {
+       fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+               match self {
+                       SignerOp::GetPerCommitmentPoint => write!(f, "get_per_commitment_point"),
+                       SignerOp::ReleaseCommitmentSecret => write!(f, "release_commitment_secret"),
+                       SignerOp::ValidateHolderCommitment => write!(f, "validate_holder_commitment"),
+                       SignerOp::SignCounterpartyCommitment => write!(f, "sign_counterparty_commitment"),
+                       SignerOp::ValidateCounterpartyRevocation => write!(f, "validate_counterparty_revocation"),
+                       SignerOp::SignHolderCommitment => write!(f, "sign_holder_commitment"),
+                       SignerOp::SignJusticeRevokedOutput => write!(f, "sign_justice_revoked_output"),
+                       SignerOp::SignJusticeRevokedHtlc => write!(f, "sign_justice_revoked_htlc"),
+                       SignerOp::SignHolderHtlcTransaction => write!(f, "sign_holder_htlc_transaction"),
+                       SignerOp::SignCounterpartyHtlcTransaction => write!(f, "sign_counterparty_htlc_transaction"),
+                       SignerOp::SignClosingTransaction => write!(f, "sign_closing_transaction"),
+                       SignerOp::SignHolderAnchorInput => write!(f, "sign_holder_anchor_input"),
+                       SignerOp::SignChannelAnnouncementWithFundingKey => write!(f, "sign_channel_announcement_with_funding_key"),
+               }
+       }
 }
 
 impl PartialEq for TestChannelSigner {
@@ -91,6 +131,7 @@ impl TestChannelSigner {
                        state,
                        disable_revocation_policy_check: false,
                        available: Arc::new(Mutex::new(true)),
+                       disabled_signer_ops: Arc::new(Mutex::new(new_hash_set())),
                }
        }
 
@@ -105,6 +146,7 @@ impl TestChannelSigner {
                        state,
                        disable_revocation_policy_check,
                        available: Arc::new(Mutex::new(true)),
+                       disabled_signer_ops: Arc::new(Mutex::new(new_hash_set())),
                }
        }
 
@@ -123,6 +165,18 @@ impl TestChannelSigner {
        pub fn set_available(&self, available: bool) {
                *self.available.lock().unwrap() = available;
        }
+
+       pub fn enable_op(&mut self, signer_op: SignerOp) {
+               self.disabled_signer_ops.lock().unwrap().remove(&signer_op);
+       }
+
+       pub fn disable_op(&mut self, signer_op: SignerOp) {
+               self.disabled_signer_ops.lock().unwrap().insert(signer_op);
+       }
+
+       fn is_signer_available(&self, signer_op: SignerOp) -> bool {
+               !self.disabled_signer_ops.lock().unwrap().contains(&signer_op)
+       }
 }
 
 impl ChannelSigner for TestChannelSigner {
index f6616a8e5d2449391c2beb68d08e93c295127cee..afdcbbac370eb37cb76cbd896b6c069d20c6c6e2 100644 (file)
@@ -79,6 +79,8 @@ use std::time::{SystemTime, UNIX_EPOCH};
 use bitcoin::psbt::Psbt;
 use bitcoin::Sequence;
 
+use super::test_channel_signer::SignerOp;
+
 pub fn pubkey(byte: u8) -> PublicKey {
        let secp_ctx = Secp256k1::new();
        PublicKey::from_secret_key(&secp_ctx, &privkey(byte))
@@ -1215,6 +1217,7 @@ pub struct TestKeysInterface {
        enforcement_states: Mutex<HashMap<[u8;32], Arc<Mutex<EnforcementState>>>>,
        expectations: Mutex<Option<VecDeque<OnGetShutdownScriptpubkey>>>,
        pub unavailable_signers: Mutex<HashSet<[u8; 32]>>,
+       pub unavailable_signers_ops: Mutex<HashMap<[u8; 32], HashSet<SignerOp>>>,
 }
 
 impl EntropySource for TestKeysInterface {
@@ -1273,10 +1276,15 @@ impl SignerProvider for TestKeysInterface {
        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);
                let state = self.make_enforcement_state_cell(keys.commitment_seed);
-               let signer = TestChannelSigner::new_with_revoked(keys, state, self.disable_revocation_policy_check);
+               let mut signer = TestChannelSigner::new_with_revoked(keys, state, self.disable_revocation_policy_check);
                if self.unavailable_signers.lock().unwrap().contains(&channel_keys_id) {
                        signer.set_available(false);
                }
+               if let Some(ops) = self.unavailable_signers_ops.lock().unwrap().get(&channel_keys_id) {
+                       for &op in ops {
+                               signer.disable_op(op);
+                       }
+               }
                signer
        }
 
@@ -1316,6 +1324,7 @@ impl TestKeysInterface {
                        enforcement_states: Mutex::new(new_hash_map()),
                        expectations: Mutex::new(None),
                        unavailable_signers: Mutex::new(new_hash_set()),
+                       unavailable_signers_ops: Mutex::new(new_hash_map()),
                }
        }