Skip to content

Commit d1e94bd

Browse files
committed
Add test for async open and accept channel
Here we make a test that disables a channel signer's ability to return commitment points upon being first derived for a channel. We also fit in a couple cleanups: removing a comment referencing a previous design with a `HolderCommitmentPoint::Uninitialized` variant, as well as adding coverage for updating channel maps in async closing signed.
1 parent e64af01 commit d1e94bd

File tree

4 files changed

+152
-41
lines changed

4 files changed

+152
-41
lines changed

lightning/src/ln/async_signer_tests.rs

+141-40
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
//! Tests for asynchronous signing. These tests verify that the channel state machine behaves
1111
//! properly with a signer implementation that asynchronously derives signatures.
1212
13-
use std::collections::HashSet;
14-
use bitcoin::key::Secp256k1;
13+
use crate::prelude::*;
14+
use bitcoin::secp256k1::Secp256k1;
1515
use bitcoin::{Transaction, TxOut, TxIn, Amount};
1616
use bitcoin::locktime::absolute::LockTime;
1717
use bitcoin::transaction::Version;
1818

1919
use crate::chain::channelmonitor::LATENCY_GRACE_PERIOD_BLOCKS;
2020
use crate::chain::ChannelMonitorUpdateStatus;
21+
use crate::chain::transaction::OutPoint;
2122
use crate::events::bump_transaction::WalletSource;
2223
use crate::events::{ClosureReason, Event, MessageSendEvent, MessageSendEventsProvider};
2324
use crate::ln::chan_utils::ClosingTransaction;
@@ -31,7 +32,78 @@ use crate::util::test_channel_signer::SignerOp;
3132
use crate::util::logger::Logger;
3233

3334
#[test]
34-
fn test_async_commitment_signature_for_funding_created() {
35+
fn test_open_channel() {
36+
do_test_open_channel(false);
37+
do_test_open_channel(true);
38+
}
39+
40+
fn do_test_open_channel(zero_conf: bool) {
41+
// Simulate acquiring the commitment point for `open_channel` and `accept_channel` asynchronously.
42+
let mut manually_accept_config = test_default_channel_config();
43+
manually_accept_config.manually_accept_inbound_channels = zero_conf;
44+
45+
let chanmon_cfgs = create_chanmon_cfgs(2);
46+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
47+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(manually_accept_config)]);
48+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
49+
50+
// Open an outbound channel simulating an async signer.
51+
let channel_value_satoshis = 100000;
52+
let user_channel_id = 42;
53+
nodes[0].disable_next_channel_signer_op(SignerOp::GetPerCommitmentPoint);
54+
let channel_id_0 = nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, 10001, user_channel_id, None, None).unwrap();
55+
56+
{
57+
let msgs = nodes[0].node.get_and_clear_pending_msg_events();
58+
assert!(msgs.is_empty(), "Expected no message events; got {:?}", msgs);
59+
}
60+
61+
nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &channel_id_0, SignerOp::GetPerCommitmentPoint);
62+
nodes[0].node.signer_unblocked(None);
63+
64+
// nodes[0] --- open_channel --> nodes[1]
65+
let mut open_chan_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
66+
67+
// Handle an inbound channel simulating an async signer.
68+
nodes[1].disable_next_channel_signer_op(SignerOp::GetPerCommitmentPoint);
69+
nodes[1].node.handle_open_channel(nodes[0].node.get_our_node_id(), &open_chan_msg);
70+
71+
if zero_conf {
72+
let events = nodes[1].node.get_and_clear_pending_events();
73+
assert_eq!(events.len(), 1, "Expected one event, got {}", events.len());
74+
match &events[0] {
75+
Event::OpenChannelRequest { temporary_channel_id, .. } => {
76+
nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(
77+
temporary_channel_id, &nodes[0].node.get_our_node_id(), 0)
78+
.expect("Unable to accept inbound zero-conf channel");
79+
},
80+
ev => panic!("Expected OpenChannelRequest, not {:?}", ev)
81+
}
82+
} else {
83+
let msgs = nodes[1].node.get_and_clear_pending_msg_events();
84+
assert!(msgs.is_empty(), "Expected no message events; got {:?}", msgs);
85+
}
86+
87+
let channel_id_1 = {
88+
let channels = nodes[1].node.list_channels();
89+
assert_eq!(channels.len(), 1, "expected one channel, not {}", channels.len());
90+
channels[0].channel_id
91+
};
92+
93+
nodes[1].enable_channel_signer_op(&nodes[0].node.get_our_node_id(), &channel_id_1, SignerOp::GetPerCommitmentPoint);
94+
nodes[1].node.signer_unblocked(None);
95+
96+
// nodes[0] <-- accept_channel --- nodes[1]
97+
get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
98+
}
99+
100+
#[test]
101+
fn test_funding_created() {
102+
do_test_funding_created(vec![SignerOp::SignCounterpartyCommitment, SignerOp::GetPerCommitmentPoint]);
103+
do_test_funding_created(vec![SignerOp::GetPerCommitmentPoint, SignerOp::SignCounterpartyCommitment]);
104+
}
105+
106+
fn do_test_funding_created(signer_ops: Vec<SignerOp>) {
35107
// Simulate acquiring the signature for `funding_created` asynchronously.
36108
let chanmon_cfgs = create_chanmon_cfgs(2);
37109
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
@@ -52,7 +124,9 @@ fn test_async_commitment_signature_for_funding_created() {
52124
// But! Let's make node[0]'s signer be unavailable: we should *not* broadcast a funding_created
53125
// message...
54126
let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100000, 42);
55-
nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &temporary_channel_id, SignerOp::SignCounterpartyCommitment);
127+
for op in signer_ops.iter() {
128+
nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &temporary_channel_id, *op);
129+
}
56130
nodes[0].node.funding_transaction_generated(temporary_channel_id, nodes[1].node.get_our_node_id(), tx.clone()).unwrap();
57131
check_added_monitors(&nodes[0], 0);
58132

