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, ()> {
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> {
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.
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};
.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
#[allow(unused_imports)]
use crate::prelude::*;
-use core::cmp;
+use core::{cmp, fmt};
use crate::sync::{Mutex, Arc};
#[cfg(test)] use crate::sync::MutexGuard;
/// 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 {
state,
disable_revocation_policy_check: false,
available: Arc::new(Mutex::new(true)),
+ disabled_signer_ops: Arc::new(Mutex::new(new_hash_set())),
}
}
state,
disable_revocation_policy_check,
available: Arc::new(Mutex::new(true)),
+ disabled_signer_ops: Arc::new(Mutex::new(new_hash_set())),
}
}
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 {
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))
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 {
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
}
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()),
}
}