Skip to content

Commit f3b20fa

Browse files
committed
Allow toggling specific signing methods in test channel signer
1 parent a1fa544 commit f3b20fa

File tree

2 files changed

+104
-1
lines changed

2 files changed

+104
-1
lines changed

lightning/src/ln/functional_test_utils.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::util::errors::APIError;
3030
#[cfg(test)]
3131
use crate::util::logger::Logger;
3232
use crate::util::scid_utils;
33-
use crate::util::test_channel_signer::TestChannelSigner;
33+
use crate::util::test_channel_signer::{TestChannelSigner, ops};
3434
use crate::util::test_utils;
3535
use crate::util::test_utils::{panicking, TestChainMonitor, TestScorer, TestKeysInterface};
3636
use crate::util::ser::{ReadableArgs, Writeable};
@@ -523,6 +523,41 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
523523
.insert(channel_keys_id.unwrap());
524524
}
525525
}
526+
527+
/// Changes the channel signer's availability for the specified peer and channel.
528+
///
529+
/// When `available` is set to `true`, the channel signer will behave normally. When set to
530+
/// `false`, the channel signer will act like an off-line remote signer and will return `Err` for
531+
/// several of the signing methods. Currently, only `get_per_commitment_point` and
532+
/// `release_commitment_secret` are affected by this setting.
533+
/// several of the signing methods.
534+
#[cfg(test)]
535+
pub fn set_channel_signer_ops_available(&self, peer_id: &PublicKey, chan_id: &ChannelId, mask: u32, available: bool) {
536+
use crate::sign::ChannelSigner;
537+
log_debug!(self.logger, "Setting channel signer for {} as available={}", chan_id, available);
538+
539+
let per_peer_state = self.node.per_peer_state.read().unwrap();
540+
let chan_lock = per_peer_state.get(peer_id).unwrap().lock().unwrap();
541+
542+
let mut channel_keys_id = None;
543+
if let Some(chan) = chan_lock.channel_by_id.get(chan_id).map(|phase| phase.context()) {
544+
chan.get_signer().as_ecdsa().unwrap().set_ops_available(mask, available);
545+
channel_keys_id = Some(chan.channel_keys_id);
546+
}
547+
548+
let mut monitor = None;
549+
for (funding_txo, channel_id) in self.chain_monitor.chain_monitor.list_monitors() {
550+
if *chan_id == channel_id {
551+
monitor = self.chain_monitor.chain_monitor.get_monitor(funding_txo).ok();
552+
}
553+
}
554+
if let Some(monitor) = monitor {
555+
monitor.do_signer_call(|signer| {
556+
channel_keys_id = channel_keys_id.or(Some(signer.inner.channel_keys_id()));
557+
signer.set_ops_available(mask, available)
558+
});
559+
}
560+
}
526561
}
527562

528563
/// 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: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,51 @@ pub struct TestChannelSigner {
7676
pub available: Arc<Mutex<bool>>,
7777
}
7878

