diff --git a/Cargo.lock b/Cargo.lock index 1eaf731f65..205c428b80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3548,6 +3548,7 @@ dependencies = [ "base64 0.12.3", "chrono", "clarity", + "hashbrown 0.14.0", "http-types", "lazy_static", "libc", @@ -3615,6 +3616,7 @@ dependencies = [ "criterion", "curve25519-dalek", "ed25519-dalek", + "hashbrown 0.14.0", "integer-sqrt", "lazy_static", "libc", @@ -4714,9 +4716,9 @@ dependencies = [ [[package]] name = "wsts" -version = "6.1.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c7db3d3fe28c359e0cdb7f7ad83e3316bda0ba982b8cd1bf0fbe73ae4127e4b" +checksum = "c398736468f3322a43b6419be5315e68ae035e6565628603503c2a62ad726f36" dependencies = [ "aes-gcm 0.10.2", "bs58 0.5.0", diff --git a/Cargo.toml b/Cargo.toml index 33f1720b77..4564ee800c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ # Dependencies we want to keep the same between workspace members [workspace.dependencies] -wsts = "6.1" +wsts = "7.0" rand_core = "0.6" rand = "0.8" diff --git a/stacks-signer/src/client/stackerdb.rs b/stacks-signer/src/client/stackerdb.rs index 4631ecbd4d..c6c1a6e366 100644 --- a/stacks-signer/src/client/stackerdb.rs +++ b/stacks-signer/src/client/stackerdb.rs @@ -33,19 +33,20 @@ use crate::config::Config; /// Temporary placeholder for the number of slots allocated to a stacker-db writer. This will be retrieved from the stacker-db instance in the future /// See: https://github.com/stacks-network/stacks-blockchain/issues/3921 /// Is equal to the number of message types -pub const SIGNER_SLOTS_PER_USER: u32 = 10; +pub const SIGNER_SLOTS_PER_USER: u32 = 11; // The slot IDS for each message type const DKG_BEGIN_SLOT_ID: u32 = 0; const DKG_PRIVATE_BEGIN_SLOT_ID: u32 = 1; -const DKG_END_SLOT_ID: u32 = 2; -const DKG_PUBLIC_SHARES_SLOT_ID: u32 = 3; -const DKG_PRIVATE_SHARES_SLOT_ID: u32 = 4; -const NONCE_REQUEST_SLOT_ID: u32 = 5; -const NONCE_RESPONSE_SLOT_ID: u32 = 6; -const SIGNATURE_SHARE_REQUEST_SLOT_ID: u32 = 7; -const SIGNATURE_SHARE_RESPONSE_SLOT_ID: u32 = 8; -const BLOCK_SLOT_ID: u32 = 9; +const DKG_END_BEGIN_SLOT_ID: u32 = 2; +const DKG_END_SLOT_ID: u32 = 3; +const DKG_PUBLIC_SHARES_SLOT_ID: u32 = 4; +const DKG_PRIVATE_SHARES_SLOT_ID: u32 = 5; +const NONCE_REQUEST_SLOT_ID: u32 = 6; +const NONCE_RESPONSE_SLOT_ID: u32 = 7; +const SIGNATURE_SHARE_REQUEST_SLOT_ID: u32 = 8; +const SIGNATURE_SHARE_RESPONSE_SLOT_ID: u32 = 9; +const BLOCK_SLOT_ID: u32 = 10; /// The messages being sent through the stacker db contracts #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -122,6 +123,7 @@ impl SignerMessage { Self::Packet(packet) => match packet.msg { Message::DkgBegin(_) => DKG_BEGIN_SLOT_ID, Message::DkgPrivateBegin(_) => DKG_PRIVATE_BEGIN_SLOT_ID, + Message::DkgEndBegin(_) => DKG_END_BEGIN_SLOT_ID, Message::DkgEnd(_) => DKG_END_SLOT_ID, Message::DkgPublicShares(_) => DKG_PUBLIC_SHARES_SLOT_ID, Message::DkgPrivateShares(_) => DKG_PRIVATE_SHARES_SLOT_ID, diff --git a/stacks-signer/src/config.rs b/stacks-signer/src/config.rs index 9261cc5a63..f83673e26c 100644 --- a/stacks-signer/src/config.rs +++ b/stacks-signer/src/config.rs @@ -36,7 +36,7 @@ use wsts::state_machine::PublicKeys; /// List of key_ids for each signer_id pub type SignerKeyIds = HashMap>; -const EVENT_TIMEOUT_MS: u64 = 5000; +const EVENT_TIMEOUT_MS: u64 = 50; #[derive(thiserror::Error, Debug)] /// An error occurred parsing the provided configuration @@ -119,6 +119,8 @@ pub struct Config { pub event_timeout: Duration, /// timeout to gather DkgPublicShares messages pub dkg_public_timeout: Option, + /// timeout to gather DkgPrivateShares messages + pub dkg_private_timeout: Option, /// timeout to gather DkgEnd messages pub dkg_end_timeout: Option, /// timeout to gather nonces @@ -159,7 +161,17 @@ struct RawConfigFile { /// The signer ID pub signer_id: u32, /// The time to wait (in millisecs) for a response from the stacker-db instance - pub event_timeout: Option, + pub event_timeout_ms: Option, + /// timeout in (millisecs) to gather DkgPublicShares messages + pub dkg_public_timeout_ms: Option, + /// timeout in (millisecs) to gather DkgPrivateShares messages + pub dkg_private_timeout_ms: Option, + /// timeout in (millisecs) to gather DkgEnd messages + pub dkg_end_timeout_ms: Option, + /// timeout in (millisecs) to gather nonces + pub nonce_timeout_ms: Option, + /// timeout in (millisecs) to gather signature shares + pub sign_timeout_ms: Option, } impl RawConfigFile { @@ -270,7 +282,12 @@ impl TryFrom for Config { signer_key_ids.insert(signer_key, s.key_ids.clone()); } let event_timeout = - Duration::from_millis(raw_data.event_timeout.unwrap_or(EVENT_TIMEOUT_MS)); + Duration::from_millis(raw_data.event_timeout_ms.unwrap_or(EVENT_TIMEOUT_MS)); + let dkg_end_timeout = raw_data.dkg_end_timeout_ms.map(Duration::from_millis); + let dkg_public_timeout = raw_data.dkg_public_timeout_ms.map(Duration::from_millis); + let dkg_private_timeout = raw_data.dkg_private_timeout_ms.map(Duration::from_millis); + let nonce_timeout = raw_data.nonce_timeout_ms.map(Duration::from_millis); + let sign_timeout = raw_data.sign_timeout_ms.map(Duration::from_millis); Ok(Self { node_host, endpoint, @@ -283,10 +300,11 @@ impl TryFrom for Config { signer_id: raw_data.signer_id, signer_key_ids, event_timeout, - dkg_end_timeout: None, - dkg_public_timeout: None, - nonce_timeout: None, - sign_timeout: None, + dkg_end_timeout, + dkg_public_timeout, + dkg_private_timeout, + nonce_timeout, + sign_timeout, }) } } diff --git a/stacks-signer/src/runloop.rs b/stacks-signer/src/runloop.rs index 5f68359a1c..f165546130 100644 --- a/stacks-signer/src/runloop.rs +++ b/stacks-signer/src/runloop.rs @@ -373,14 +373,12 @@ impl From<&Config> for RunLoop> { .signer_key_ids .get(&config.signer_id) .unwrap() - .iter() - .map(|i| i - 1) // Signer::new (unlike Signer::from) doesn't do this - .collect::>(); + .clone(); // signer uses a Vec for its key_ids, but coordinator uses a HashSet for each signer since it needs to do lots of lookups let signer_key_ids = config .signer_key_ids .iter() - .map(|(i, ids)| (*i, ids.iter().map(|id| id - 1).collect::>())) + .map(|(i, ids)| (*i, ids.iter().copied().collect::>())) .collect::>>(); let coordinator_config = CoordinatorConfig { @@ -390,6 +388,7 @@ impl From<&Config> for RunLoop> { num_keys: total_keys, message_private_key: config.message_private_key, dkg_public_timeout: config.dkg_public_timeout, + dkg_private_timeout: config.dkg_private_timeout, dkg_end_timeout: config.dkg_end_timeout, nonce_timeout: config.nonce_timeout, sign_timeout: config.sign_timeout, diff --git a/stackslib/Cargo.toml b/stackslib/Cargo.toml index c505d8429b..c5411353e2 100644 --- a/stackslib/Cargo.toml +++ b/stackslib/Cargo.toml @@ -57,6 +57,7 @@ libstackerdb = { path = "../libstackerdb" } siphasher = "0.3.7" wsts = {workspace = true} rand_core = {workspace = true} +hashbrown = "0.14" [target.'cfg(unix)'.dependencies] nix = "0.23" diff --git a/stackslib/src/chainstate/nakamoto/tests/node.rs b/stackslib/src/chainstate/nakamoto/tests/node.rs index 9c96ca1e6c..4f59a3851e 100644 --- a/stackslib/src/chainstate/nakamoto/tests/node.rs +++ b/stackslib/src/chainstate/nakamoto/tests/node.rs @@ -15,13 +15,14 @@ // along with this program. If not, see . use std::cell::RefCell; -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::{HashSet, VecDeque}; use std::path::{Path, PathBuf}; use std::{fs, io}; use clarity::vm::clarity::ClarityConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; use clarity::vm::types::*; +use hashbrown::HashMap; use rand::seq::SliceRandom; use rand::{thread_rng, Rng}; use stacks_common::address::*; @@ -70,7 +71,7 @@ pub struct TestSigners { /// The parties that will sign the blocks pub signer_parties: Vec, /// The commitments to the polynomials for the aggregate public key - pub poly_commitments: Vec, + pub poly_commitments: HashMap, /// The aggregate public key pub aggregate_public_key: Point, /// The total number of key ids distributed among signer_parties @@ -85,7 +86,7 @@ impl Default for TestSigners { let num_keys = 10; let threshold = 7; let party_key_ids: Vec> = - vec![vec![0, 1, 2], vec![3, 4], vec![5, 6, 7], vec![8, 9]]; + vec![vec![1, 2, 3], vec![4, 5], vec![6, 7, 8], vec![9, 10]]; let num_parties = party_key_ids.len().try_into().unwrap(); // Create the parties @@ -111,10 +112,11 @@ impl Default for TestSigners { panic!("Got secret errors from DKG: {:?}", secret_errors); } }; - let aggregate_public_key = poly_commitments.iter().fold( - Point::default(), - |s, poly_commitment: &wsts::common::PolyCommitment| s + poly_commitment.poly[0], - ); + let mut sig_aggregator = wsts::v2::Aggregator::new(num_keys, threshold); + sig_aggregator + .init(&poly_commitments) + .expect("aggregator init failed"); + let aggregate_public_key = sig_aggregator.poly[0]; Self { signer_parties, aggregate_public_key, @@ -138,7 +140,7 @@ impl TestSigners { let mut sig_aggregator = wsts::v2::Aggregator::new(self.num_keys, self.threshold); sig_aggregator - .init(self.poly_commitments.clone()) + .init(&self.poly_commitments) .expect("aggregator init failed"); let signature = sig_aggregator .sign(msg.as_slice(), &nonces, &sig_shares, &key_ids) diff --git a/testnet/stacks-node/Cargo.toml b/testnet/stacks-node/Cargo.toml index 45e0ce231b..1647766d29 100644 --- a/testnet/stacks-node/Cargo.toml +++ b/testnet/stacks-node/Cargo.toml @@ -30,6 +30,7 @@ libsigner = { path = "../../libsigner" } wsts = { workspace = true } rand = { workspace = true } rand_core = { workspace = true } +hashbrown = "0.14" [dev-dependencies] ring = "0.16.19" diff --git a/testnet/stacks-node/src/mockamoto/signer.rs b/testnet/stacks-node/src/mockamoto/signer.rs index 7e577b24f2..fadc98f570 100644 --- a/testnet/stacks-node/src/mockamoto/signer.rs +++ b/testnet/stacks-node/src/mockamoto/signer.rs @@ -1,3 +1,4 @@ +use hashbrown::HashMap; use rand::{CryptoRng, RngCore, SeedableRng}; use stacks::chainstate::nakamoto::NakamotoBlock; use stacks::chainstate::stacks::ThresholdSignature; @@ -13,7 +14,7 @@ pub struct SelfSigner { /// The parties that will sign the blocks pub signer_parties: Vec, /// The commitments to the polynomials for the aggregate public key - pub poly_commitments: Vec, + pub poly_commitments: HashMap, /// The aggregate public key pub aggregate_public_key: Point, /// The total number of key ids distributed among signer_parties @@ -35,7 +36,7 @@ impl SelfSigner { fn from_rng(mut rng: RNG) -> Self { // Create the parties - let mut signer_parties = [wsts::v2::Party::new(0, &[0], 1, 1, 1, &mut rng)]; + let mut signer_parties = [wsts::v2::Party::new(0, &[1], 1, 1, 1, &mut rng)]; // Generate an aggregate public key let poly_commitments = match wsts::v2::test_helpers::dkg(&mut signer_parties, &mut rng) { @@ -48,11 +49,12 @@ impl SelfSigner { assert_eq!(poly_commitments.len(), 1); assert_eq!(signer_parties.len(), 1); - let aggregate_public_key = poly_commitments.iter().fold( - Point::default(), - |s, poly_commitment: &wsts::common::PolyCommitment| s + poly_commitment.poly[0], - ); + let mut sig_aggregator = wsts::v2::Aggregator::new(1, 1); + sig_aggregator + .init(&poly_commitments) + .expect("aggregator init failed"); + let aggregate_public_key = sig_aggregator.poly[0]; Self { signer_parties: signer_parties.to_vec(), aggregate_public_key, @@ -74,7 +76,7 @@ impl SelfSigner { let mut sig_aggregator = wsts::v2::Aggregator::new(self.num_keys, self.threshold); sig_aggregator - .init(self.poly_commitments.clone()) + .init(&self.poly_commitments) .expect("aggregator init failed"); let signature = sig_aggregator .sign(msg.as_slice(), &nonces, &sig_shares, &key_ids)