Skip to content

Commit 5f3a7f2

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 242c2f5 commit 5f3a7f2

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
@@ -267,6 +267,7 @@ impl SignerProvider for KeyProvider {
267267
inner,
268268
state,
269269
disable_revocation_policy_check: false,
270+
available: Arc::new(Mutex::new(true)),
270271
})
271272
}
272273

lightning/src/ln/channel.rs

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

1080+
/// Returns the holder signer for this channel.
1081+
#[cfg(test)]
1082+
pub fn get_signer(&self) -> &ChannelSignerType<<SP::Target as SignerProvider>::Signer> {
1083+
return &self.holder_signer
1084+
}
1085+
10801086
/// Only allowed immediately after deserialization if get_outbound_scid_alias returns 0,
10811087
/// indicating we were written by LDK prior to 0.0.106 which did not set outbound SCID aliases
10821088
/// 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};
@@ -436,6 +438,25 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
436438
pub fn get_block_header(&self, height: u32) -> BlockHeader {
437439
self.blocks.lock().unwrap()[height as usize].0.header
438440
}
441+
/// Changes the channel signer's availability for the specified peer and channel.
442+
///
443+
/// When `available` is set to `true`, the channel signer will behave normally. When set to
444+
/// `false`, the channel signer will act like an off-line remote signer and will return `Err` for
445+
/// several of the signing methods. Currently, only `get_per_commitment_point` and
446+
/// `release_commitment_secret` are affected by this setting.
447+
#[cfg(test)]
448+
pub fn set_channel_signer_available(&self, peer_id: &PublicKey, chan_id: &ChannelId, available: bool) {
449+
let per_peer_state = self.node.per_peer_state.read().unwrap();
450+
let chan_lock = per_peer_state.get(peer_id).unwrap().lock().unwrap();
451+
let signer = (|| {
452+
match chan_lock.channel_by_id.get(chan_id) {
453+
Some(phase) => phase.context().get_signer(),
454+
None => panic!("Couldn't find a channel with id {}", chan_id),
455+
}
456+
})();
457+
log_debug!(self.logger, "Setting channel signer for {} as available={}", chan_id, available);
458+
signer.as_ecdsa().unwrap().set_available(available);
459+
}
439460
}
440461

441462
/// 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(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<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 state = self.state.lock().unwrap();
161185
let commitment_number = trusted_tx.commitment_number();

0 commit comments

Comments
 (0)