@@ -66,8 +140,10 @@ fn test_async_commitment_signature_for_funding_created() {
66140
channels[0].channel_id
67141
};
68142

69-
nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
70-
nodes[0].node.signer_unblocked(Some((nodes[1].node.get_our_node_id(), chan_id)));
143+
for op in signer_ops.iter() {
144+
nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, *op);
145+
nodes[0].node.signer_unblocked(Some((nodes[1].node.get_our_node_id(), chan_id)));
146+
}
71147

72148
let mut funding_created_msg = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
73149
nodes[1].node.handle_funding_created(nodes[0].node.get_our_node_id(), &funding_created_msg);
@@ -82,7 +158,12 @@ fn test_async_commitment_signature_for_funding_created() {
82158
}
83159

84160
#[test]
85-
fn test_async_commitment_signature_for_funding_signed() {
161+
fn test_funding_signed() {
162+
do_test_funding_signed(vec![SignerOp::SignCounterpartyCommitment, SignerOp::GetPerCommitmentPoint]);
163+
do_test_funding_signed(vec![SignerOp::GetPerCommitmentPoint, SignerOp::SignCounterpartyCommitment]);
164+
}
165+
166+
fn do_test_funding_signed(signer_ops: Vec<SignerOp>) {
86167
// Simulate acquiring the signature for `funding_signed` asynchronously.
87168
let chanmon_cfgs = create_chanmon_cfgs(2);
88169
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
@@ -107,7 +188,9 @@ fn test_async_commitment_signature_for_funding_signed() {
107188

108189
// Now let's make node[1]'s signer be unavailable while handling the `funding_created`. It should
109190
// *not* broadcast a `funding_signed`...
110-
nodes[1].disable_channel_signer_op(&nodes[0].node.get_our_node_id(), &temporary_channel_id, SignerOp::SignCounterpartyCommitment);
191+
for op in signer_ops.iter() {
192+
nodes[1].disable_channel_signer_op(&nodes[0].node.get_our_node_id(), &temporary_channel_id, *op);
193+
}
111194
nodes[1].node.handle_funding_created(nodes[0].node.get_our_node_id(), &funding_created_msg);
112195
check_added_monitors(&nodes[1], 1);
113196

@@ -120,16 +203,21 @@ fn test_async_commitment_signature_for_funding_signed() {
120203
assert_eq!(channels.len(), 1, "expected one channel, not {}", channels.len());
121204
channels[0].channel_id
122205
};
123-
nodes[1].enable_channel_signer_op(&nodes[0].node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
124-
nodes[1].node.signer_unblocked(Some((nodes[0].node.get_our_node_id(), chan_id)));
125-
126-
expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id());
127-
128-
// nodes[0] <-- funding_signed --- nodes[1]
129-
let funding_signed_msg = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id());
130-
nodes[0].node.handle_funding_signed(nodes[1].node.get_our_node_id(), &funding_signed_msg);
131-
check_added_monitors(&nodes[0], 1);
132-
expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id());
206+
for op in signer_ops.iter() {
207+
nodes[1].enable_channel_signer_op(&nodes[0].node.get_our_node_id(), &chan_id, *op);
208+
nodes[1].node.signer_unblocked(Some((nodes[0].node.get_our_node_id(), chan_id)));
209+
if *op == SignerOp::SignCounterpartyCommitment {
210+
expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id());
211+
212+
// nodes[0] <-- funding_signed --- nodes[1]
213+
let funding_signed_msg = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id());
214+
nodes[0].node.handle_funding_signed(nodes[1].node.get_our_node_id(), &funding_signed_msg);
215+
check_added_monitors(&nodes[0], 1);
216+
expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id());
217+
} else {
218+
assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
219+
}
220+
}
133221
}
134222