79+
/// Channel signer operations that can be individually enabled and disabled. If a particular value
80+
/// is set in the `TestChannelSigner::unavailable` bitmask, then that operation will return an
81+
/// error.
82+
pub mod ops {
83+
pub const GET_PER_COMMITMENT_POINT: u32 = 1 << 0;
84+
pub const RELEASE_COMMITMENT_SECRET: u32 = 1 << 1;
85+
pub const VALIDATE_HOLDER_COMMITMENT: u32 = 1 << 2;
86+
pub const SIGN_COUNTERPARTY_COMMITMENT: u32 = 1 << 3;
87+
pub const VALIDATE_COUNTERPARTY_REVOCATION: u32 = 1 << 4;
88+
pub const SIGN_HOLDER_COMMITMENT_AND_HTLCS: u32 = 1 << 5;
89+
pub const SIGN_JUSTICE_REVOKED_OUTPUT: u32 = 1 << 6;
90+
pub const SIGN_JUSTICE_REVOKED_HTLC: u32 = 1 << 7;
91+
pub const SIGN_HOLDER_HTLC_TRANSACTION: u32 = 1 << 8;
92+
pub const SIGN_COUNTERPARTY_HTLC_TRANSACTION: u32 = 1 << 9;
93+
pub const SIGN_CLOSING_TRANSACTION: u32 = 1 << 10;
94+
pub const SIGN_HOLDER_ANCHOR_INPUT: u32 = 1 << 11;
95+
pub const SIGN_CHANNEL_ANNOUNCMENT_WITH_FUNDING_KEY: u32 = 1 << 12;
96+
97+
#[cfg(test)]
98+
pub fn string_from(mask: u32) -> String {
99+
if mask == 0 {
100+
return "nothing".to_owned();
101+
}
102+
if mask == !(0 as u32) {
103+
return "everything".to_owned();
104+
}
105+
106+
vec![
107+
if (mask & GET_PER_COMMITMENT_POINT) != 0 { Some("get_per_commitment_point") } else { None },
108+
if (mask & RELEASE_COMMITMENT_SECRET) != 0 { Some("release_commitment_secret") } else { None },
109+
if (mask & VALIDATE_HOLDER_COMMITMENT) != 0 { Some("validate_holder_commitment") } else { None },
110+
if (mask & SIGN_COUNTERPARTY_COMMITMENT) != 0 { Some("sign_counterparty_commitment") } else { None },
111+
if (mask & VALIDATE_COUNTERPARTY_REVOCATION) != 0 { Some("validate_counterparty_revocation") } else { None },
112+
if (mask & SIGN_HOLDER_COMMITMENT_AND_HTLCS) != 0 { Some("sign_holder_commitment_and_htlcs") } else { None },
113+
if (mask & SIGN_JUSTICE_REVOKED_OUTPUT) != 0 { Some("sign_justice_revoked_output") } else { None },
114+
if (mask & SIGN_JUSTICE_REVOKED_HTLC) != 0 { Some("sign_justice_revoked_htlc") } else { None },
115+
if (mask & SIGN_HOLDER_HTLC_TRANSACTION) != 0 { Some("sign_holder_htlc_transaction") } else { None },
116+
if (mask & SIGN_COUNTERPARTY_HTLC_TRANSACTION) != 0 { Some("sign_counterparty_htlc_transaction") } else { None },
117+
if (mask & SIGN_CLOSING_TRANSACTION) != 0 { Some("sign_closing_transaction") } else { None },
118+
if (mask & SIGN_HOLDER_ANCHOR_INPUT) != 0 { Some("sign_holder_anchor_input") } else { None },
119+
if (mask & SIGN_CHANNEL_ANNOUNCMENT_WITH_FUNDING_KEY) != 0 { Some("sign_channel_announcment_with_funding_key") } else { None },
120+
].iter().flatten().map(|s| s.to_string()).collect::<Vec<_>>().join(", ")
121+
}
122+
}
123+
79124
impl PartialEq for TestChannelSigner {
80125
fn eq(&self, o: &Self) -> bool {
81126
Arc::ptr_eq(&self.state, &o.state)
@@ -123,6 +168,20 @@ impl TestChannelSigner {
123168
pub fn set_available(&self, available: bool) {
124169
*self.available.lock().unwrap() = available;
125170
}
171+
172+
#[cfg(test)]
173+
pub fn set_ops_available(&self, mask: u32, available: bool) {
174+
let mut state = self.get_enforcement_state();
175+
if available {
176+
state.unavailable_signer_ops &= !mask; // clear the bits that are now available
177+
} else {
178+
state.unavailable_signer_ops |= mask; // set the bits that are now unavailable
179+
}
180+
}
181+
182+
fn is_signer_available(&self, ops_mask: u32) -> bool {
183+
self.state.lock().unwrap().is_signer_available(ops_mask)
184+
}
126185
}
127186

128187
impl ChannelSigner for TestChannelSigner {
@@ -379,6 +438,10 @@ pub struct EnforcementState {
379438
pub last_holder_revoked_commitment: u64,
380439
/// The last validated holder commitment number, backwards counting
381440
pub last_holder_commitment: u64,
441+
/// A flag array that indicates which signing operations are currently *not* available in the
442+
/// channel. When a method's bit is set, then the signer will act as if the signature is
443+
/// unavailable and return an error result.
444+
pub unavailable_signer_ops: u32,
382445
}
383446

384447
impl EnforcementState {
@@ -389,6 +452,11 @@ impl EnforcementState {
389452
last_counterparty_revoked_commitment: INITIAL_REVOKED_COMMITMENT_NUMBER,
390453
last_holder_revoked_commitment: INITIAL_REVOKED_COMMITMENT_NUMBER,
391454
last_holder_commitment: INITIAL_REVOKED_COMMITMENT_NUMBER,
455+
unavailable_signer_ops: 0,
392456
}
393457
}
458+
459+
pub fn is_signer_available(&self, ops_mask: u32) -> bool {
460+
(self.unavailable_signer_ops & ops_mask) == 0
461+
}
394462
}

0 commit comments

Comments
 (0)