Skip to content

Commit 0983db1

Browse files
committed
Add support for retrieving and suspending the channel signer
This adds a `get_signer` method to the context so that a test can get ahold of the channel signer. Adds a `set_available` method on the `TestChannelSigner` to allow a test to enable and disable the signer: when disabled some of the signer's methods will return `Err` which will typically activate the error handling case. Adds a `set_channel_signer_available` function on the test `Node` class to make it easy to enable and disable a specific signer. Fix fuzz test
1 parent 06f5ea0 commit 0983db1

File tree

4 files changed

+54
-2
lines changed

4 files changed

+54
-2
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ impl SignerProvider for KeyProvider {
266266
inner,
267267
state,
268268
disable_revocation_policy_check: false,
269+
available: Arc::new(Mutex::new(true)),
269270
})
270271
}
271272

lightning/src/ln/channel.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,12 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider {
10541054
self.outbound_scid_alias
10551055
}
10561056

1057+
/// Returns the holder signer for this channel.
1058+
#[cfg(test)]
1059+
pub fn get_signer(&self) -> &ChannelSignerType<<SP::Target as SignerProvider>::Signer> {
1060+
return &self.holder_signer
1061+
}
1062+
10571063
/// Only allowed immediately after deserialization if get_outbound_scid_alias returns 0,
10581064
/// indicating we were written by LDK prior to 0.0.106 which did not set outbound SCID aliases
10591065
/// or prior to any channel actions during `Channel` initialization.

lightning/src/ln/functional_test_utils.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ use crate::util::test_utils::{panicking, TestChainMonitor, TestScorer, TestKeysI
3030
use crate::util::errors::APIError;
3131
use crate::util::config::{UserConfig, MaxDustHTLCExposure};
3232
use crate::util::ser::{ReadableArgs, Writeable};
33+
#[cfg(test)]
34+
use crate::util::logger::Logger;
3335

3436
use bitcoin::blockdata::block::{Block, BlockHeader};
3537
use bitcoin::blockdata::transaction::{Transaction, TxOut};
@@ -432,6 +434,25 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
432434
pub fn get_block_header(&self, height: u32) -> BlockHeader {
433435
self.blocks.lock().unwrap()[height as usize].0.header
434436
}
437+
/// Changes the channel signer's availability for the specified peer and channel.
438+
///
439+
/// When `available` is set to `true`, the channel signer will behave normally. When set to
440+
/// `false`, the channel signer will act like an off-line remote signer and will return `Err` for
441+
/// several of the signing methods. Currently, only `get_per_commitment_point` and
442+
/// `release_commitment_secret` are affected by this setting.
443+
#[cfg(test)]
444+
pub fn set_channel_signer_available(&self, peer_id: &PublicKey, chan_id: &ChannelId, available: bool) {
445+
let per_peer_state = self.node.per_peer_state.read().unwrap();
446+
let chan_lock = per_peer_state.get(peer_id).unwrap().lock().unwrap();
447+
let signer = (|| {
448+
match chan_lock.channel_by_id.get(chan_id) {
449+
Some(phase) => phase.context().get_signer(),
450+
None => panic!("Couldn't find a channel with id {}", chan_id),
451+
}
452+
})();
453+
log_debug!(self.logger, "Setting channel signer for {} as available={}", chan_id, available);
454+
signer.as_ecdsa().unwrap().set_available(available);
455+
}
435456
}
436457

437458
/// If we need an unsafe pointer to a `Node` (ie to reference it in a thread

lightning/src/util/test_channel_signer.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ pub struct TestChannelSigner {
5656
/// Channel state used for policy enforcement
5757
pub state: Arc<Mutex<EnforcementState>>,
5858
pub disable_revocation_policy_check: bool,
59+
/// When `true` (the default), the signer will respond immediately with signatures. When `false`,
60+
/// the signer will return an error indicating that it is unavailable.
61+
pub available: Arc<Mutex<bool>>,
5962
}
6063

6164
impl PartialEq for TestChannelSigner {
@@ -71,7 +74,8 @@ impl TestChannelSigner {
7174
Self {
7275
inner,
7376
state,
74-
disable_revocation_policy_check: false
77+
disable_revocation_policy_check: false,
78+
available: Arc::new(Mutex::new(true)),
7579
}
7680
}
7781

@@ -84,7 +88,8 @@ impl TestChannelSigner {
8488
Self {
8589
inner,
8690
state,
87-
disable_revocation_policy_check
91+
disable_revocation_policy_check,
92+
available: Arc::new(Mutex::new(true)),
8893
}
8994
}
9095

@@ -94,6 +99,16 @@ impl TestChannelSigner {
9499
pub fn get_enforcement_state(&self) -> MutexGuard<EnforcementState> {
95100
self.state.lock().unwrap()
96101
}
102+
103+
/// Marks the signer's availability.
104+
///
105+
/// When `true`, methods are forwarded to the underlying signer as normal. When `false`, some
106+
/// methods will return `Err` indicating that the signer is unavailable. Intended to be used for
107+
/// testing asynchronous signing.
108+
#[cfg(test)]
109+
pub fn set_available(&self, available: bool) {
110+
*self.available.lock().unwrap() = available;
111+
}
97112
}
98113

99114
impl ChannelSigner for TestChannelSigner {
@@ -133,6 +148,9 @@ impl EcdsaChannelSigner for TestChannelSigner {
133148
self.verify_counterparty_commitment_tx(commitment_tx, secp_ctx);
134149

135150
{
151+
if !*self.available.lock().unwrap() {
152+
return Err(());
153+
}
136154
let mut state = self.state.lock().unwrap();
137155
let actual_commitment_number = commitment_tx.commitment_number();
138156
let last_commitment_number = state.last_counterparty_commitment;
@@ -149,13 +167,19 @@ impl EcdsaChannelSigner for TestChannelSigner {
149167
}
150168

151169
fn validate_counterparty_revocation(&self, idx: u64, _secret: &SecretKey) -> Result<(), ()> {
170+
if !*self.available.lock().unwrap() {
171+
return Err(());
172+
}
152173
let mut state = self.state.lock().unwrap();
153174
assert!(idx == state.last_counterparty_revoked_commitment || idx == state.last_counterparty_revoked_commitment - 1, "expecting to validate the current or next counterparty revocation - trying {}, current {}", idx, state.last_counterparty_revoked_commitment);
154175
state.last_counterparty_revoked_commitment = idx;
155176
Ok(())
156177
}
157178

158179
fn sign_holder_commitment_and_htlcs(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<(Signature, Vec<Signature>), ()> {
180+
if !*self.available.lock().unwrap() {
181+
return Err(());
182+
}
159183
let trusted_tx = self.verify_holder_commitment_tx(commitment_tx, secp_ctx);
160184
let commitment_txid = trusted_tx.txid();
161185
let holder_csv = self.inner.counterparty_selected_contest_delay();

0 commit comments

Comments
 (0)