135223
#[test]
@@ -178,7 +266,7 @@ fn do_test_async_commitment_signature_for_commitment_signed_revoke_and_ack(enabl
178266
dst.node.handle_commitment_signed(src.node.get_our_node_id(), &payment_event.commitment_msg);
179267
check_added_monitors(dst, 1);
180268

181-
let mut enabled_signer_ops = HashSet::new();
269+
let mut enabled_signer_ops = new_hash_set();
182270
log_trace!(dst.logger, "enable_signer_op_order={:?}", enable_signer_op_order);
183271
for op in enable_signer_op_order {
184272
enabled_signer_ops.insert(op);
@@ -204,7 +292,12 @@ fn do_test_async_commitment_signature_for_commitment_signed_revoke_and_ack(enabl
204292
}
205293

206294
#[test]
207-
fn test_async_commitment_signature_for_funding_signed_0conf() {
295+
fn test_funding_signed_0conf() {
296+
do_test_funding_signed_0conf(vec![SignerOp::GetPerCommitmentPoint, SignerOp::SignCounterpartyCommitment]);
297+
do_test_funding_signed_0conf(vec![SignerOp::SignCounterpartyCommitment, SignerOp::GetPerCommitmentPoint]);
298+
}
299+
300+
fn do_test_funding_signed_0conf(signer_ops: Vec<SignerOp>) {
208301
// Simulate acquiring the signature for `funding_signed` asynchronously for a zero-conf channel.
209302
let mut manually_accept_config = test_default_channel_config();
210303
manually_accept_config.manually_accept_inbound_channels = true;
@@ -247,7 +340,9 @@ fn test_async_commitment_signature_for_funding_signed_0conf() {
247340

248341
// Now let's make node[1]'s signer be unavailable while handling the `funding_created`. It should
249342
// *not* broadcast a `funding_signed`...
250-
nodes[1].disable_channel_signer_op(&nodes[0].node.get_our_node_id(), &temporary_channel_id, SignerOp::SignCounterpartyCommitment);
343+
for op in signer_ops.iter() {
344+
nodes[1].disable_channel_signer_op(&nodes[0].node.get_our_node_id(), &temporary_channel_id, *op);
345+
}
251346
nodes[1].node.handle_funding_created(nodes[0].node.get_our_node_id(), &funding_created_msg);
252347
check_added_monitors(&nodes[1], 1);
253348

@@ -262,8 +357,10 @@ fn test_async_commitment_signature_for_funding_signed_0conf() {
262357
};
263358

264359
// At this point, we basically expect the channel to open like a normal zero-conf channel.
265-
nodes[1].enable_channel_signer_op(&nodes[0].node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
266-
nodes[1].node.signer_unblocked(Some((nodes[0].node.get_our_node_id(), chan_id)));
360+
for op in signer_ops.iter() {
361+
nodes[1].enable_channel_signer_op(&nodes[0].node.get_our_node_id(), &chan_id, *op);
362+
nodes[1].node.signer_unblocked(Some((nodes[0].node.get_our_node_id(), chan_id)));
363+
}
267364

268365
let (funding_signed, channel_ready_1) = {
269366
let events = nodes[1].node.get_and_clear_pending_msg_events();
@@ -867,65 +964,65 @@ fn do_test_closing_signed(extra_closing_signed: bool, reconnect: bool) {
867964
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
868965
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
869966
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
870-
let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);
967+
let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
871968

872969
// Avoid extra channel ready message upon reestablish later
873970
send_payment(&nodes[0], &vec![&nodes[1]][..], 8_000_000);
874971

875-
expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::NotShuttingDown);
972+
expect_channel_shutdown_state!(nodes[0], chan_id, ChannelShutdownState::NotShuttingDown);
876973

877-
nodes[0].node.close_channel(&chan_1.2, &nodes[1].node.get_our_node_id()).unwrap();
974+
nodes[0].node.close_channel(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
878975

879-
expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::ShutdownInitiated);
880-
expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::NotShuttingDown);
976+
expect_channel_shutdown_state!(nodes[0], chan_id, ChannelShutdownState::ShutdownInitiated);
977+
expect_channel_shutdown_state!(nodes[1], chan_id, ChannelShutdownState::NotShuttingDown);
881978

882979
let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
883980
nodes[1].node.handle_shutdown(nodes[0].node.get_our_node_id(), &node_0_shutdown);
884981

885-
expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::ShutdownInitiated);
886-
expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::NegotiatingClosingFee);
982+
expect_channel_shutdown_state!(nodes[0], chan_id, ChannelShutdownState::ShutdownInitiated);
983+
expect_channel_shutdown_state!(nodes[1], chan_id, ChannelShutdownState::NegotiatingClosingFee);
887984

888985
let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
889-
nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_1.2, SignerOp::SignClosingTransaction);
986+
nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignClosingTransaction);
890987
nodes[0].node.handle_shutdown(nodes[1].node.get_our_node_id(), &node_1_shutdown);
891988

892-
expect_channel_shutdown_state!(nodes[0], chan_1.2, ChannelShutdownState::NegotiatingClosingFee);
893-
expect_channel_shutdown_state!(nodes[1], chan_1.2, ChannelShutdownState::NegotiatingClosingFee);
989+
expect_channel_shutdown_state!(nodes[0], chan_id, ChannelShutdownState::NegotiatingClosingFee);
990+
expect_channel_shutdown_state!(nodes[1], chan_id, ChannelShutdownState::NegotiatingClosingFee);
894991

895992
let events = nodes[0].node.get_and_clear_pending_msg_events();
896993
assert!(events.is_empty(), "Expected no events, got {:?}", events);
897-
nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_1.2, SignerOp::SignClosingTransaction);
994+
nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignClosingTransaction);
898995
nodes[0].node.signer_unblocked(None);
899996

