mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-04-29 04:05:21 +08:00
Merge branch 'next' into draft/multisig-order-independence
This commit is contained in:
@@ -92,6 +92,8 @@ struct SignerTest {
|
||||
pub signer_stacks_private_keys: Vec<StacksPrivateKey>,
|
||||
// link to the stacks node
|
||||
pub stacks_client: StacksClient,
|
||||
// Unique number used to isolate files created during the test
|
||||
pub run_stamp: u16,
|
||||
}
|
||||
|
||||
impl SignerTest {
|
||||
@@ -107,6 +109,8 @@ impl SignerTest {
|
||||
let password = "12345";
|
||||
naka_conf.connection_options.block_proposal_token = Some(password.to_string());
|
||||
|
||||
let run_stamp = rand::random();
|
||||
|
||||
// Setup the signer and coordinator configurations
|
||||
let signer_configs = build_signer_config_tomls(
|
||||
&signer_stacks_private_keys,
|
||||
@@ -114,6 +118,8 @@ impl SignerTest {
|
||||
Some(Duration::from_millis(128)), // Timeout defaults to 5 seconds. Let's override it to 128 milliseconds.
|
||||
&Network::Testnet,
|
||||
password,
|
||||
run_stamp,
|
||||
3000,
|
||||
);
|
||||
|
||||
let mut running_signers = Vec::new();
|
||||
@@ -144,6 +150,7 @@ impl SignerTest {
|
||||
running_signers,
|
||||
signer_stacks_private_keys,
|
||||
stacks_client,
|
||||
run_stamp,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,22 +433,11 @@ impl SignerTest {
|
||||
.expect("failed to recv dkg results");
|
||||
for result in results {
|
||||
match result {
|
||||
OperationResult::Sign(sig) => {
|
||||
panic!("Received Signature ({},{})", &sig.R, &sig.z);
|
||||
}
|
||||
OperationResult::SignTaproot(proof) => {
|
||||
panic!("Received SchnorrProof ({},{})", &proof.r, &proof.s);
|
||||
}
|
||||
OperationResult::DkgError(dkg_error) => {
|
||||
panic!("Received DkgError {:?}", dkg_error);
|
||||
}
|
||||
OperationResult::SignError(sign_error) => {
|
||||
panic!("Received SignError {}", sign_error);
|
||||
}
|
||||
OperationResult::Dkg(point) => {
|
||||
info!("Received aggregate_group_key {point}");
|
||||
aggregate_public_key = Some(point);
|
||||
}
|
||||
other => panic!("{}", operation_panic_message(&other)),
|
||||
}
|
||||
}
|
||||
if aggregate_public_key.is_some() || dkg_now.elapsed() > timeout {
|
||||
@@ -703,6 +699,46 @@ impl SignerTest {
|
||||
]
|
||||
}
|
||||
|
||||
/// Kills the signer runloop at index `signer_idx`
|
||||
/// and returns the private key of the killed signer.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if `signer_idx` is out of bounds
|
||||
fn stop_signer(&mut self, signer_idx: usize) -> StacksPrivateKey {
|
||||
let running_signer = self.running_signers.remove(signer_idx);
|
||||
self.signer_cmd_senders.remove(signer_idx);
|
||||
self.result_receivers.remove(signer_idx);
|
||||
let signer_key = self.signer_stacks_private_keys.remove(signer_idx);
|
||||
|
||||
running_signer.stop();
|
||||
signer_key
|
||||
}
|
||||
|
||||
/// (Re)starts a new signer runloop with the given private key
|
||||
fn restart_signer(&mut self, signer_idx: usize, signer_private_key: StacksPrivateKey) {
|
||||
let signer_config = build_signer_config_tomls(
|
||||
&[signer_private_key],
|
||||
&self.running_nodes.conf.node.rpc_bind,
|
||||
Some(Duration::from_millis(128)), // Timeout defaults to 5 seconds. Let's override it to 128 milliseconds.
|
||||
&Network::Testnet,
|
||||
"12345", // It worked sir, we have the combination! -Great, what's the combination?
|
||||
self.run_stamp,
|
||||
3000 + signer_idx,
|
||||
)
|
||||
.pop()
|
||||
.unwrap();
|
||||
|
||||
let (cmd_send, cmd_recv) = channel();
|
||||
let (res_send, res_recv) = channel();
|
||||
|
||||
info!("Restarting signer");
|
||||
let signer = spawn_signer(&signer_config, cmd_recv, res_send);
|
||||
|
||||
self.result_receivers.insert(signer_idx, res_recv);
|
||||
self.signer_cmd_senders.insert(signer_idx, cmd_send);
|
||||
self.running_signers.insert(signer_idx, signer);
|
||||
}
|
||||
|
||||
fn shutdown(self) {
|
||||
self.running_nodes
|
||||
.coord_channel
|
||||
@@ -851,6 +887,26 @@ fn setup_stx_btc_node(
|
||||
}
|
||||
}
|
||||
|
||||
fn operation_panic_message(result: &OperationResult) -> String {
|
||||
match result {
|
||||
OperationResult::Sign(sig) => {
|
||||
format!("Received Signature ({},{})", sig.R, sig.z)
|
||||
}
|
||||
OperationResult::SignTaproot(proof) => {
|
||||
format!("Received SchnorrProof ({},{})", proof.r, proof.s)
|
||||
}
|
||||
OperationResult::DkgError(dkg_error) => {
|
||||
format!("Received DkgError {:?}", dkg_error)
|
||||
}
|
||||
OperationResult::SignError(sign_error) => {
|
||||
format!("Received SignError {}", sign_error)
|
||||
}
|
||||
OperationResult::Dkg(point) => {
|
||||
format!("Received aggregate_group_key {point}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
/// Test the signer can respond to external commands to perform DKG
|
||||
@@ -1266,3 +1322,72 @@ fn stackerdb_filter_bad_transactions() {
|
||||
}
|
||||
signer_test.shutdown();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
/// Test that signers will be able to continue their operations even if one signer is restarted.
|
||||
///
|
||||
/// Test Setup:
|
||||
/// The test spins up three stacks signers, one miner Nakamoto node, and a corresponding bitcoind.
|
||||
/// The stacks node is advanced to epoch 2.5, triggering a DKG round. The stacks node is then advanced
|
||||
/// to Epoch 3.0 boundary to allow block signing.
|
||||
///
|
||||
/// Test Execution:
|
||||
/// The signers sign one block as usual.
|
||||
/// Then, one of the signers is restarted.
|
||||
/// Finally, the signers sign another block with the restarted signer.
|
||||
///
|
||||
/// Test Assertion:
|
||||
/// The signers are able to produce a valid signature after one of them is restarted.
|
||||
fn stackerdb_sign_after_signer_reboot() {
|
||||
if env::var("BITCOIND_TEST") != Ok("1".into()) {
|
||||
return;
|
||||
}
|
||||
|
||||
tracing_subscriber::registry()
|
||||
.with(fmt::layer())
|
||||
.with(EnvFilter::from_default_env())
|
||||
.init();
|
||||
|
||||
info!("------------------------- Test Setup -------------------------");
|
||||
let mut signer_test = SignerTest::new(3);
|
||||
let timeout = Duration::from_secs(200);
|
||||
let short_timeout = Duration::from_secs(30);
|
||||
|
||||
let key = signer_test.boot_to_epoch_3(timeout);
|
||||
|
||||
info!("------------------------- Test Mine Block -------------------------");
|
||||
|
||||
signer_test.mine_nakamoto_block(timeout);
|
||||
let proposed_signer_signature_hash = signer_test.wait_for_validate_ok_response(short_timeout);
|
||||
let signature =
|
||||
signer_test.wait_for_confirmed_block(&proposed_signer_signature_hash, short_timeout);
|
||||
|
||||
assert!(
|
||||
signature.verify(&key, proposed_signer_signature_hash.0.as_slice()),
|
||||
"Signature verification failed"
|
||||
);
|
||||
|
||||
info!("------------------------- Restart one Signer -------------------------");
|
||||
let signer_key = signer_test.stop_signer(2);
|
||||
debug!(
|
||||
"Removed signer 2 with key: {:?}, {}",
|
||||
signer_key,
|
||||
signer_key.to_hex()
|
||||
);
|
||||
signer_test.restart_signer(2, signer_key);
|
||||
|
||||
info!("------------------------- Test Mine Block after restart -------------------------");
|
||||
|
||||
signer_test.mine_nakamoto_block(timeout);
|
||||
let proposed_signer_signature_hash = signer_test.wait_for_validate_ok_response(short_timeout);
|
||||
let frost_signature =
|
||||
signer_test.wait_for_confirmed_block(&proposed_signer_signature_hash, short_timeout);
|
||||
|
||||
assert!(
|
||||
frost_signature.verify(&key, proposed_signer_signature_hash.0.as_slice()),
|
||||
"Signature verification failed"
|
||||
);
|
||||
|
||||
signer_test.shutdown();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user