900997
let node_0_closing_signed = get_event_msg!(nodes[0], MessageSendEvent::SendClosingSigned, nodes[1].node.get_our_node_id());
901-
nodes[1].disable_channel_signer_op(&nodes[0].node.get_our_node_id(), &chan_1.2, SignerOp::SignClosingTransaction);
998+
nodes[1].disable_channel_signer_op(&nodes[0].node.get_our_node_id(), &chan_id, SignerOp::SignClosingTransaction);
902999
nodes[1].node.handle_closing_signed(nodes[0].node.get_our_node_id(), &node_0_closing_signed);
9031000

9041001
let events = nodes[1].node.get_and_clear_pending_msg_events();
9051002
assert!(events.is_empty(), "Expected no events, got {:?}", events);
906-
nodes[1].enable_channel_signer_op(&nodes[0].node.get_our_node_id(), &chan_1.2, SignerOp::SignClosingTransaction);
1003+
nodes[1].enable_channel_signer_op(&nodes[0].node.get_our_node_id(), &chan_id, SignerOp::SignClosingTransaction);
9071004
nodes[1].node.signer_unblocked(None);
9081005

9091006
let node_1_closing_signed = get_event_msg!(nodes[1], MessageSendEvent::SendClosingSigned, nodes[0].node.get_our_node_id());
9101007

911-
nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_1.2, SignerOp::SignClosingTransaction);
1008+
nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignClosingTransaction);
9121009
nodes[0].node.handle_closing_signed(nodes[1].node.get_our_node_id(), &node_1_closing_signed);
9131010
let events = nodes[0].node.get_and_clear_pending_msg_events();
9141011
assert!(events.is_empty(), "Expected no events, got {:?}", events);
915-
nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_1.2, SignerOp::SignClosingTransaction);
1012+
nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignClosingTransaction);
9161013

9171014
if extra_closing_signed {
9181015
let node_1_closing_signed_2_bad = {
9191016
let mut node_1_closing_signed_2 = node_1_closing_signed.clone();
9201017
let holder_script = nodes[0].keys_manager.get_shutdown_scriptpubkey().unwrap();
9211018
let counterparty_script = nodes[1].keys_manager.get_shutdown_scriptpubkey().unwrap();
922-
let funding_outpoint = bitcoin::OutPoint { txid: chan_1.3.compute_txid(), vout: 0 };
1019+
let funding_outpoint = bitcoin::OutPoint { txid: funding_tx.compute_txid(), vout: 0 };
9231020
let closing_tx_2 = ClosingTransaction::new(50000, 0, holder_script.into(),
9241021
counterparty_script.into(), funding_outpoint);
9251022

9261023
let per_peer_state = nodes[1].node.per_peer_state.read().unwrap();
9271024
let mut chan_lock = per_peer_state.get(&nodes[0].node.get_our_node_id()).unwrap().lock().unwrap();
928-
let chan = chan_lock.channel_by_id.get_mut(&chan_1.2).map(|phase| phase.context_mut()).unwrap();
1025+
let chan = chan_lock.channel_by_id.get_mut(&chan_id).map(|phase| phase.context_mut()).unwrap();
9291026

9301027
let signer = chan.get_mut_signer().as_mut_ecdsa().unwrap();
9311028
let signature = signer.sign_closing_transaction(&closing_tx_2, &Secp256k1::new()).unwrap();
@@ -994,4 +1091,8 @@ fn do_test_closing_signed(extra_closing_signed: bool, reconnect: bool) {
9941091
check_closed_event!(nodes[0], 1, ClosureReason::LocallyInitiatedCooperativeClosure, [nodes[1].node.get_our_node_id()], 100000);
9951092
check_closed_event!(nodes[1], 1, ClosureReason::CounterpartyInitiatedCooperativeClosure, [nodes[0].node.get_our_node_id()], 100000);
9961093

1094+
// Check that our maps have been updated after async signing channel closure.
1095+
let funding_outpoint = OutPoint { txid: funding_tx.compute_txid(), index: 0 };
1096+
assert!(nodes[0].node().outpoint_to_peer.lock().unwrap().get(&funding_outpoint).is_none());
1097+
assert!(nodes[1].node().outpoint_to_peer.lock().unwrap().get(&funding_outpoint).is_none());
9971098
}

lightning/src/ln/channel.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10130,7 +10130,6 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
1013010130
transaction_number: cur_holder_commitment_transaction_number, current,
1013110131
},
1013210132
(_, _) => {
10133-
// TODO(async_signing): remove this expect with the Uninitialized variant
1013410133
let current = holder_signer.get_per_commitment_point(cur_holder_commitment_transaction_number, &secp_ctx)
1013510134
.expect("Must be able to derive the current commitment point upon channel restoration");
1013610135
let next = holder_signer.get_per_commitment_point(cur_holder_commitment_transaction_number - 1, &secp_ctx)

lightning/src/ln/functional_test_utils.rs

+5
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,11 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
580580
entry.insert(signer_op);
581581
};
582582
}
583+
584+
#[cfg(test)]
585+
pub fn disable_next_channel_signer_op(&self, signer_op: SignerOp) {
586+
self.keys_manager.next_signer_disabled_ops.lock().unwrap().insert(signer_op);
587+
}
583588
}
584589

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

lightning/src/util/test_utils.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,7 @@ pub struct TestKeysInterface {
12341234
enforcement_states: Mutex<HashMap<[u8;32], Arc<Mutex<EnforcementState>>>>,
12351235
expectations: Mutex<Option<VecDeque<OnGetShutdownScriptpubkey>>>,
12361236
pub unavailable_signers_ops: Mutex<HashMap<[u8; 32], HashSet<SignerOp>>>,
1237+
pub next_signer_disabled_ops: Mutex<HashSet<SignerOp>>,
12371238
}
12381239

12391240
impl EntropySource for TestKeysInterface {
@@ -1293,6 +1294,10 @@ impl SignerProvider for TestKeysInterface {
12931294
signer.disable_op(op);
12941295
}
12951296
}
1297+
#[cfg(test)]
1298+
for op in self.next_signer_disabled_ops.lock().unwrap().drain() {
1299+
signer.disable_op(op);
1300+
}
12961301
signer
12971302
}
12981303

@@ -1332,6 +1337,7 @@ impl TestKeysInterface {
13321337
enforcement_states: Mutex::new(new_hash_map()),
13331338
expectations: Mutex::new(None),
13341339
unavailable_signers_ops: Mutex::new(new_hash_map()),
1340+
next_signer_disabled_ops: Mutex::new(new_hash_set()),
13351341
}
13361342
}
13371343

0 commit comments

Comments
 (0)