From 9de0a79e6a78450f9c9836fad019e147384c1d4a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 07:32:15 +0000 Subject: [PATCH 01/17] Bump async-trait from 0.1.82 to 0.1.83 in the patch-dependencies group (#1067) Bumps the patch-dependencies group with 1 update: [async-trait](https://github.com/dtolnay/async-trait). Updates `async-trait` from 0.1.82 to 0.1.83 - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](https://github.com/dtolnay/async-trait/compare/0.1.82...0.1.83) --- updated-dependencies: - dependency-name: async-trait dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- crates/protocol/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e4f24f61..29006b9d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -594,9 +594,9 @@ checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", diff --git a/crates/protocol/Cargo.toml b/crates/protocol/Cargo.toml index 934a4ee93..0b9adbcc0 100644 --- a/crates/protocol/Cargo.toml +++ b/crates/protocol/Cargo.toml @@ -9,7 +9,7 @@ repository ='https://github.com/entropyxyz/entropy-core' edition ='2021' [dependencies] -async-trait ="0.1.82" +async-trait ="0.1.83" entropy-shared ={ version="0.2.0", path="../shared", default-features=false } synedrion ={ git="https://github.com/entropyxyz/synedrion", rev="1d210d149dfeb0dca1dd41d7fac4d0bf03c686fa" } serde ={ version="1.0", features=["derive"], default-features=false } From f286071948a1c1f4de398bd44840e11ee36cc740 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 25 Sep 2024 10:51:15 +0200 Subject: [PATCH 02/17] Handle Provisioning Certification Keys (PCKs) (#1051) * Add PCK to server info * Add PCK to chainspec * Update chainspec genesis config to include PCKs for all TSSs * Add sp-runtime to wasm deps of entropy-shared * Bump tdx-quote, check PCK signature when verifying quotes * Update benchmarks * When mocking, derive PCK from TSS account id * Get boundedvec from sp-core, not sp-runtime * Ignore BoundedVec type when compiling for wasm with std * Update propagation pallet mock * Update attestation pallet mock * Add helpers for deriving mock pcks * Add actual PCK values to chainspec * Rm unused import * Update registry tests * Update metadata * Comments * Fix client test * Add random secret PCK to attestation pallet benchmark test * Fix attestation benchmark * Fix attestation benchmark again * Update attestation pallet test * Fix attestation pallet mock/bench * Fix entropy-client test * Fix client test * Fix client test * Changelog * Rm unused dependency from staking pallet --- CHANGELOG.md | 1 + Cargo.lock | 4 +- crates/client/entropy_metadata.scale | Bin 208617 -> 208772 bytes crates/client/src/tests.rs | 16 +++- crates/shared/src/types.rs | 4 + crates/testing-utils/Cargo.toml | 1 + crates/testing-utils/src/helpers.rs | 19 +++- crates/threshold-signature-server/Cargo.toml | 5 +- .../src/attestation/api.rs | 9 +- node/cli/src/chain_spec/dev.rs | 33 +++++-- node/cli/src/chain_spec/integration_tests.rs | 6 +- node/cli/src/chain_spec/mod.rs | 29 ++++++ node/cli/src/chain_spec/testnet.rs | 29 ++++-- pallets/attestation/Cargo.toml | 4 +- pallets/attestation/src/benchmarking.rs | 19 +++- pallets/attestation/src/lib.rs | 34 ++++--- pallets/attestation/src/mock.rs | 13 ++- pallets/attestation/src/tests.rs | 7 +- pallets/propagation/src/mock.rs | 12 +-- pallets/registry/src/benchmarking.rs | 8 +- pallets/registry/src/mock.rs | 12 +-- pallets/registry/src/tests.rs | 24 +++-- pallets/staking/src/benchmarking.rs | 11 ++- pallets/staking/src/lib.rs | 4 +- pallets/staking/src/mock.rs | 7 +- pallets/staking/src/tests.rs | 88 ++++++++++++++---- 26 files changed, 304 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8148a6b6..22baf545b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ At the moment this project **does not** adhere to - Add remove program function to entropy-client ([#1023](https://github.com/entropyxyz/entropy-core/pull/1023)) - Select validators for jumpstart DKG [#1053](https://github.com/entropyxyz/entropy-core/pull/1053)) - Add a programs version ([#1045](https://github.com/entropyxyz/entropy-core/pull/1045)) +- Handle Provisioning Certification Keys (PCKs) ([#1051](https://github.com/entropyxyz/entropy-core/pull/1051)) ### Changed - Fix TSS `AccountId` keys in chainspec ([#993](https://github.com/entropyxyz/entropy-core/pull/993)) diff --git a/Cargo.lock b/Cargo.lock index 29006b9d5..47bbaeff3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2751,6 +2751,7 @@ dependencies = [ "sp-keyring 34.0.0", "subxt", "synedrion", + "tdx-quote", "tokio", "tracing", "tracing-subscriber 0.3.18", @@ -2789,6 +2790,7 @@ dependencies = [ "num", "parity-scale-codec", "project-root", + "rand", "rand_core 0.6.4", "reqwest", "reqwest-eventsource", @@ -14138,7 +14140,7 @@ checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "tdx-quote" version = "0.1.0" -source = "git+https://github.com/entropyxyz/tdx-quote?rev=f7968ff#f7968ff35ff744ff8c007cffe6ec8d709d7f18d9" +source = "git+https://github.com/entropyxyz/tdx-quote?rev=cb167f2#cb167f2aef1c7539c91082ee21c764eac60f6bef" dependencies = [ "nom", "p256", diff --git a/crates/client/entropy_metadata.scale b/crates/client/entropy_metadata.scale index adb357cc3bf70dcb346378a9c6eacde1e3df61f1..3c2856de606a1c8b1dd9303eb79fa3fcaf95cc33 100644 GIT binary patch delta 3101 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 diff --git a/crates/client/src/tests.rs b/crates/client/src/tests.rs index 0315cdb5e..13ab41d8d 100644 --- a/crates/client/src/tests.rs +++ b/crates/client/src/tests.rs @@ -16,8 +16,11 @@ use crate::{ update_programs, }; use entropy_testing_utils::{ - constants::TEST_PROGRAM_WASM_BYTECODE, jump_start_network, - substrate_context::test_context_stationary, test_node_process_testing_state, + constants::{TEST_PROGRAM_WASM_BYTECODE, TSS_ACCOUNTS}, + helpers::{derive_mock_pck_verifying_key, encode_verifying_key}, + jump_start_network, + substrate_context::test_context_stationary, + test_node_process_testing_state, }; use serial_test::serial; use sp_core::{sr25519, Pair, H256}; @@ -64,6 +67,12 @@ async fn test_change_threshold_accounts() { ) .await .unwrap(); + + let provisioning_certification_key = { + let key = derive_mock_pck_verifying_key(&TSS_ACCOUNTS[0]); + BoundedVec(encode_verifying_key(&key).unwrap().to_vec()) + }; + assert_eq!( format!("{:?}", result), format!( @@ -73,7 +82,8 @@ async fn test_change_threshold_accounts() { ServerInfo { tss_account: AccountId32(one.pair().public().0), x25519_public_key, - endpoint: "127.0.0.1:3001".as_bytes().to_vec() + endpoint: "127.0.0.1:3001".as_bytes().to_vec(), + provisioning_certification_key, } ) ) diff --git a/crates/shared/src/types.rs b/crates/shared/src/types.rs index 48a5ab089..0cf844dd3 100644 --- a/crates/shared/src/types.rs +++ b/crates/shared/src/types.rs @@ -109,6 +109,10 @@ pub enum HashingAlgorithm { /// A compressed, serialized [synedrion::ecdsa::VerifyingKey] pub type EncodedVerifyingKey = [u8; VERIFICATION_KEY_LENGTH as usize]; +#[cfg(not(feature = "wasm"))] +pub type BoundedVecEncodedVerifyingKey = + sp_runtime::BoundedVec>; + /// Input data to be included in a TDX attestation pub struct QuoteInputData(pub [u8; 64]); diff --git a/crates/testing-utils/Cargo.toml b/crates/testing-utils/Cargo.toml index c1c955751..9cf8ae52d 100644 --- a/crates/testing-utils/Cargo.toml +++ b/crates/testing-utils/Cargo.toml @@ -26,6 +26,7 @@ synedrion ={ git="https://github.com/entropyxyz/synedrion", rev="1d210d1 hex ="0.4.3" rand_core ="0.6.4" rand ="0.8.5" +tdx-quote ={ git="https://github.com/entropyxyz/tdx-quote", rev="cb167f2", features=["mock"] } # Logging tracing ="0.1.37" diff --git a/crates/testing-utils/src/helpers.rs b/crates/testing-utils/src/helpers.rs index 60194a153..5e64f843e 100644 --- a/crates/testing-utils/src/helpers.rs +++ b/crates/testing-utils/src/helpers.rs @@ -20,7 +20,9 @@ use crate::{ ChainSpecType, }; use entropy_protocol::PartyId; -use subxt::{backend::legacy::LegacyRpcMethods, OnlineClient}; +use rand::{rngs::StdRng, SeedableRng}; +use subxt::{backend::legacy::LegacyRpcMethods, utils::AccountId32, OnlineClient}; +pub use tdx_quote::encode_verifying_key; /// A helper for setting up tests which starts both a set of TS servers and a chain node and returns /// the chain API as well as IP addresses and PartyId of the started validators @@ -52,3 +54,18 @@ pub async fn spawn_tss_nodes_and_start_chain( }; (api, rpc, validator_ips, validator_ids) } + +/// Get the mock PCK that will be used for a given TSS account ID +pub fn derive_mock_pck_verifying_key(tss_account_id: &AccountId32) -> tdx_quote::VerifyingKey { + let mut pck_seeder = StdRng::from_seed(tss_account_id.0); + let pck = tdx_quote::SigningKey::random(&mut pck_seeder); + tdx_quote::VerifyingKey::from(pck) +} + +/// For each test TSS account, display the encoded mock PCK +pub fn print_test_pck_verifying_keys() { + for tss_account in crate::constants::TSS_ACCOUNTS.iter() { + let pck = derive_mock_pck_verifying_key(tss_account); + println!("{:?}", encode_verifying_key(&pck)); + } +} diff --git a/crates/threshold-signature-server/Cargo.toml b/crates/threshold-signature-server/Cargo.toml index 95cf52549..e8f20d734 100644 --- a/crates/threshold-signature-server/Cargo.toml +++ b/crates/threshold-signature-server/Cargo.toml @@ -17,6 +17,7 @@ thiserror ="1.0.64" blake2 ="0.10.4" x25519-dalek ={ version="2.0.1", features=["static_secrets"] } rand_core ="0.6.4" +rand ="0.8.5" zeroize ="1.8.1" hex ="0.4.3" reqwest-eventsource="0.6" @@ -71,7 +72,7 @@ sha1="0.10.6" sha2="0.10.8" hkdf="0.12.4" project-root={ version="0.2.2", optional=true } -tdx-quote={ git="https://github.com/entropyxyz/tdx-quote", rev="f7968ff", optional=true, features=[ +tdx-quote={ git="https://github.com/entropyxyz/tdx-quote", rev="cb167f2", optional=true, features=[ "mock", ] } configfs-tsm={ git="https://github.com/entropyxyz/configfs-tsm", rev="f32c166", optional=true } @@ -88,7 +89,7 @@ ethers-core ="2.0.14" schnorrkel ={ version="0.11.4", default-features=false, features=["std"] } schemars ={ version="0.8.21" } subxt-signer="0.35.3" -tdx-quote ={ git="https://github.com/entropyxyz/tdx-quote", rev="f7968ff", features=["mock"] } +tdx-quote ={ git="https://github.com/entropyxyz/tdx-quote", rev="cb167f2", features=["mock"] } # Note: We don't specify versions here because otherwise we run into a cyclical dependency between # `entropy-tss` and `entropy-testing-utils` when we try and publish the `entropy-tss` crate. diff --git a/crates/threshold-signature-server/src/attestation/api.rs b/crates/threshold-signature-server/src/attestation/api.rs index 918d3c7e1..8615e4e6a 100644 --- a/crates/threshold-signature-server/src/attestation/api.rs +++ b/crates/threshold-signature-server/src/attestation/api.rs @@ -78,10 +78,11 @@ pub async fn create_quote( signer: &PairSigner, x25519_secret: &StaticSecret, ) -> Result, AttestationErr> { + use rand::{rngs::StdRng, SeedableRng}; use rand_core::OsRng; use sp_core::Pair; - // In the real thing this is the hardware key used in the quoting enclave + // In the real thing this is the key used in the quoting enclave let signing_key = tdx_quote::SigningKey::random(&mut OsRng); let public_key = x25519_dalek::PublicKey::from(x25519_secret); @@ -93,7 +94,11 @@ pub async fn create_quote( block_number, ); - let quote = tdx_quote::Quote::mock(signing_key.clone(), input_data.0).as_bytes().to_vec(); + // This is generated deterministically from TSS account id + let mut pck_seeder = StdRng::from_seed(signer.signer().public().0); + let pck = tdx_quote::SigningKey::random(&mut pck_seeder); + + let quote = tdx_quote::Quote::mock(signing_key.clone(), pck, input_data.0).as_bytes().to_vec(); Ok(quote) } diff --git a/node/cli/src/chain_spec/dev.rs b/node/cli/src/chain_spec/dev.rs index 5f33a1b44..6e6aaa186 100644 --- a/node/cli/src/chain_spec/dev.rs +++ b/node/cli/src/chain_spec/dev.rs @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::chain_spec::{get_account_id_from_seed, ChainSpec}; +use crate::chain_spec::{get_account_id_from_seed, provisioning_certification_key, ChainSpec}; use crate::endowed_accounts::endowed_accounts_dev; use entropy_runtime::{ @@ -24,9 +24,9 @@ use entropy_runtime::{ }; use entropy_runtime::{AccountId, Balance}; use entropy_shared::{ - X25519PublicKey as TssX25519PublicKey, DEVICE_KEY_AUX_DATA_TYPE, DEVICE_KEY_CONFIG_TYPE, - DEVICE_KEY_HASH, DEVICE_KEY_PROXY, INITIAL_MAX_INSTRUCTIONS_PER_PROGRAM, SIGNER_THRESHOLD, - TOTAL_SIGNERS, + BoundedVecEncodedVerifyingKey, X25519PublicKey as TssX25519PublicKey, DEVICE_KEY_AUX_DATA_TYPE, + DEVICE_KEY_CONFIG_TYPE, DEVICE_KEY_HASH, DEVICE_KEY_PROXY, + INITIAL_MAX_INSTRUCTIONS_PER_PROGRAM, SIGNER_THRESHOLD, TOTAL_SIGNERS, }; use grandpa_primitives::AuthorityId as GrandpaId; use itertools::Itertools; @@ -38,75 +38,85 @@ use sp_core::{sr25519, ByteArray}; use sp_runtime::{BoundedVec, Perbill}; pub fn devnet_three_node_initial_tss_servers( -) -> Vec<(sp_runtime::AccountId32, TssX25519PublicKey, String)> { +) -> Vec<(sp_runtime::AccountId32, TssX25519PublicKey, String, BoundedVecEncodedVerifyingKey)> { let alice = ( crate::chain_spec::tss_account_id::ALICE.clone(), crate::chain_spec::tss_x25519_public_key::ALICE, "127.0.0.1:3001".to_string(), + provisioning_certification_key::ALICE.clone(), ); let bob = ( crate::chain_spec::tss_account_id::BOB.clone(), crate::chain_spec::tss_x25519_public_key::BOB, "127.0.0.1:3002".to_string(), + provisioning_certification_key::BOB.clone(), ); let charlie = ( crate::chain_spec::tss_account_id::CHARLIE.clone(), crate::chain_spec::tss_x25519_public_key::CHARLIE, "127.0.0.1:3003".to_string(), + provisioning_certification_key::CHARLIE.clone(), ); vec![alice, bob, charlie] } pub fn devnet_local_docker_three_node_initial_tss_servers( -) -> Vec<(sp_runtime::AccountId32, TssX25519PublicKey, String)> { +) -> Vec<(sp_runtime::AccountId32, TssX25519PublicKey, String, BoundedVecEncodedVerifyingKey)> { let alice = ( crate::chain_spec::tss_account_id::ALICE.clone(), crate::chain_spec::tss_x25519_public_key::ALICE, "alice-tss-server:3001".to_string(), + provisioning_certification_key::ALICE.clone(), ); let bob = ( crate::chain_spec::tss_account_id::BOB.clone(), crate::chain_spec::tss_x25519_public_key::BOB, "bob-tss-server:3002".to_string(), + provisioning_certification_key::BOB.clone(), ); let charlie = ( crate::chain_spec::tss_account_id::CHARLIE.clone(), crate::chain_spec::tss_x25519_public_key::CHARLIE, "charlie-tss-server:3003".to_string(), + provisioning_certification_key::CHARLIE.clone(), ); vec![alice, bob, charlie] } pub fn devnet_local_docker_four_node_initial_tss_servers( -) -> Vec<(sp_runtime::AccountId32, TssX25519PublicKey, String)> { +) -> Vec<(sp_runtime::AccountId32, TssX25519PublicKey, String, BoundedVecEncodedVerifyingKey)> { let alice = ( crate::chain_spec::tss_account_id::ALICE.clone(), crate::chain_spec::tss_x25519_public_key::ALICE, "alice-tss-server:3001".to_string(), + provisioning_certification_key::ALICE.clone(), ); let bob = ( crate::chain_spec::tss_account_id::BOB.clone(), crate::chain_spec::tss_x25519_public_key::BOB, "bob-tss-server:3002".to_string(), + provisioning_certification_key::BOB.clone(), ); let dave = ( crate::chain_spec::tss_account_id::DAVE.clone(), crate::chain_spec::tss_x25519_public_key::DAVE, "dave-tss-server:3003".to_string(), + provisioning_certification_key::DAVE.clone(), ); let eve = ( crate::chain_spec::tss_account_id::EVE.clone(), crate::chain_spec::tss_x25519_public_key::EVE_TSS, "eve-tss-server:3004".to_string(), + provisioning_certification_key::EVE.clone(), ); vec![alice, bob, dave, eve] @@ -194,7 +204,12 @@ pub fn development_genesis_config( )>, initial_nominators: Vec, root_key: AccountId, - initial_tss_servers: Vec<(sp_runtime::AccountId32, TssX25519PublicKey, String)>, + initial_tss_servers: Vec<( + sp_runtime::AccountId32, + TssX25519PublicKey, + String, + BoundedVecEncodedVerifyingKey, + )>, ) -> serde_json::Value { // Note that any endowed_accounts added here will be included in the `elections` and // `technical_committee` genesis configs. If you don't want that, don't push those accounts to @@ -272,7 +287,7 @@ pub fn development_genesis_config( .iter() .zip(initial_tss_servers.iter()) .map(|(auth, tss)| { - (auth.0.clone(), (tss.0.clone(), tss.1, tss.2.as_bytes().to_vec())) + (auth.0.clone(), (tss.0.clone(), tss.1, tss.2.as_bytes().to_vec(), tss.3.clone())) }) .collect::>(), proactive_refresh_data: (vec![], vec![]), diff --git a/node/cli/src/chain_spec/integration_tests.rs b/node/cli/src/chain_spec/integration_tests.rs index b45dfe5de..5d7fc54ed 100644 --- a/node/cli/src/chain_spec/integration_tests.rs +++ b/node/cli/src/chain_spec/integration_tests.rs @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::chain_spec::{get_account_id_from_seed, ChainSpec}; +use crate::chain_spec::{get_account_id_from_seed, provisioning_certification_key, ChainSpec}; use crate::endowed_accounts::endowed_accounts_dev; use entropy_runtime::{ @@ -158,6 +158,7 @@ pub fn integration_tests_genesis_config( crate::chain_spec::tss_account_id::ALICE.clone(), crate::chain_spec::tss_x25519_public_key::ALICE, "127.0.0.1:3001".as_bytes().to_vec(), + provisioning_certification_key::ALICE.clone(), ), ), ( @@ -166,6 +167,7 @@ pub fn integration_tests_genesis_config( crate::chain_spec::tss_account_id::BOB.clone(), crate::chain_spec::tss_x25519_public_key::BOB, "127.0.0.1:3002".as_bytes().to_vec(), + provisioning_certification_key::BOB.clone(), ), ), ( @@ -174,6 +176,7 @@ pub fn integration_tests_genesis_config( crate::chain_spec::tss_account_id::CHARLIE.clone(), crate::chain_spec::tss_x25519_public_key::CHARLIE, "127.0.0.1:3003".as_bytes().to_vec(), + provisioning_certification_key::CHARLIE.clone(), ), ), ( @@ -182,6 +185,7 @@ pub fn integration_tests_genesis_config( crate::chain_spec::tss_account_id::DAVE.clone(), crate::chain_spec::tss_x25519_public_key::DAVE, "127.0.0.1:3004".as_bytes().to_vec(), + provisioning_certification_key::DAVE.clone(), ), ), ], diff --git a/node/cli/src/chain_spec/mod.rs b/node/cli/src/chain_spec/mod.rs index 79485d720..ed9f3c9cd 100644 --- a/node/cli/src/chain_spec/mod.rs +++ b/node/cli/src/chain_spec/mod.rs @@ -126,6 +126,35 @@ pub mod tss_x25519_public_key { ]; } +/// Mock provisioning certification keys for attestation of the test TS servers. +/// These are generated deterministically from their TSS account IDs using the helper function +/// entropy_testing_utils::helpers::print_test_pck_verifying_keys +pub mod provisioning_certification_key { + use entropy_shared::BoundedVecEncodedVerifyingKey; + + lazy_static::lazy_static! { + pub static ref ALICE: BoundedVecEncodedVerifyingKey = vec![ + 2, 137, 55, 65, 52, 103, 166, 204, 247, 160, 46, 220, 5, 113, 151, 217, 157, 196, 11, + 240, 175, 82, 148, 230, 31, 245, 207, 194, 3, 74, 121, 184, 20 + ].try_into().unwrap(); + pub static ref BOB: BoundedVecEncodedVerifyingKey = vec![ + 3, 83, 163, 234, 166, 114, 67, 146, 122, 122, 99, 236, 205, 116, 209, 45, 230, 107, 62, + 55, 147, 38, 185, 203, 157, 147, 156, 173, 233, 58, 134, 162, 156].try_into().unwrap(); + pub static ref CHARLIE: BoundedVecEncodedVerifyingKey = vec![ + 2, 167, 50, 42, 76, 239, 190, 42, 72, 64, 110, 90, 172, 253, 252, 148, 115, 107, 34, 110, + 2, 112, 184, 147, 87, 71, 63, 217, 238, 89, 253, 97, 176 + ].try_into().unwrap(); + pub static ref DAVE: BoundedVecEncodedVerifyingKey = vec![ + 3, 68, 52, 130, 44, 84, 174, 32, 55, 213, 192, 7, 121, 188, 19, 231, 134, 47, 223, 166, + 199, 118, 161, 203, 142, 75, 184, 108, 165, 70, 251, 249, 142 + ].try_into().unwrap(); + pub static ref EVE: BoundedVecEncodedVerifyingKey = vec![ + 2, 60, 115, 185, 180, 118, 177, 23, 3, 49, 65, 92, 230, 60, 245, 1, 140, 149, 117, 238, + 83, 69, 110, 30, 140, 31, 60, 69, 38, 34, 202, 242, 125 + ].try_into().unwrap(); + } +} + fn entropy_properties() -> Properties { json!({"tokenDecimals": 10, "tokenSymbol": "BITS" }).as_object().unwrap().clone() } diff --git a/node/cli/src/chain_spec/testnet.rs b/node/cli/src/chain_spec/testnet.rs index fb5848420..9dd3c1f5f 100644 --- a/node/cli/src/chain_spec/testnet.rs +++ b/node/cli/src/chain_spec/testnet.rs @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::chain_spec::{get_account_id_from_seed, ChainSpec}; +use crate::chain_spec::{get_account_id_from_seed, provisioning_certification_key, ChainSpec}; use crate::endowed_accounts::endowed_testnet_accounts; use entropy_runtime::{ @@ -24,9 +24,9 @@ use entropy_runtime::{ }; use entropy_runtime::{AccountId, Balance}; use entropy_shared::{ - X25519PublicKey as TssX25519PublicKey, DEVICE_KEY_AUX_DATA_TYPE, DEVICE_KEY_CONFIG_TYPE, - DEVICE_KEY_HASH, DEVICE_KEY_PROXY, INITIAL_MAX_INSTRUCTIONS_PER_PROGRAM, SIGNER_THRESHOLD, - TOTAL_SIGNERS, + BoundedVecEncodedVerifyingKey, X25519PublicKey as TssX25519PublicKey, DEVICE_KEY_AUX_DATA_TYPE, + DEVICE_KEY_CONFIG_TYPE, DEVICE_KEY_HASH, DEVICE_KEY_PROXY, + INITIAL_MAX_INSTRUCTIONS_PER_PROGRAM, SIGNER_THRESHOLD, TOTAL_SIGNERS, }; use grandpa_primitives::AuthorityId as GrandpaId; use hex_literal::hex; @@ -177,17 +177,20 @@ pub fn testnet_local_config() -> crate::chain_spec::ChainSpec { .build() } -pub fn testnet_local_initial_tss_servers() -> Vec<(TssAccountId, TssX25519PublicKey, TssEndpoint)> { +pub fn testnet_local_initial_tss_servers( +) -> Vec<(TssAccountId, TssX25519PublicKey, TssEndpoint, BoundedVecEncodedVerifyingKey)> { let alice = ( crate::chain_spec::tss_account_id::ALICE.clone(), crate::chain_spec::tss_x25519_public_key::ALICE, "alice-tss-server:3001".to_string(), + provisioning_certification_key::ALICE.clone(), ); let bob = ( crate::chain_spec::tss_account_id::BOB.clone(), crate::chain_spec::tss_x25519_public_key::BOB, "bob-tss-server:3002".to_string(), + provisioning_certification_key::BOB.clone(), ); vec![alice, bob] @@ -207,7 +210,8 @@ pub fn testnet_local_initial_tss_servers() -> Vec<(TssAccountId, TssX25519Public /// /// Note that if the KVDB of the TSS is deleted at any point during this process you will end up /// with different `AccountID`s and `PublicKey`s. -pub fn testnet_initial_tss_servers() -> Vec<(TssAccountId, TssX25519PublicKey, TssEndpoint)> { +pub fn testnet_initial_tss_servers( +) -> Vec<(TssAccountId, TssX25519PublicKey, TssEndpoint, BoundedVecEncodedVerifyingKey)> { use std::str::FromStr; let node_1a = ( @@ -218,6 +222,7 @@ pub fn testnet_initial_tss_servers() -> Vec<(TssAccountId, TssX25519PublicKey, T 198, 84, 61, 178, 36, 191, 56, 41, 39, 173, 70, 9, 67, ], "100.26.207.49:3001".to_string(), + provisioning_certification_key::ALICE.clone(), ); let node_1b = ( @@ -228,6 +233,7 @@ pub fn testnet_initial_tss_servers() -> Vec<(TssAccountId, TssX25519PublicKey, T 10, 107, 31, 67, 10, 98, 215, 34, 26, 10, 188, 59, 71, 100, ], "34.200.237.166:3001".to_string(), + provisioning_certification_key::BOB.clone(), ); let node_1c = ( @@ -238,6 +244,7 @@ pub fn testnet_initial_tss_servers() -> Vec<(TssAccountId, TssX25519PublicKey, T 36, 157, 25, 170, 72, 247, 152, 130, 139, 244, 4, 67, 162, 0, ], "184.72.189.154:3001".to_string(), + provisioning_certification_key::CHARLIE.clone(), ); let node_2a = ( @@ -248,6 +255,7 @@ pub fn testnet_initial_tss_servers() -> Vec<(TssAccountId, TssX25519PublicKey, T 196, 3, 154, 37, 23, 133, 28, 168, 221, 37, 204, 186, 61, ], "184.73.19.95:3001".to_string(), + provisioning_certification_key::DAVE.clone(), ); vec![node_1a, node_1b, node_1c, node_2a] @@ -293,7 +301,12 @@ pub fn testnet_genesis_config( )>, initial_nominators: Vec, root_key: AccountId, - initial_tss_servers: Vec<(TssAccountId, TssX25519PublicKey, TssEndpoint)>, + initial_tss_servers: Vec<( + TssAccountId, + TssX25519PublicKey, + TssEndpoint, + BoundedVecEncodedVerifyingKey, + )>, ) -> serde_json::Value { assert!( initial_authorities.len() == initial_tss_servers.len(), @@ -410,7 +423,7 @@ pub fn testnet_genesis_config( .iter() .zip(initial_tss_servers.iter()) .map(|(auth, tss)| { - (auth.0.clone(), (tss.0.clone(), tss.1, tss.2.as_bytes().to_vec())) + (auth.0.clone(), (tss.0.clone(), tss.1, tss.2.as_bytes().to_vec(), tss.3.clone())) }) .collect::>(), proactive_refresh_data: (vec![], vec![]), diff --git a/pallets/attestation/Cargo.toml b/pallets/attestation/Cargo.toml index 44d63ae1c..ded3b1a93 100644 --- a/pallets/attestation/Cargo.toml +++ b/pallets/attestation/Cargo.toml @@ -27,7 +27,7 @@ entropy-shared={ version="0.2.0", path="../../crates/shared", features=[ "wasm-no-std", ], default-features=false } pallet-staking-extension={ version="0.2.0", path="../staking", default-features=false } -tdx-quote={ git="https://github.com/entropyxyz/tdx-quote", rev="f7968ff" } +tdx-quote={ git="https://github.com/entropyxyz/tdx-quote", rev="cb167f2" } [dev-dependencies] pallet-session ={ version="29.0.0", default-features=false } @@ -38,7 +38,7 @@ pallet-timestamp ={ version="28.0.0", default-features=false } sp-npos-elections ={ version="27.0.0", default-features=false } frame-election-provider-support={ version="29.0.0", default-features=false } pallet-staking-reward-curve ={ version="11.0.0" } -tdx-quote ={ git="https://github.com/entropyxyz/tdx-quote", rev="f7968ff", features=["mock"] } +tdx-quote ={ git="https://github.com/entropyxyz/tdx-quote", rev="cb167f2", features=["mock"] } rand_core ="0.6.4" [features] diff --git a/pallets/attestation/src/benchmarking.rs b/pallets/attestation/src/benchmarking.rs index f3c88604f..16b4de2ad 100644 --- a/pallets/attestation/src/benchmarking.rs +++ b/pallets/attestation/src/benchmarking.rs @@ -15,6 +15,7 @@ use entropy_shared::QuoteInputData; use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; +use frame_support::BoundedVec; use frame_system::{EventRecord, RawOrigin}; use pallet_staking_extension::{ServerInfo, ThresholdServers, ThresholdToStash}; @@ -22,12 +23,19 @@ use super::*; #[allow(unused)] use crate::Pallet as AttestationPallet; -// This is a randomly generated secret p256 ECDSA key -const ENCLAVE_SIGNING_KEY: [u8; 32] = [ +/// This is a randomly generated secret p256 ECDSA key - for mocking attestation +const ATTESTATION_KEY: [u8; 32] = [ 167, 184, 203, 130, 240, 249, 191, 129, 206, 9, 200, 29, 99, 197, 64, 81, 135, 166, 59, 73, 31, 27, 206, 207, 69, 248, 56, 195, 64, 92, 109, 46, ]; +/// This is a randomly generated secret p256 ECDSA key - for mocking the provisioning certification +/// key +const PCK: [u8; 32] = [ + 117, 153, 212, 7, 220, 16, 181, 32, 110, 138, 4, 68, 208, 37, 104, 54, 1, 110, 232, 207, 100, + 168, 16, 99, 66, 83, 21, 178, 81, 155, 132, 37, +]; + fn assert_last_event(generic_event: ::RuntimeEvent) { let events = frame_system::Pallet::::events(); let system_event: ::RuntimeEvent = generic_event.into(); @@ -41,7 +49,9 @@ benchmarks! { let attestee: T::AccountId = whitelisted_caller(); let nonce = [0; 32]; - let signing_key = tdx_quote::SigningKey::from_bytes(&ENCLAVE_SIGNING_KEY.into()).unwrap(); + let attestation_key = tdx_quote::SigningKey::from_bytes(&ATTESTATION_KEY.into()).unwrap(); + let pck = tdx_quote::SigningKey::from_bytes(&PCK.into()).unwrap(); + let pck_encoded = tdx_quote::encode_verifying_key(pck.verifying_key()).unwrap(); let input_data = QuoteInputData::new( &attestee, // TSS Account ID @@ -49,7 +59,7 @@ benchmarks! { nonce, 1, // Block number ); - let quote = tdx_quote::Quote::mock(signing_key.clone(), input_data.0).as_bytes().to_vec(); + let quote = tdx_quote::Quote::mock(attestation_key.clone(), pck, input_data.0).as_bytes().to_vec(); // Insert a pending attestation so that this quote is expected >::insert(attestee.clone(), nonce); @@ -63,6 +73,7 @@ benchmarks! { tss_account: attestee.clone(), x25519_public_key: [0; 32], endpoint: b"http://localhost:3001".to_vec(), + provisioning_certification_key: pck_encoded.to_vec().try_into().unwrap(), }); }: _(RawOrigin::Signed(attestee.clone()), quote.clone()) diff --git a/pallets/attestation/src/lib.rs b/pallets/attestation/src/lib.rs index ebab0a19e..ae09ea549 100644 --- a/pallets/attestation/src/lib.rs +++ b/pallets/attestation/src/lib.rs @@ -51,7 +51,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use sp_std::vec::Vec; - use tdx_quote::Quote; + use tdx_quote::{decode_verifying_key, Quote}; pub use crate::weights::WeightInfo; @@ -123,6 +123,10 @@ pub mod pallet { NoServerInfo, /// Unacceptable VM image running BadMrtdValue, + /// Cannot decode verifying key (PCK) + CannotDecodeVerifyingKey, + /// Could not verify PCK signature + PckVerification, } #[pallet::call] @@ -142,17 +146,15 @@ pub mod pallet { let nonce = PendingAttestations::::get(&who).ok_or(Error::::UnexpectedAttestation)?; - // Parse the quote (which internally verifies the signature) + // Parse the quote (which internally verifies the attestation key signature) let quote = Quote::from_bytes("e).map_err(|_| Error::::BadQuote)?; - // Get associated x25519 public key from staking pallet - let x25519_public_key = { + // Get associated server info from staking pallet + let server_info = { let stash_account = pallet_staking_extension::Pallet::::threshold_to_stash(&who) .ok_or(Error::::NoStashAccount)?; - let server_info = - pallet_staking_extension::Pallet::::threshold_server(&stash_account) - .ok_or(Error::::NoServerInfo)?; - server_info.x25519_public_key + pallet_staking_extension::Pallet::::threshold_server(&stash_account) + .ok_or(Error::::NoServerInfo)? }; // Get current block number @@ -163,7 +165,7 @@ pub mod pallet { // Check report input data matches the nonce, TSS details and block number let expected_input_data = - QuoteInputData::new(&who, x25519_public_key, nonce, block_number); + QuoteInputData::new(&who, server_info.x25519_public_key, nonce, block_number); ensure!( quote.report_input_data() == expected_input_data.0, Error::::IncorrectInputData @@ -175,8 +177,18 @@ pub mod pallet { let accepted_mrtd_values = pallet_parameters::Pallet::::accepted_mrtd_values(); ensure!(accepted_mrtd_values.contains(&mrtd_value), Error::::BadMrtdValue); - // TODO #982 Check that the attestation public key matches that from PCK certificate - let _attestation_key = quote.attestation_key; + // Check that the attestation public key is signed with the PCK + let provisioning_certification_key = decode_verifying_key( + &server_info + .provisioning_certification_key + .to_vec() + .try_into() + .map_err(|_| Error::::CannotDecodeVerifyingKey)?, + ) + .map_err(|_| Error::::CannotDecodeVerifyingKey)?; + quote + .verify_with_pck(provisioning_certification_key) + .map_err(|_| Error::::PckVerification)?; // Remove the entry from PendingAttestations PendingAttestations::::remove(&who); diff --git a/pallets/attestation/src/mock.rs b/pallets/attestation/src/mock.rs index 086153d1f..3513578c4 100644 --- a/pallets/attestation/src/mock.rs +++ b/pallets/attestation/src/mock.rs @@ -36,6 +36,13 @@ use std::cell::RefCell; use crate as pallet_attestation; +/// This is a randomly generated secret p256 ECDSA key - for mocking the provisioning certification +/// key +pub const PCK: [u8; 32] = [ + 117, 153, 212, 7, 220, 16, 181, 32, 110, 138, 4, 68, 208, 37, 104, 54, 1, 110, 232, 207, 100, + 168, 16, 99, 66, 83, 21, 178, 81, 155, 132, 37, +]; + const NULL_ARR: [u8; 32] = [0; 32]; type Block = frame_system::mocking::MockBlock; @@ -342,10 +349,12 @@ pub fn new_test_ext() -> sp_io::TestExternalities { }; pallet_attestation.assimilate_storage(&mut t).unwrap(); + let pck = tdx_quote::SigningKey::from_bytes(&PCK.into()).unwrap(); + let pck_encoded = tdx_quote::encode_verifying_key(&pck.verifying_key()).unwrap(); let pallet_staking_extension = pallet_staking_extension::GenesisConfig:: { threshold_servers: vec![ - // (ValidatorID, (AccountId, X25519PublicKey, TssServerURL)) - (5, (0, NULL_ARR, vec![20])), + // (ValidatorID, (AccountId, X25519PublicKey, TssServerURL, PCK)) + (5, (0, NULL_ARR, vec![20], pck_encoded.to_vec().try_into().unwrap())), ], proactive_refresh_data: (vec![], vec![]), mock_signer_rotate: (false, vec![], vec![]), diff --git a/pallets/attestation/src/tests.rs b/pallets/attestation/src/tests.rs index 7e34966e2..31ef6c53e 100644 --- a/pallets/attestation/src/tests.rs +++ b/pallets/attestation/src/tests.rs @@ -27,9 +27,8 @@ fn attest() { let nonce = Attestation::pending_attestations(ATTESTEE).unwrap(); assert_eq!(nonce, [0; 32]); - // For now it doesn't matter what this is, but once we handle PCK certificates this will - // need to correspond to the public key in the certificate - let signing_key = tdx_quote::SigningKey::random(&mut OsRng); + let attestation_key = tdx_quote::SigningKey::random(&mut OsRng); + let pck = tdx_quote::SigningKey::from_bytes(&PCK.into()).unwrap(); let input_data = QuoteInputData::new( ATTESTEE, // TSS Account ID @@ -37,7 +36,7 @@ fn attest() { nonce, 0, // Block number ); - let quote = tdx_quote::Quote::mock(signing_key.clone(), input_data.0); + let quote = tdx_quote::Quote::mock(attestation_key.clone(), pck, input_data.0); assert_ok!( Attestation::attest(RuntimeOrigin::signed(ATTESTEE), quote.as_bytes().to_vec(),) ); diff --git a/pallets/propagation/src/mock.rs b/pallets/propagation/src/mock.rs index a87be8a69..2d99b152d 100644 --- a/pallets/propagation/src/mock.rs +++ b/pallets/propagation/src/mock.rs @@ -28,7 +28,7 @@ use sp_runtime::{ curve::PiecewiseLinear, testing::{TestXt, UintAuthorityId}, traits::{BlakeTwo256, ConvertInto, IdentityLookup}, - BuildStorage, Perbill, + BoundedVec, BuildStorage, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; use std::cell::RefCell; @@ -379,11 +379,11 @@ pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = system::GenesisConfig::::default().build_storage().unwrap(); let pallet_staking_extension = pallet_staking_extension::GenesisConfig:: { threshold_servers: vec![ - // (ValidatorID, (AccountId, X25519PublicKey, TssServerURL)) - (5, (7, NULL_ARR, vec![20])), - (6, (8, NULL_ARR, vec![40])), - (1, (3, NULL_ARR, vec![10])), - (2, (4, NULL_ARR, vec![11])), + // (ValidatorID, (AccountId, X25519PublicKey, TssServerURL, PCK)) + (5, (7, NULL_ARR, vec![20], BoundedVec::with_max_capacity())), + (6, (8, NULL_ARR, vec![40], BoundedVec::with_max_capacity())), + (1, (3, NULL_ARR, vec![10], BoundedVec::with_max_capacity())), + (2, (4, NULL_ARR, vec![11], BoundedVec::with_max_capacity())), ], proactive_refresh_data: (vec![], vec![]), mock_signer_rotate: (false, vec![], vec![]), diff --git a/pallets/registry/src/benchmarking.rs b/pallets/registry/src/benchmarking.rs index 92021f801..79e2c7710 100644 --- a/pallets/registry/src/benchmarking.rs +++ b/pallets/registry/src/benchmarking.rs @@ -52,8 +52,12 @@ pub fn add_non_syncing_validators( ) -> Vec<::ValidatorId> { let validators = create_validators::(validator_amount, SEED); let account = account::("ts_account", 1, SEED); - let server_info = - ServerInfo { tss_account: account, x25519_public_key: NULL_ARR, endpoint: vec![20] }; + let server_info = ServerInfo { + tss_account: account, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; for (c, validator) in validators.iter().enumerate() { >::insert(validator, server_info.clone()); if c >= syncing_validators.try_into().unwrap() { diff --git a/pallets/registry/src/mock.rs b/pallets/registry/src/mock.rs index 3d2c10f19..3101f1760 100644 --- a/pallets/registry/src/mock.rs +++ b/pallets/registry/src/mock.rs @@ -366,12 +366,12 @@ pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = system::GenesisConfig::::default().build_storage().unwrap(); let pallet_staking_extension = pallet_staking_extension::GenesisConfig:: { threshold_servers: vec![ - // (ValidatorID, (AccountId, X25519PublicKey, TssServerURL)) - (5, (7, NULL_ARR, vec![20])), - (6, (8, NULL_ARR, vec![40])), - (1, (3, NULL_ARR, vec![10])), - (2, (4, NULL_ARR, vec![11])), - (7, (4, NULL_ARR, vec![50])), + // (ValidatorID, (AccountId, X25519PublicKey, TssServerURL, PCK)) + (5, (7, NULL_ARR, vec![20], BoundedVec::with_max_capacity())), + (6, (8, NULL_ARR, vec![40], BoundedVec::with_max_capacity())), + (1, (3, NULL_ARR, vec![10], BoundedVec::with_max_capacity())), + (2, (4, NULL_ARR, vec![11], BoundedVec::with_max_capacity())), + (7, (4, NULL_ARR, vec![50], BoundedVec::with_max_capacity())), ], proactive_refresh_data: (vec![], vec![]), mock_signer_rotate: (false, vec![], vec![]), diff --git a/pallets/registry/src/tests.rs b/pallets/registry/src/tests.rs index ccde65810..f382bd34c 100644 --- a/pallets/registry/src/tests.rs +++ b/pallets/registry/src/tests.rs @@ -57,12 +57,24 @@ fn setup_programs( fn it_tests_get_validators_info() { new_test_ext().execute_with(|| { let result_1 = Registry::get_validators_info().unwrap(); - let server_info_1 = - ServerInfo { tss_account: 3, x25519_public_key: NULL_ARR, endpoint: vec![10] }; - let server_info_2 = - ServerInfo { tss_account: 4, x25519_public_key: NULL_ARR, endpoint: vec![11] }; - let server_info_3 = - ServerInfo { tss_account: 7, x25519_public_key: NULL_ARR, endpoint: vec![20] }; + let server_info_1 = ServerInfo { + tss_account: 3, + x25519_public_key: NULL_ARR, + endpoint: vec![10], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; + let server_info_2 = ServerInfo { + tss_account: 4, + x25519_public_key: NULL_ARR, + endpoint: vec![11], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; + let server_info_3 = ServerInfo { + tss_account: 7, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; assert_eq!(result_1, vec![server_info_1, server_info_2, server_info_3]); }); diff --git a/pallets/staking/src/benchmarking.rs b/pallets/staking/src/benchmarking.rs index 5fce1157b..088342a9a 100644 --- a/pallets/staking/src/benchmarking.rs +++ b/pallets/staking/src/benchmarking.rs @@ -21,6 +21,7 @@ use frame_support::{ assert_ok, ensure, sp_runtime::traits::StaticLookup, traits::{Currency, Get}, + BoundedVec, }; use frame_system::{EventRecord, RawOrigin}; use pallet_parameters::{SignersInfo, SignersSize}; @@ -77,8 +78,12 @@ fn prep_bond_and_validate( reward_destination, )); - let server_info = - ServerInfo { tss_account: threshold, x25519_public_key, endpoint: vec![20, 20] }; + let server_info = ServerInfo { + tss_account: threshold, + x25519_public_key, + endpoint: vec![20, 20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; if validate_also { assert_ok!(>::validate( @@ -120,6 +125,7 @@ benchmarks! { endpoint: vec![20, 20], tss_account: _bonder.clone(), x25519_public_key: NULL_ARR, + provisioning_certification_key: BoundedVec::with_max_capacity(), }; assert_last_event::(Event::::ThresholdAccountChanged(bonder, server_info).into()); } @@ -161,6 +167,7 @@ benchmarks! { tss_account: threshold.clone(), x25519_public_key: NULL_ARR, endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), }; }: _(RawOrigin::Signed(bonder.clone()), validator_preference, server_info) diff --git a/pallets/staking/src/lib.rs b/pallets/staking/src/lib.rs index f6ea6f16a..85b51ae5a 100644 --- a/pallets/staking/src/lib.rs +++ b/pallets/staking/src/lib.rs @@ -115,6 +115,7 @@ pub mod pallet { pub tss_account: AccountId, pub x25519_public_key: X25519PublicKey, pub endpoint: TssServerURL, + pub provisioning_certification_key: VerifyingKey, } /// Info that is requiered to do a proactive refresh #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, Default)] @@ -238,7 +239,7 @@ pub mod pallet { /// A type used to simplify the genesis configuration definition. pub type ThresholdServersConfig = ( ::ValidatorId, - (::AccountId, X25519PublicKey, TssServerURL), + (::AccountId, X25519PublicKey, TssServerURL, VerifyingKey), ); #[pallet::genesis_config] @@ -265,6 +266,7 @@ pub mod pallet { tss_account: server_info_tuple.0.clone(), x25519_public_key: server_info_tuple.1, endpoint: server_info_tuple.2.clone(), + provisioning_certification_key: server_info_tuple.3.clone(), }; ThresholdServers::::insert(validator_stash, server_info.clone()); diff --git a/pallets/staking/src/mock.rs b/pallets/staking/src/mock.rs index 0d1fe7159..9ab987bfd 100644 --- a/pallets/staking/src/mock.rs +++ b/pallets/staking/src/mock.rs @@ -400,8 +400,11 @@ pub fn new_test_ext() -> sp_io::TestExternalities { balances: vec![(1, 100), (2, 100), (3, 100), (4, 100)], }; let pallet_staking_extension = pallet_staking_extension::GenesisConfig:: { - // (ValidatorID, (AccountId, X25519PublicKey, TssServerURL)) - threshold_servers: vec![(5, (7, NULL_ARR, vec![20])), (6, (8, NULL_ARR, vec![40]))], + // (ValidatorID, (AccountId, X25519PublicKey, TssServerURL, VerifyingKey)) + threshold_servers: vec![ + (5, (7, NULL_ARR, vec![20], BoundedVec::with_max_capacity())), + (6, (8, NULL_ARR, vec![40], BoundedVec::with_max_capacity())), + ], proactive_refresh_data: (vec![], vec![]), mock_signer_rotate: (false, vec![], vec![]), }; diff --git a/pallets/staking/src/tests.rs b/pallets/staking/src/tests.rs index a6639b9f5..7f1c21ba1 100644 --- a/pallets/staking/src/tests.rs +++ b/pallets/staking/src/tests.rs @@ -22,6 +22,7 @@ use frame_support::{assert_noop, assert_ok}; use frame_system::{EventRecord, Phase}; use pallet_parameters::SignersSize; use pallet_session::SessionManager; +use sp_runtime::BoundedVec; const NULL_ARR: [u8; 32] = [0; 32]; #[test] @@ -29,11 +30,21 @@ fn basic_setup_works() { new_test_ext().execute_with(|| { assert_eq!( Staking::threshold_server(5).unwrap(), - ServerInfo { tss_account: 7, x25519_public_key: NULL_ARR, endpoint: vec![20] } + ServerInfo { + tss_account: 7, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity() + } ); assert_eq!( Staking::threshold_server(6).unwrap(), - ServerInfo { tss_account: 8, x25519_public_key: NULL_ARR, endpoint: vec![40] } + ServerInfo { + tss_account: 8, + x25519_public_key: NULL_ARR, + endpoint: vec![40], + provisioning_certification_key: BoundedVec::with_max_capacity() + } ); assert_eq!(Staking::threshold_to_stash(7).unwrap(), 5); assert_eq!(Staking::threshold_to_stash(8).unwrap(), 6); @@ -51,8 +62,12 @@ fn it_takes_in_an_endpoint() { pallet_staking::RewardDestination::Account(1), )); - let server_info = - ServerInfo { tss_account: 3, x25519_public_key: NULL_ARR, endpoint: vec![20] }; + let server_info = ServerInfo { + tss_account: 3, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; assert_ok!(Staking::validate( RuntimeOrigin::signed(1), pallet_staking::ValidatorPrefs::default(), @@ -68,6 +83,7 @@ fn it_takes_in_an_endpoint() { tss_account: 3, x25519_public_key: NULL_ARR, endpoint: vec![20, 20, 20, 20], + provisioning_certification_key: BoundedVec::with_max_capacity(), }; assert_noop!( Staking::validate( @@ -78,8 +94,12 @@ fn it_takes_in_an_endpoint() { Error::::EndpointTooLong ); - let server_info = - ServerInfo { tss_account: 5, x25519_public_key: NULL_ARR, endpoint: vec![20, 20] }; + let server_info = ServerInfo { + tss_account: 5, + x25519_public_key: NULL_ARR, + endpoint: vec![20, 20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; assert_noop!( Staking::validate( RuntimeOrigin::signed(4), @@ -100,8 +120,12 @@ fn it_will_not_allow_validator_to_use_existing_tss_account() { pallet_staking::RewardDestination::Account(1), )); - let server_info = - ServerInfo { tss_account: 3, x25519_public_key: NULL_ARR, endpoint: vec![20] }; + let server_info = ServerInfo { + tss_account: 3, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; assert_ok!(Staking::validate( RuntimeOrigin::signed(1), pallet_staking::ValidatorPrefs::default(), @@ -134,8 +158,12 @@ fn it_changes_endpoint() { pallet_staking::RewardDestination::Account(1), )); - let server_info = - ServerInfo { tss_account: 3, x25519_public_key: NULL_ARR, endpoint: vec![20] }; + let server_info = ServerInfo { + tss_account: 3, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; assert_ok!(Staking::validate( RuntimeOrigin::signed(1), pallet_staking::ValidatorPrefs::default(), @@ -161,8 +189,12 @@ fn it_changes_threshold_account() { pallet_staking::RewardDestination::Account(1), )); - let server_info = - ServerInfo { tss_account: 3, x25519_public_key: NULL_ARR, endpoint: vec![20] }; + let server_info = ServerInfo { + tss_account: 3, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; assert_ok!(Staking::validate( RuntimeOrigin::signed(1), pallet_staking::ValidatorPrefs::default(), @@ -185,8 +217,12 @@ fn it_changes_threshold_account() { pallet_staking::RewardDestination::Account(2), )); - let server_info = - ServerInfo { tss_account: 5, x25519_public_key: NULL_ARR, endpoint: vec![20] }; + let server_info = ServerInfo { + tss_account: 5, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; assert_ok!(Staking::validate( RuntimeOrigin::signed(2), pallet_staking::ValidatorPrefs::default(), @@ -209,8 +245,12 @@ fn it_will_not_allow_existing_tss_account_when_changing_threshold_account() { pallet_staking::RewardDestination::Account(1), )); - let server_info = - ServerInfo { tss_account: 3, x25519_public_key: NULL_ARR, endpoint: vec![20] }; + let server_info = ServerInfo { + tss_account: 3, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; assert_ok!(Staking::validate( RuntimeOrigin::signed(1), pallet_staking::ValidatorPrefs::default(), @@ -224,8 +264,12 @@ fn it_will_not_allow_existing_tss_account_when_changing_threshold_account() { pallet_staking::RewardDestination::Account(2), )); - let server_info = - ServerInfo { tss_account: 5, x25519_public_key: NULL_ARR, endpoint: vec![20] }; + let server_info = ServerInfo { + tss_account: 5, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; assert_ok!(Staking::validate( RuntimeOrigin::signed(2), pallet_staking::ValidatorPrefs::default(), @@ -250,8 +294,12 @@ fn it_deletes_when_no_bond_left() { pallet_staking::RewardDestination::Account(1), )); - let server_info = - ServerInfo { tss_account: 3, x25519_public_key: NULL_ARR, endpoint: vec![20] }; + let server_info = ServerInfo { + tss_account: 3, + x25519_public_key: NULL_ARR, + endpoint: vec![20], + provisioning_certification_key: BoundedVec::with_max_capacity(), + }; assert_ok!(Staking::validate( RuntimeOrigin::signed(2), pallet_staking::ValidatorPrefs::default(), From 2800d612bbde297d261bebf57e2e1f37ac5cd0bf Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 25 Sep 2024 20:06:46 +0200 Subject: [PATCH 03/17] Fix how pre-generated keyshares are added for tests (#1061) * Rename test keyshares * Fix adding pre-generated keyshares for tests * Rm unused argument to test helper * Use copy not clone and other review suggestions * Charlie should be the chosen new signer in reshare integration test chainspec * WIP fix reshare test * Include correct nodes in chainspec integration test for reshare mock * Fix client remove program test * Ignore proactive refresh test * fix test * clean * fix integration test * fmt * clean * add unsafe to test command * fix * fix * lint * fix * ignore sign eth tx --------- Co-authored-by: Jesse Abramowitz --- crates/client/src/tests.rs | 7 +- crates/testing-utils/Cargo.toml | 2 +- ...lice.keyshare => dave-keyshare-0.keyshare} | Bin ...-bob.keyshare => dave-keyshare-1.keyshare} | Bin ...rlie.keyshare => dave-keyshare-2.keyshare} | Bin ...alice.keyshare => eve-keyshare-0.keyshare} | Bin ...y-bob.keyshare => eve-keyshare-1.keyshare} | Bin ...arlie.keyshare => eve-keyshare-2.keyshare} | Bin ...lice.keyshare => dave-keyshare-0.keyshare} | Bin ...-bob.keyshare => dave-keyshare-1.keyshare} | Bin ...rlie.keyshare => dave-keyshare-2.keyshare} | Bin ...alice.keyshare => eve-keyshare-0.keyshare} | Bin ...y-bob.keyshare => eve-keyshare-1.keyshare} | Bin ...arlie.keyshare => eve-keyshare-2.keyshare} | Bin crates/testing-utils/src/helpers.rs | 4 +- .../src/attestation/tests.rs | 2 +- .../src/helpers/launch.rs | 2 +- .../src/helpers/tests.rs | 64 ++++++----- .../src/signing_client/tests.rs | 3 +- .../src/user/tests.rs | 32 ++---- .../src/validator/tests.rs | 106 +++++++++++++----- .../tests/register_and_sign.rs | 6 +- .../tests/sign_eth_tx.rs | 4 +- node/cli/src/chain_spec/integration_tests.rs | 4 +- 24 files changed, 141 insertions(+), 95 deletions(-) rename crates/testing-utils/keyshares/production/{dave-keyshare-held-by-alice.keyshare => dave-keyshare-0.keyshare} (100%) rename crates/testing-utils/keyshares/production/{dave-keyshare-held-by-bob.keyshare => dave-keyshare-1.keyshare} (100%) rename crates/testing-utils/keyshares/production/{dave-keyshare-held-by-charlie.keyshare => dave-keyshare-2.keyshare} (100%) rename crates/testing-utils/keyshares/production/{eve-keyshare-held-by-alice.keyshare => eve-keyshare-0.keyshare} (100%) rename crates/testing-utils/keyshares/production/{eve-keyshare-held-by-bob.keyshare => eve-keyshare-1.keyshare} (100%) rename crates/testing-utils/keyshares/production/{eve-keyshare-held-by-charlie.keyshare => eve-keyshare-2.keyshare} (100%) rename crates/testing-utils/keyshares/test/{dave-keyshare-held-by-alice.keyshare => dave-keyshare-0.keyshare} (100%) rename crates/testing-utils/keyshares/test/{dave-keyshare-held-by-bob.keyshare => dave-keyshare-1.keyshare} (100%) rename crates/testing-utils/keyshares/test/{dave-keyshare-held-by-charlie.keyshare => dave-keyshare-2.keyshare} (100%) rename crates/testing-utils/keyshares/test/{eve-keyshare-held-by-alice.keyshare => eve-keyshare-0.keyshare} (100%) rename crates/testing-utils/keyshares/test/{eve-keyshare-held-by-bob.keyshare => eve-keyshare-1.keyshare} (100%) rename crates/testing-utils/keyshares/test/{eve-keyshare-held-by-charlie.keyshare => eve-keyshare-2.keyshare} (100%) diff --git a/crates/client/src/tests.rs b/crates/client/src/tests.rs index 13ab41d8d..f84b221d9 100644 --- a/crates/client/src/tests.rs +++ b/crates/client/src/tests.rs @@ -18,9 +18,9 @@ use crate::{ use entropy_testing_utils::{ constants::{TEST_PROGRAM_WASM_BYTECODE, TSS_ACCOUNTS}, helpers::{derive_mock_pck_verifying_key, encode_verifying_key}, - jump_start_network, + jump_start_network, spawn_testing_validators, substrate_context::test_context_stationary, - test_node_process_testing_state, + test_node_process_testing_state, ChainSpecType, }; use serial_test::serial; use sp_core::{sr25519, Pair, H256}; @@ -134,6 +134,9 @@ async fn test_store_and_remove_program() { async fn test_remove_program_reference_counter() { let program_owner = AccountKeyring::Ferdie.pair(); + let (_validator_ips, _validator_ids) = + spawn_testing_validators(ChainSpecType::Integration).await; + let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; let api = get_api(&substrate_context.ws_url).await.unwrap(); diff --git a/crates/testing-utils/Cargo.toml b/crates/testing-utils/Cargo.toml index 9cf8ae52d..686c14f39 100644 --- a/crates/testing-utils/Cargo.toml +++ b/crates/testing-utils/Cargo.toml @@ -17,7 +17,7 @@ parity-scale-codec="3.6.12" lazy_static ="1.5.0" hex-literal ="0.4.1" tokio ={ version="1.40", features=["macros", "fs", "rt-multi-thread", "io-util", "process"] } -axum ={ version="0.7.6" } +axum ={ version="0.7.5" } entropy-shared ={ version="0.2.0", path="../shared" } entropy-kvdb ={ version="0.2.0", path="../kvdb", default-features=false } entropy-tss ={ version="0.2.0", path="../threshold-signature-server", features=["test_helpers"] } diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-0.keyshare similarity index 100% rename from crates/testing-utils/keyshares/production/dave-keyshare-held-by-alice.keyshare rename to crates/testing-utils/keyshares/production/dave-keyshare-0.keyshare diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-held-by-bob.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-1.keyshare similarity index 100% rename from crates/testing-utils/keyshares/production/dave-keyshare-held-by-bob.keyshare rename to crates/testing-utils/keyshares/production/dave-keyshare-1.keyshare diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-held-by-charlie.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-2.keyshare similarity index 100% rename from crates/testing-utils/keyshares/production/dave-keyshare-held-by-charlie.keyshare rename to crates/testing-utils/keyshares/production/dave-keyshare-2.keyshare diff --git a/crates/testing-utils/keyshares/production/eve-keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/production/eve-keyshare-0.keyshare similarity index 100% rename from crates/testing-utils/keyshares/production/eve-keyshare-held-by-alice.keyshare rename to crates/testing-utils/keyshares/production/eve-keyshare-0.keyshare diff --git a/crates/testing-utils/keyshares/production/eve-keyshare-held-by-bob.keyshare b/crates/testing-utils/keyshares/production/eve-keyshare-1.keyshare similarity index 100% rename from crates/testing-utils/keyshares/production/eve-keyshare-held-by-bob.keyshare rename to crates/testing-utils/keyshares/production/eve-keyshare-1.keyshare diff --git a/crates/testing-utils/keyshares/production/eve-keyshare-held-by-charlie.keyshare b/crates/testing-utils/keyshares/production/eve-keyshare-2.keyshare similarity index 100% rename from crates/testing-utils/keyshares/production/eve-keyshare-held-by-charlie.keyshare rename to crates/testing-utils/keyshares/production/eve-keyshare-2.keyshare diff --git a/crates/testing-utils/keyshares/test/dave-keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/test/dave-keyshare-0.keyshare similarity index 100% rename from crates/testing-utils/keyshares/test/dave-keyshare-held-by-alice.keyshare rename to crates/testing-utils/keyshares/test/dave-keyshare-0.keyshare diff --git a/crates/testing-utils/keyshares/test/dave-keyshare-held-by-bob.keyshare b/crates/testing-utils/keyshares/test/dave-keyshare-1.keyshare similarity index 100% rename from crates/testing-utils/keyshares/test/dave-keyshare-held-by-bob.keyshare rename to crates/testing-utils/keyshares/test/dave-keyshare-1.keyshare diff --git a/crates/testing-utils/keyshares/test/dave-keyshare-held-by-charlie.keyshare b/crates/testing-utils/keyshares/test/dave-keyshare-2.keyshare similarity index 100% rename from crates/testing-utils/keyshares/test/dave-keyshare-held-by-charlie.keyshare rename to crates/testing-utils/keyshares/test/dave-keyshare-2.keyshare diff --git a/crates/testing-utils/keyshares/test/eve-keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/test/eve-keyshare-0.keyshare similarity index 100% rename from crates/testing-utils/keyshares/test/eve-keyshare-held-by-alice.keyshare rename to crates/testing-utils/keyshares/test/eve-keyshare-0.keyshare diff --git a/crates/testing-utils/keyshares/test/eve-keyshare-held-by-bob.keyshare b/crates/testing-utils/keyshares/test/eve-keyshare-1.keyshare similarity index 100% rename from crates/testing-utils/keyshares/test/eve-keyshare-held-by-bob.keyshare rename to crates/testing-utils/keyshares/test/eve-keyshare-1.keyshare diff --git a/crates/testing-utils/keyshares/test/eve-keyshare-held-by-charlie.keyshare b/crates/testing-utils/keyshares/test/eve-keyshare-2.keyshare similarity index 100% rename from crates/testing-utils/keyshares/test/eve-keyshare-held-by-charlie.keyshare rename to crates/testing-utils/keyshares/test/eve-keyshare-2.keyshare diff --git a/crates/testing-utils/src/helpers.rs b/crates/testing-utils/src/helpers.rs index 5e64f843e..246720958 100644 --- a/crates/testing-utils/src/helpers.rs +++ b/crates/testing-utils/src/helpers.rs @@ -27,11 +27,9 @@ pub use tdx_quote::encode_verifying_key; /// A helper for setting up tests which starts both a set of TS servers and a chain node and returns /// the chain API as well as IP addresses and PartyId of the started validators pub async fn spawn_tss_nodes_and_start_chain( - add_parent_key: bool, chain_spec_type: ChainSpecType, ) -> (OnlineClient, LegacyRpcMethods, Vec, Vec) { - let (validator_ips, validator_ids) = - spawn_testing_validators(add_parent_key, chain_spec_type.clone()).await; + let (validator_ips, validator_ids) = spawn_testing_validators(chain_spec_type).await; let (api, rpc) = match chain_spec_type { ChainSpecType::Development => { diff --git a/crates/threshold-signature-server/src/attestation/tests.rs b/crates/threshold-signature-server/src/attestation/tests.rs index 6dc8a495c..f9883fcca 100644 --- a/crates/threshold-signature-server/src/attestation/tests.rs +++ b/crates/threshold-signature-server/src/attestation/tests.rs @@ -33,7 +33,7 @@ async fn test_attest() { let cxt = test_node_process_stationary().await; let (_validator_ips, _validator_ids) = - spawn_testing_validators(false, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let api = get_api(&cxt.ws_url).await.unwrap(); let rpc = get_rpc(&cxt.ws_url).await.unwrap(); diff --git a/crates/threshold-signature-server/src/helpers/launch.rs b/crates/threshold-signature-server/src/helpers/launch.rs index daa0df9c5..a90331b97 100644 --- a/crates/threshold-signature-server/src/helpers/launch.rs +++ b/crates/threshold-signature-server/src/helpers/launch.rs @@ -65,7 +65,7 @@ pub const FORBIDDEN_KEY_DIFFIE_HELLMAN_PUBLIC: &str = "DH_PUBLIC"; // Deafult name for TSS server // Will set mnemonic and db path -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone, Copy)] pub enum ValidatorName { Alice, Bob, diff --git a/crates/threshold-signature-server/src/helpers/tests.rs b/crates/threshold-signature-server/src/helpers/tests.rs index b60666988..172f9ab31 100644 --- a/crates/threshold-signature-server/src/helpers/tests.rs +++ b/crates/threshold-signature-server/src/helpers/tests.rs @@ -34,6 +34,7 @@ use crate::{ substrate::submit_transaction, validator::get_signer_and_x25519_secret_from_mnemonic, }, + r#unsafe::api::UnsafeQuery, signing_client::ListenerState, AppState, }; @@ -42,7 +43,7 @@ use entropy_kvdb::{encrypted_sled::PasswordMethod, get_db_path, kv_manager::KvMa use entropy_protocol::PartyId; #[cfg(test)] use entropy_shared::EncodedVerifyingKey; -use entropy_shared::{DAVE_VERIFYING_KEY, EVE_VERIFYING_KEY, NETWORK_PARENT_KEY}; +use entropy_shared::{EVE_VERIFYING_KEY, NETWORK_PARENT_KEY}; use std::time::Duration; use subxt::{ backend::legacy::LegacyRpcMethods, ext::sp_core::sr25519, tx::PairSigner, @@ -121,7 +122,7 @@ pub async fn create_clients( } /// A way to specify which chainspec to use in testing -#[derive(Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum ChainSpecType { /// The development chainspec, which has 3 TSS nodes Development, @@ -132,7 +133,6 @@ pub enum ChainSpecType { /// Spawn either 3 or 4 TSS nodes depending on chain configuration, adding pre-stored keyshares if /// desired pub async fn spawn_testing_validators( - add_parent_key: bool, chain_spec_type: ChainSpecType, ) -> (Vec, Vec) { let add_fourth_server = chain_spec_type == ChainSpecType::Integration; @@ -165,11 +165,6 @@ pub async fn spawn_testing_validators( let mut ids = vec![alice_id, bob_id, charlie_id]; - put_keyshares_in_db("alice", alice_kv, add_parent_key).await; - put_keyshares_in_db("bob", bob_kv, add_parent_key).await; - put_keyshares_in_db("charlie", charlie_kv, add_parent_key).await; - // Don't give dave keyshares as dave is not initially in the signing committee - let listener_alice = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", ports[0])) .await .expect("Unable to bind to given server address."); @@ -215,25 +210,30 @@ pub async fn spawn_testing_validators( } /// Add the pre-generated test keyshares to a kvdb -async fn put_keyshares_in_db(holder_name: &str, kvdb: KvManager, add_parent_key: bool) { - let mut user_names_and_verifying_keys = - vec![("eve", hex::encode(EVE_VERIFYING_KEY)), ("dave", hex::encode(DAVE_VERIFYING_KEY))]; - if add_parent_key { - user_names_and_verifying_keys.push(("eve", hex::encode(NETWORK_PARENT_KEY))) - } - for (user_name, user_verifying_key) in user_names_and_verifying_keys { - let keyshare_bytes = { - let project_root = - project_root::get_project_root().expect("Error obtaining project root."); - let file_path = project_root.join(format!( - "crates/testing-utils/keyshares/production/{}-keyshare-held-by-{}.keyshare", - user_name, holder_name - )); - std::fs::read(file_path).unwrap() - }; - let reservation = kvdb.kv().reserve_key(user_verifying_key).await.unwrap(); - kvdb.kv().put(reservation, keyshare_bytes).await.unwrap(); - } +async fn put_keyshares_in_db(index: usize, validator_name: ValidatorName) { + // Eve's keyshares are used as the network parent key + let user_name = "eve"; + let keyshare_bytes = { + let project_root = project_root::get_project_root().expect("Error obtaining project root."); + let file_path = project_root.join(format!( + "crates/testing-utils/keyshares/production/{}-keyshare-{}.keyshare", + user_name, index + )); + std::fs::read(file_path).unwrap() + }; + + let unsafe_put = UnsafeQuery { key: hex::encode(NETWORK_PARENT_KEY), value: keyshare_bytes }; + let unsafe_put = serde_json::to_string(&unsafe_put).unwrap(); + + let port = 3001 + (validator_name as usize); + let http_client = reqwest::Client::new(); + http_client + .post(format!("http://127.0.0.1:{port}/unsafe/put")) + .header("Content-Type", "application/json") + .body(unsafe_put.clone()) + .send() + .await + .unwrap(); } /// Removes the program at the program hash @@ -284,6 +284,7 @@ pub async fn jump_start_network_with_signer( let validators_names = vec![ValidatorName::Alice, ValidatorName::Bob, ValidatorName::Charlie, ValidatorName::Dave]; + let mut keyshare_index = 0; for validator_name in validators_names { let mnemonic = development_mnemonic(&Some(validator_name)); let (tss_signer, _static_secret) = @@ -292,8 +293,13 @@ pub async fn jump_start_network_with_signer( entropy::tx().registry().confirm_jump_start(BoundedVec(EVE_VERIFYING_KEY.to_vec())); // Ignore the error as one confirmation will fail - let _result = - submit_transaction(api, rpc, &tss_signer, &jump_start_confirm_request, None).await; + if submit_transaction(api, rpc, &tss_signer, &jump_start_confirm_request, None) + .await + .is_ok() + { + put_keyshares_in_db(keyshare_index, validator_name).await; + keyshare_index += 1; + } } } diff --git a/crates/threshold-signature-server/src/signing_client/tests.rs b/crates/threshold-signature-server/src/signing_client/tests.rs index 63cc8f6b3..e1822ea44 100644 --- a/crates/threshold-signature-server/src/signing_client/tests.rs +++ b/crates/threshold-signature-server/src/signing_client/tests.rs @@ -38,6 +38,7 @@ use parity_scale_codec::Encode; use serial_test::serial; use sp_keyring::AccountKeyring; +#[ignore] #[tokio::test] #[serial] async fn test_proactive_refresh() { @@ -45,7 +46,7 @@ async fn test_proactive_refresh() { clean_tests(); let _cxt = test_node_process_testing_state(false).await; - let (validator_ips, _ids) = spawn_testing_validators(false, ChainSpecType::Integration).await; + let (validator_ips, _ids) = spawn_testing_validators(ChainSpecType::Integration).await; let signing_committee_ips = &validator_ips[..3].to_vec(); let client = reqwest::Client::new(); diff --git a/crates/threshold-signature-server/src/user/tests.rs b/crates/threshold-signature-server/src/user/tests.rs index 101ee9c6e..6dc2866f0 100644 --- a/crates/threshold-signature-server/src/user/tests.rs +++ b/crates/threshold-signature-server/src/user/tests.rs @@ -170,9 +170,8 @@ async fn test_signature_requests_fail_on_different_conditions() { let one = AccountKeyring::One; let two = AccountKeyring::Two; - let add_parent_key_to_kvdb = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key_to_kvdb, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. @@ -307,9 +306,8 @@ async fn signature_request_with_derived_account_works() { let bob = AccountKeyring::Bob; let charlie = AccountKeyring::Charlie; - let add_parent_key_to_kvdb = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key_to_kvdb, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. @@ -356,9 +354,8 @@ async fn test_signing_fails_if_wrong_participants_are_used() { let one = AccountKeyring::Dave; - let add_parent_key = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -436,9 +433,8 @@ async fn test_request_limit_are_updated_during_signing() { let one = AccountKeyring::One; let two = AccountKeyring::Two; - let add_parent_key = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -539,9 +535,8 @@ async fn test_fails_to_sign_if_non_signing_group_participants_are_used() { let one = AccountKeyring::One; let two = AccountKeyring::Two; - let add_parent_key = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -631,9 +626,8 @@ async fn test_program_with_config() { let one = AccountKeyring::One; let two = AccountKeyring::Two; - let add_parent_key = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -716,9 +710,8 @@ async fn test_jumpstart_network() { let alice = AccountKeyring::Alice; - let add_parent_key = false; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -917,9 +910,8 @@ async fn test_fail_infinite_program() { let one = AccountKeyring::One; let two = AccountKeyring::Two; - let add_parent_key = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -998,9 +990,8 @@ async fn test_device_key_proxy() { let one = AccountKeyring::One; let two = AccountKeyring::Two; - let add_parent_key_to_kvdb = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key_to_kvdb, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. @@ -1138,7 +1129,7 @@ async fn test_faucet() { let alice = AccountKeyring::Alice; let (validator_ips, _validator_ids) = - spawn_testing_validators(false, ChainSpecType::Development).await; + spawn_testing_validators(ChainSpecType::Development).await; let substrate_context = test_node_process_testing_state(true).await; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -1310,9 +1301,8 @@ async fn test_registration_flow() { let bob = AccountKeyring::Bob; let charlie = AccountKeyring::Charlie; - let add_parent_key_to_kvdb = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key_to_kvdb, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. diff --git a/crates/threshold-signature-server/src/validator/tests.rs b/crates/threshold-signature-server/src/validator/tests.rs index 1ea9f3032..ffa4ab534 100644 --- a/crates/threshold-signature-server/src/validator/tests.rs +++ b/crates/threshold-signature-server/src/validator/tests.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + // Copyright (C) 2023 Entropy Cryptography Inc. // // This program is free software: you can redistribute it and/or modify @@ -27,12 +29,16 @@ use crate::{ errors::ValidatorErr, }, }; -use entropy_client as test_client; +use entropy_client::{ + self as test_client, + chain_api::entropy::runtime_types::pallet_staking_extension::pallet::ServerInfo, +}; use entropy_client::{ chain_api::{ - entropy::runtime_types::bounded_collections::bounded_vec::BoundedVec, + entropy, entropy::runtime_types::bounded_collections::bounded_vec::BoundedVec, entropy::runtime_types::pallet_registry::pallet::ProgramInstance, get_api, get_rpc, }, + substrate::query_chain, Hasher, }; use entropy_kvdb::{ @@ -65,32 +71,53 @@ async fn test_reshare() { initialize_test_logger().await; clean_tests(); - let dave = AccountKeyring::DaveStash; - let cxt = test_node_process_testing_state(true).await; - let add_parent_key_to_kvdb = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key_to_kvdb, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let validator_ports = vec![3001, 3002, 3003, 3004]; let api = get_api(&cxt.ws_url).await.unwrap(); let rpc = get_rpc(&cxt.ws_url).await.unwrap(); let client = reqwest::Client::new(); - let mut key_shares_before = vec![]; - for port in &validator_ports[..3] { - key_shares_before.push(unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), *port).await); - } jump_start_network(&api, &rpc).await; + // Get current signers + let signer_query = entropy::storage().staking_extension().signers(); + let signer_stash_accounts = query_chain(&api, &rpc, signer_query, None).await.unwrap().unwrap(); + let mut signers = Vec::new(); + for signer in signer_stash_accounts.iter() { + let query = entropy::storage().staking_extension().threshold_servers(signer); + let server_info = query_chain(&api, &rpc, query, None).await.unwrap().unwrap(); + signers.push(server_info); + } + + // A map of account IDs to serialized keyshares before the reshare + let mut key_shares_before = HashMap::new(); + for signer in signers.iter() { + let port = get_port(signer); + key_shares_before.insert( + signer.tss_account.0, + unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), port).await, + ); + } + + // Get all validators + let validators_query = entropy::storage().session().validators(); + let all_validators = query_chain(&api, &rpc, validators_query, None).await.unwrap().unwrap(); + + // Get stash account of a non-signer, to become the new signer + // Since we only have 4 nodes in our test setup, this will be the same one the chain chooses + let new_signer = all_validators.iter().find(|v| !signer_stash_accounts.contains(v)).unwrap(); + let block_number = TEST_RESHARE_BLOCK_NUMBER; let onchain_reshare_request = - OcwMessageReshare { new_signer: dave.public().encode(), block_number }; + OcwMessageReshare { new_signer: new_signer.0.to_vec(), block_number }; run_to_block(&rpc, block_number + 1).await; - + // Send the OCW message to all TS servers who don't have a chain node let response_results = join_all( validator_ports[1..] .iter() @@ -107,14 +134,15 @@ async fn test_reshare() { assert_eq!(response_result.unwrap().text().await.unwrap(), ""); } - for i in 0..3 { + for (tss_account, key_share_and_aux_before) in key_shares_before.iter() { let (key_share_before, aux_info_before): KeyShareWithAuxInfo = - deserialize(&key_shares_before[i]).unwrap(); + deserialize(key_share_and_aux_before).unwrap(); - let key_share_and_aux_data_after = - unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), validator_ports[i]).await; + let port = get_port(signers.iter().find(|s| s.tss_account.0 == *tss_account).unwrap()); + let key_share_and_aux_after = + unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), port).await; let (key_share_after, aux_info_after): KeyShareWithAuxInfo = - deserialize(&key_share_and_aux_data_after).unwrap(); + deserialize(&key_share_and_aux_after).unwrap(); // Check key share has not yet changed assert_eq!(serialize(&key_share_before).unwrap(), serialize(&key_share_after).unwrap()); @@ -122,25 +150,36 @@ async fn test_reshare() { assert_eq!(serialize(&aux_info_before).unwrap(), serialize(&aux_info_after).unwrap()); } - // We add one here because after the reshare the siging committee has - // shifted from alice, bob, charlie to bob, charlie, dave - for i in 1..4 { + let new_signers = { + let signer_query = entropy::storage().staking_extension().signers(); + let signer_ids = query_chain(&api, &rpc, signer_query, None).await.unwrap().unwrap(); + let mut signers = Vec::new(); + for signer in signer_ids { + let query = entropy::storage().staking_extension().threshold_servers(signer); + let server_info = query_chain(&api, &rpc, query, None).await.unwrap().unwrap(); + signers.push(server_info); + } + signers + }; + + for signer in new_signers { let _ = client - .post(format!("http://127.0.0.1:{}/validator/rotate_network_key", validator_ports[i])) + .post(format!( + "http://{}/validator/rotate_network_key", + std::str::from_utf8(&signer.endpoint).unwrap() + )) .send() .await .unwrap(); let key_share_and_aux_data_after_rotate = - unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), validator_ports[i]).await; + unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), get_port(&signer)).await; let (key_share_after_rotate, aux_info_after_rotate): KeyShareWithAuxInfo = deserialize(&key_share_and_aux_data_after_rotate).unwrap(); - // We can only check if the first two keyshares changed as dave did not have a keyshare at - // all before - if i < 3 { + if let Some(key_share_and_aux_before) = key_shares_before.get(&signer.tss_account.0) { let (key_share_before, aux_info_before): KeyShareWithAuxInfo = - deserialize(&key_shares_before[i]).unwrap(); + deserialize(&key_share_and_aux_before).unwrap(); // Check key share has changed assert_ne!( serialize(&key_share_before).unwrap(), @@ -155,14 +194,17 @@ async fn test_reshare() { // calling twice doesn't do anything let response = client - .post(format!("http://127.0.0.1:{}/validator/rotate_network_key", validator_ports[i])) + .post(format!( + "http://{}/validator/rotate_network_key", + std::str::from_utf8(&signer.endpoint).unwrap() + )) .send() .await .unwrap(); assert_eq!(response.text().await.unwrap(), "Kv error: Recv Error: channel closed"); let key_share_and_aux_data_after_rotate_twice = - unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), validator_ports[i]).await; + unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), get_port(&signer)).await; let (key_share_after_rotate_twice, aux_info_after_rotate_twice): KeyShareWithAuxInfo = deserialize(&key_share_and_aux_data_after_rotate_twice).unwrap(); @@ -249,9 +291,8 @@ async fn test_reshare_none_called() { let _cxt = test_node_process_testing_state(true).await; - let add_parent_key_to_kvdb = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key_to_kvdb, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let validator_ports = vec![3001, 3002, 3003, 3004]; @@ -403,3 +444,8 @@ async fn test_deletes_key() { assert!(!has_key); clean_tests(); } + +/// Given a ServerInfo, get the port number +fn get_port(server_info: &ServerInfo) -> u32 { + std::str::from_utf8(&server_info.endpoint).unwrap().split(":").last().unwrap().parse().unwrap() +} diff --git a/crates/threshold-signature-server/tests/register_and_sign.rs b/crates/threshold-signature-server/tests/register_and_sign.rs index 21d6191c3..c2d8353dd 100644 --- a/crates/threshold-signature-server/tests/register_and_sign.rs +++ b/crates/threshold-signature-server/tests/register_and_sign.rs @@ -28,22 +28,24 @@ use entropy_testing_utils::{ }, jump_start_network, spawn_testing_validators, test_node_process_testing_state, ChainSpecType, }; +use entropy_tss::helpers::tests::initialize_test_logger; use serial_test::serial; use sp_core::{sr25519, Pair}; use sp_keyring::AccountKeyring; use subxt::{tx::PairSigner, utils::AccountId32}; use synedrion::k256::ecdsa::VerifyingKey; +#[ignore] #[tokio::test] #[serial] async fn integration_test_register_and_sign() { + initialize_test_logger().await; clean_tests(); let account_owner = AccountKeyring::Ferdie.pair(); let signature_request_author = AccountKeyring::One; - let add_parent_key = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; diff --git a/crates/threshold-signature-server/tests/sign_eth_tx.rs b/crates/threshold-signature-server/tests/sign_eth_tx.rs index b8392d039..6fb139ec4 100644 --- a/crates/threshold-signature-server/tests/sign_eth_tx.rs +++ b/crates/threshold-signature-server/tests/sign_eth_tx.rs @@ -43,6 +43,7 @@ use synedrion::k256::ecdsa::VerifyingKey; const GOERLI_CHAIN_ID: u64 = 5; +#[ignore] #[tokio::test] #[serial] async fn integration_test_sign_eth_tx() { @@ -50,9 +51,8 @@ async fn integration_test_sign_eth_tx() { let account_owner = AccountKeyring::Ferdie.pair(); let signature_request_author = AccountKeyring::One; - let add_parent_key = true; let (_validator_ips, _validator_ids) = - spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; + spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; diff --git a/node/cli/src/chain_spec/integration_tests.rs b/node/cli/src/chain_spec/integration_tests.rs index 5d7fc54ed..a922bc0e0 100644 --- a/node/cli/src/chain_spec/integration_tests.rs +++ b/node/cli/src/chain_spec/integration_tests.rs @@ -59,7 +59,7 @@ pub fn integration_tests_config() -> ChainSpec { get_account_id_from_seed::("Alice"), vec![ get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), ], )) .build() @@ -218,7 +218,7 @@ pub fn integration_tests_genesis_config( ], vec![EVE_VERIFYING_KEY.to_vec(), DAVE_VERIFYING_KEY.to_vec()], ), - mock_signer_rotate: (true, mock_signer_rotate_data, vec![get_account_id_from_seed::("Dave//stash")],), + mock_signer_rotate: (true, mock_signer_rotate_data, vec![get_account_id_from_seed::("Charlie//stash")],), }, "elections": ElectionsConfig { members: endowed_accounts From 9facf6eb7eafdad4a20f5d1698c69704e6d78837 Mon Sep 17 00:00:00 2001 From: JesseAbram <33698952+JesseAbram@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:56:17 -0400 Subject: [PATCH 04/17] Add `/relay_tx` endpoint (#1050) * add relay tx endpoint * working * redesign test * fix sig recovery check * add pre sign checks * add signer check * add validator checks * remove validator info from user sig req message * fixing tests * another test * fix user tests * more tests * clean * test * clean * fmt * fmt * docs * tests * fmt * fix tests * fix test * Apply suggestions from code review Co-authored-by: peg Co-authored-by: David * Update crates/threshold-signature-server/src/user/api.rs Co-authored-by: peg * move get_signers_from_chain * return option validator name * random selection * add validator checks * clean tests * tests * remove poping selected signers * fix * Apply suggestions from code review Co-authored-by: Hernando Castano Co-authored-by: peg * collapse user_sig_request into relayer request * Apply suggestions from code review Co-authored-by: Hernando Castano Co-authored-by: peg * clean * clean * clean * clean * Update crates/threshold-signature-server/src/user/tests.rs Co-authored-by: peg * clean * replace charlie with dave in key creation * fmt * lint * test fix --------- Co-authored-by: peg Co-authored-by: David Co-authored-by: Hernando Castano --- CHANGELOG.md | 6 + Cargo.lock | 1 + crates/client/Cargo.toml | 1 + crates/client/src/client.rs | 123 ++-- crates/client/src/user.rs | 73 +- .../dave-keyshare-held-by-alice.keyshare | Bin 0 -> 3472 bytes .../dave-keyshare-held-by-bob.keyshare | Bin 0 -> 3472 bytes .../dave-keyshare-held-by-dave.keyshare | Bin 0 -> 3472 bytes .../eve-keyshare-held-by-alice.keyshare | Bin 0 -> 3472 bytes .../eve-keyshare-held-by-bob.keyshare | Bin 0 -> 3472 bytes .../eve-keyshare-held-by-dave.keyshare | Bin 0 -> 3472 bytes .../test/dave-keyshare-held-by-alice.keyshare | Bin 0 -> 2192 bytes .../test/dave-keyshare-held-by-bob.keyshare | Bin 0 -> 2192 bytes .../dave-keyshare-held-by-charlie.keyshare | Bin 0 -> 2192 bytes .../test/eve-keyshare-held-by-alice.keyshare | Bin 0 -> 2192 bytes .../test/eve-keyshare-held-by-bob.keyshare | Bin 0 -> 2192 bytes .../eve-keyshare-held-by-charlie.keyshare | Bin 0 -> 2192 bytes .../src/create_test_keyshares.rs | 7 +- .../src/helpers/signing.rs | 10 +- .../src/helpers/substrate.rs | 57 ++ .../src/helpers/tests.rs | 20 +- crates/threshold-signature-server/src/lib.rs | 47 +- .../src/sign_init.rs | 4 +- .../src/user/api.rs | 337 ++++++++-- .../src/user/errors.rs | 10 + .../src/user/tests.rs | 621 +++++++++++++----- scripts/create-test-keyshares/src/main.rs | 6 +- 27 files changed, 1000 insertions(+), 323 deletions(-) create mode 100644 crates/testing-utils/keyshares/production/dave-keyshare-held-by-alice.keyshare create mode 100644 crates/testing-utils/keyshares/production/dave-keyshare-held-by-bob.keyshare create mode 100644 crates/testing-utils/keyshares/production/dave-keyshare-held-by-dave.keyshare create mode 100644 crates/testing-utils/keyshares/production/eve-keyshare-held-by-alice.keyshare create mode 100644 crates/testing-utils/keyshares/production/eve-keyshare-held-by-bob.keyshare create mode 100644 crates/testing-utils/keyshares/production/eve-keyshare-held-by-dave.keyshare create mode 100644 crates/testing-utils/keyshares/test/dave-keyshare-held-by-alice.keyshare create mode 100644 crates/testing-utils/keyshares/test/dave-keyshare-held-by-bob.keyshare create mode 100644 crates/testing-utils/keyshares/test/dave-keyshare-held-by-charlie.keyshare create mode 100644 crates/testing-utils/keyshares/test/eve-keyshare-held-by-alice.keyshare create mode 100644 crates/testing-utils/keyshares/test/eve-keyshare-held-by-bob.keyshare create mode 100644 crates/testing-utils/keyshares/test/eve-keyshare-held-by-charlie.keyshare diff --git a/CHANGELOG.md b/CHANGELOG.md index 22baf545b..299523c18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,11 @@ At the moment this project **does not** adhere to pallet. The genesis build config was also removed. Additionally, the `new/user/` HTTP endpoint in the TSS was removed since it was no longer necessary. - In [#1045](https://github.com/entropyxyz/entropy-core/pull/1045), `ProgramsInfo` now takes `version_number` to maintain backwards compatibility if programs runtime is updated +- In [#1050](https://github.com/entropyxyz/entropy-core/pull/1050), the flow for signing has changed. + A user now sends their request to any validator that is not a signer. This will act as a relayer. + As such, `UserSignatureRequest` no longer requires the `validators_info` field since the the + relayer adds that in after. The response received from the validator is now a `Vec` + from the signers. ### Added - Jumpstart network ([#918](https://github.com/entropyxyz/entropy-core/pull/918)) @@ -40,6 +45,7 @@ At the moment this project **does not** adhere to ### Changed - Fix TSS `AccountId` keys in chainspec ([#993](https://github.com/entropyxyz/entropy-core/pull/993)) +- Add relay tx endpoint ([#1050](https://github.com/entropyxyz/entropy-core/pull/1050)) ### Removed - Remove `prune_registration` extrinsic ([#1022](https://github.com/entropyxyz/entropy-core/pull/1022)) diff --git a/Cargo.lock b/Cargo.lock index 47bbaeff3..b7e2d384a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2494,6 +2494,7 @@ dependencies = [ "hex", "js-sys", "num", + "rand", "rand_core 0.6.4", "reqwest", "serde", diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index b04c1b679..5da179d02 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -18,6 +18,7 @@ thiserror ="1.0.64" futures ="0.3" sp-core ={ version="31.0.0", default-features=false, features=["full_crypto", "serde"] } tracing ="0.1.37" +rand ={ version="0.8", default-features=false } # Present when "full-client" feature is active blake2 ={ version="0.10.4", optional=true } diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index b5589c518..89c49514b 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -21,6 +21,7 @@ pub use crate::{ }; use anyhow::anyhow; pub use entropy_protocol::{sign_and_encrypt::EncryptedSignedMessage, KeyParams}; +use rand::Rng; use std::str::FromStr; pub use synedrion::KeyShare; @@ -38,17 +39,18 @@ use crate::{ }, client::entropy::staking_extension::events::{EndpointChanged, ThresholdAccountChanged}, substrate::{get_registered_details, submit_transaction_with_pair}, - user::{get_signers_from_chain, UserSignatureRequest}, + user::{get_all_signers_from_chain, get_validators_not_signer_for_relay, UserSignatureRequest}, Hasher, }; use base64::prelude::{Engine, BASE64_STANDARD}; use entropy_protocol::RecoverableSignature; use entropy_shared::HashingAlgorithm; -use futures::{future, stream::StreamExt}; +use futures::stream::StreamExt; use sp_core::{sr25519, Pair}; use subxt::{ backend::legacy::LegacyRpcMethods, + ext::sp_core::sr25519::Signature, utils::{AccountId32 as SubxtAccountId32, H256}, Config, OnlineClient, }; @@ -113,14 +115,13 @@ pub async fn sign( ) -> Result { let message_hash = Hasher::keccak(&message); - let validators_info = get_signers_from_chain(api, rpc).await?; + let validators_info = get_validators_not_signer_for_relay(api, rpc).await?; tracing::debug!("Validators info {:?}", validators_info); let block_number = rpc.chain_get_header(None).await?.ok_or(ClientError::BlockNumber)?.number; let signature_request = UserSignatureRequest { message: hex::encode(message), auxilary_data: Some(vec![auxilary_data.map(hex::encode)]), - validators_info: validators_info.clone(), block_number, hash: HashingAlgorithm::Keccak, signature_verifying_key: signature_verifying_key.to_vec(), @@ -129,70 +130,64 @@ pub async fn sign( let signature_request_vec = serde_json::to_vec(&signature_request)?; let client = reqwest::Client::new(); - // Make http requests to TSS servers - let submit_transaction_requests = validators_info - .iter() - .map(|validator_info| async { - let encrypted_message = EncryptedSignedMessage::new( - &user_keypair, - signature_request_vec.clone(), - &validator_info.x25519_public_key, - &[], - )?; - let message_json = serde_json::to_string(&encrypted_message)?; - - let url = format!("http://{}/user/sign_tx", validator_info.ip_address); - - let res = client - .post(url) - .header("Content-Type", "application/json") - .body(message_json) - .send() - .await; - Ok::<_, ClientError>(res) - }) - .collect::>(); - - // If we have a keyshare, connect to TSS servers - let results = future::try_join_all(submit_transaction_requests).await?; - - // Get the first result - if let Some(res) = results.into_iter().next() { - let output = res?; - if output.status() != 200 { - return Err(ClientError::SigningFailed(output.text().await?)); - } - - let mut bytes_stream = output.bytes_stream(); - let chunk = bytes_stream.next().await.ok_or(ClientError::NoResponse)??; - let signing_result: Result<(String, sr25519::Signature), String> = - serde_json::from_slice(&chunk)?; - let (signature_base64, signature_of_signature) = - signing_result.map_err(ClientError::SigningFailed)?; - tracing::debug!("Signature: {}", signature_base64); - let mut decoded_sig = BASE64_STANDARD.decode(signature_base64)?; - - // Verify the response signature from the TSS client - if !sr25519::Pair::verify( + let mut rng = rand::thread_rng(); + let random_index = rng.gen_range(0..validators_info.len()); + let validator_info = &validators_info[random_index]; + + // Make http request to TSS server + let encrypted_message = EncryptedSignedMessage::new( + &user_keypair, + signature_request_vec.clone(), + &validator_info.x25519_public_key, + &[], + )?; + let message_json = serde_json::to_string(&encrypted_message)?; + + let url = format!("http://{}/user/relay_tx", validator_info.ip_address); + + let result = client + .post(url) + .header("Content-Type", "application/json") + .body(message_json) + .send() + .await?; + + let mut bytes_stream = result.bytes_stream(); + let chunk = bytes_stream.next().await.ok_or(ClientError::NoResponse)??; + let signing_results: Vec> = serde_json::from_slice(&chunk)?; + // take only one of the responses randomly + let mut rng = rand::thread_rng(); + let random_index = rng.gen_range(0..signing_results.len()); + let (signature_base64, signature_of_signature) = + signing_results[random_index].clone().map_err(ClientError::SigningFailed)?; + tracing::debug!("Signature: {}", signature_base64); + let mut decoded_sig = BASE64_STANDARD.decode(signature_base64)?; + + // Verify the response signature from the TSS client + let signers = get_all_signers_from_chain(api, rpc).await?; + let mut sig_recovery_results = vec![]; + for signer_info in signers { + let sig_recovery = ::verify( &signature_of_signature, - &decoded_sig, - &sr25519::Public(validators_info[0].tss_account.0), - ) { - return Err(ClientError::BadSignature); - } + decoded_sig.clone(), + &sr25519::Public(signer_info.tss_account.0), + ); + sig_recovery_results.push(sig_recovery) + } - let recovery_digit = decoded_sig.pop().ok_or(ClientError::NoRecoveryId)?; - let signature = k256Signature::from_slice(&decoded_sig)?; - let recovery_id = - RecoveryId::from_byte(recovery_digit).ok_or(ClientError::BadRecoveryId)?; + if !sig_recovery_results.contains(&true) { + return Err(ClientError::BadSignature); + } - let verifying_key_of_signature = - VerifyingKey::recover_from_prehash(&message_hash, &signature, recovery_id)?; - tracing::debug!("Verifying Key {:?}", verifying_key_of_signature); + let recovery_digit = decoded_sig.pop().ok_or(ClientError::NoRecoveryId)?; + let signature = k256Signature::from_slice(&decoded_sig)?; + let recovery_id = RecoveryId::from_byte(recovery_digit).ok_or(ClientError::BadRecoveryId)?; - return Ok(RecoverableSignature { signature, recovery_id }); - } - Err(ClientError::NoResponse) + let verifying_key_of_signature = + VerifyingKey::recover_from_prehash(&message_hash, &signature, recovery_id)?; + tracing::debug!("Verifying Key {:?}", verifying_key_of_signature); + + return Ok(RecoverableSignature { signature, recovery_id }); } /// Store a program on chain and return it's hash diff --git a/crates/client/src/user.rs b/crates/client/src/user.rs index 1c018fad2..9b4aa101b 100644 --- a/crates/client/src/user.rs +++ b/crates/client/src/user.rs @@ -30,8 +30,6 @@ pub struct UserSignatureRequest { pub message: String, /// Hex-encoded auxilary data for program evaluation, will not be signed (eg. zero-knowledge proof, serialized struct, etc) pub auxilary_data: Option>>, - /// Information from the validators in signing party - pub validators_info: Vec, /// When the message was created and signed pub block_number: BlockNumber, /// Hashing algorithm to be used for signing @@ -40,24 +38,32 @@ pub struct UserSignatureRequest { pub signature_verifying_key: Vec, } -pub async fn get_signers_from_chain( +/// Represents an unparsed transaction request coming from a relayer to a signer. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct RelayerSignatureRequest { + // Request relayed from user to signer + pub user_signature_request: UserSignatureRequest, + /// Information for the validators in the signing party + pub validators_info: Vec, +} + +/// Gets a validator from chain to relay a message to the signers +/// Filters out all signers +pub async fn get_validators_not_signer_for_relay( api: &OnlineClient, rpc: &LegacyRpcMethods, ) -> Result, SubgroupGetError> { let signer_query = entropy::storage().staking_extension().signers(); - let mut validators = query_chain(api, rpc, signer_query, None) + let signers = query_chain(api, rpc, signer_query, None) .await? .ok_or_else(|| SubgroupGetError::ChainFetch("Get all validators error"))?; - let key_info_query = entropy::storage().parameters().signers_info(); - let threshold = query_chain(api, rpc, key_info_query, None) + let validators_query = entropy::storage().session().validators(); + let mut validators = query_chain(api, rpc, validators_query, None) .await? - .ok_or_else(|| SubgroupGetError::ChainFetch("Failed to get signers info"))? - .threshold; - - // TODO #899 For now we just take the first t validators as the ones to perform signing - validators.truncate(threshold as usize); + .ok_or_else(|| SubgroupGetError::ChainFetch("Error getting validators"))?; + validators.retain(|validator| !signers.contains(validator)); let block_hash = rpc.chain_get_block_hash(None).await?; let mut handles = Vec::new(); @@ -85,6 +91,51 @@ pub async fn get_signers_from_chain( handles.push(handle); } + let mut all_validators: Vec = vec![]; + for handle in handles { + all_validators.push(handle.await??); + } + + Ok(all_validators) +} + +/// Gets all signers from chain +pub async fn get_all_signers_from_chain( + api: &OnlineClient, + rpc: &LegacyRpcMethods, +) -> Result, SubgroupGetError> { + let signer_query = entropy::storage().staking_extension().signers(); + let signers = query_chain(api, rpc, signer_query, None) + .await? + .ok_or_else(|| SubgroupGetError::ChainFetch("Get all validators error"))?; + + let block_hash = rpc.chain_get_block_hash(None).await?; + let mut handles = Vec::new(); + + for signer in signers { + let handle: tokio::task::JoinHandle> = + tokio::task::spawn({ + let api = api.clone(); + let rpc = rpc.clone(); + async move { + let threshold_address_query = + entropy::storage().staking_extension().threshold_servers(signer); + let server_info = query_chain(&api, &rpc, threshold_address_query, block_hash) + .await? + .ok_or_else(|| { + SubgroupGetError::ChainFetch("threshold_servers query error") + })?; + Ok(ValidatorInfo { + x25519_public_key: server_info.x25519_public_key, + ip_address: std::str::from_utf8(&server_info.endpoint)?.to_string(), + tss_account: server_info.tss_account, + }) + } + }); + + handles.push(handle); + } + let mut all_signers: Vec = vec![]; for handle in handles { all_signers.push(handle.await??); diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-held-by-alice.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..1e3aedf1d54ecd3ad100a6930acd7fbb063bb22c GIT binary patch literal 3472 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 JtuW*2e*nqs6RQ9K literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-held-by-bob.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-held-by-bob.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..2176adf506710028b355e9d88ecf3b25b80f0559 GIT binary patch literal 3472 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 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-held-by-dave.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-held-by-dave.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..24c31777057e8dec19c7e92a1475635e1fdcc1ee GIT binary patch literal 3472 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 HTD<-PR~0r5 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/eve-keyshare-held-by-dave.keyshare b/crates/testing-utils/keyshares/production/eve-keyshare-held-by-dave.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..8f8d8a98e913cead294b0d666b89c55107fbfda3 GIT binary patch literal 3472 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 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/dave-keyshare-held-by-bob.keyshare b/crates/testing-utils/keyshares/test/dave-keyshare-held-by-bob.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..f1e36e8c1ff16f3104651d28fc99651dc5c511ca GIT binary patch literal 2192 zcmbVMYd8~n9M(o{(kh`kN!Cp+r^hmvm2GxoW>Yi6*xYR{yO_B|DKaCXMJ3%6x!;#^ zlteDYTq~6nx=2MXnIq9TU!4znoZq+i!|#26@Be+Dzp*LaloDa)?Cl)EV8ducggxEQ z$%)8gBWNTVk%X`d@Cl`x;6(%~EHuE(kM0f7HPn)KZW6x;K5)-9uY`34`yaha^VC;5nW9j za0n_6OY^4?f5!-1zHKNlMWkK;&G?a$9AXFM5JYUO_KlDedO;swUFD6ddc6fL+cy;8 z-07S%6gH{_0ZAtOC0ht9JCZBXS|_h)R=v7&i*M|=Y~xUX(M(-P`qQNTb`d+d6H!3~ zC(KnQ&Gh5$`ftCLR{S+<*;jHp^tqdY3qWGMbs2@HI-c9{xj)6nEE0>MRoC!Me^lb` z_VylB?z@z$#6y_G1<|3}i~BLG>^=apy%dcg{Ho+iXnG5RojI85lh!eMhN-i2aLRex zImS)4Dh@Uz7sejKFhE-t@9VC|3_nSgUT9%v!$O?B6-f6Js6vZqC!4P4YIEwV3Mc>nxwjYte;x&K z5>NT`UU(A!t{oViS^8zxiZT>r^)m4;YH}Z)4Ps4HXZ`i1(4IlI{w_< zHdE+YbfOx)Otm)WE>h>G!FmH%^Y?GkbJ|>&)Nj9IbsdqZ0Uhf@2J#j6jV9M+&7CWh zV+~7J8670H_~pgg{; zPZ(|ax^hjSrxA-Y9L(FlFXof2#mSv! z2Xne83eTkcd$&bm$@@FN1mQPKlaB_O6je35gYkId(At<_#ivR8tvV>TCm%g2t$STP zdxQF}+A4%g>Z1k^AYq4}@M~11H>3emv{f}i?tQ)Dif)||dYj|b(|NeihGD2tDB!y0E^YMyW;qtjYtDtazqCA?t=Xum6HaI~>X<5uH%_TxIW&%Jb>FnH z4Ae#AT^LGfKC(LQQRgP=v#R!o3p)?P!Z8S4v_r#wQrF=~N$tc8lf=j4cn}%55ZbgM z4VPIuZGiB`oA;xu)gYaA-{4tb%zT5hFBPzD-MSC zd>m7*byv=VDkU&OQt!oZ)Wkk@Xtwk`fMsXyu!Ld^kJ|dP{vt{jwcrKisLf=%X6Rke+nd9&MK2 zG|^+v_#_*kq{o-vG;K|wonU$$cTseKR3X0Lr=vN_WA!B#f>CT^=2ngh&`q=bj7z&H l$x8jxz8?kiso4^}J;s8|+XEp5^?^j=52d1`i#z-u^bh8m5(EGM literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/dave-keyshare-held-by-charlie.keyshare b/crates/testing-utils/keyshares/test/dave-keyshare-held-by-charlie.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..b9cdbc7a2b6cf6a95c33dd2ea1a4eee2c5d6d8a1 GIT binary patch literal 2192 zcmbVMYdq5n7_N<&G!dy^TBanIIxa(t88)oHOJ;^K<+crDGjrEHMjUdf(65M0ZgX81 zO>(DPLZU(lMdhAJMdy5VKIrGX-<}We^ZcIodEZx47XvtBv2;DUl`W2BNk?Mv;Y`4k z?aK-#B25TR7WznY0BdatczB0vxm!6I1YF zr|QmH`t*Y}H_NHGW#ihasf*RM4%Kt?a113;wFo$*4UyvDfb*v!2><~HAT517gNQm< zwi#Y4$VZPt^!O7a=wC(?3uqHNFd3frG^S ztc+V8!aVj?%1hyW&DnI`^sNb!ja<07O|EZYYFwc0ccsz!105;=1~E}QINn3)t9!y3 z%W@pTf2SthS{VNb+rNH4mL+R>!_~sXZa-&%t-QJc{f%mYSW_ziTCp{+@9XO==Gilj zHkzasiwTucAv%dN((C&b_qNJ&!xcxPJ0B!R7EqW{?_kQ4b|h7$Ch;7+cMGXB_~k49 z>mA8yv3yze*mFTO!TM`vbI@m3#uz24^IO;3T#xuS>S=7JD_@Nb6$|FfeuFsWeykgx zPW{AAF;Bd%%s8~`h%vqvx4S4hidg5zHym(SxVaiqj6Sxce8IlSR=n27Dm4n`?RVH> z5nY3hl_Zu))Nmi8V87I))tvRm-=}ihoj26)d}MqVnIQ|G89@0mgikdVcIN!NQPg3o zUbp6$BFsyH^p^kF9 zt%YuJ1=SCX7XR)sD3zQd-=Tz#fWE39*DoGfOgl5mM0AuKE$hULf-PaAx);}mJ(F}1 z%>#_@p!FfHN2d9S%4F3BE>rgHlxsOV;+bf4y?tAMNLS?TfS6YT_n%$tJLJaXB-ug# zfs9m6w%VnHrG=*lA!e*ulV(p@DFy|)aq)aTzmD*zIj<6iZr zNH_Py;h?*6$_g?*(F+ecu>eyWu1*z2*6?~i# zsW~l@58o0)4os}RNRy26tVL6kZh~BmuZeeDb^&4!aMDhSliu>I@BeCr9Qg3Q)@mOX z=B0{a~R(^vUoXIs!B_do>*L@+#0W<&k5gV!e>RowEF2qz_7wNpB$SI|8F z%7!$_AF)o2F2ASS7DKp9cE8{x>=u`RdO>=pxgs<5CC8c5rcD|9X`)~kxz1##PIjEJ j%%t{@!qvoFj>-{D=4~ZkXkooCPIID^eRlm0{|Eg82$~#V literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/eve-keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/test/eve-keyshare-held-by-alice.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..4281330bc501088e8710623eb15741294abf0859 GIT binary patch literal 2192 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 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/eve-keyshare-held-by-charlie.keyshare b/crates/testing-utils/keyshares/test/eve-keyshare-held-by-charlie.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..c5537a9d5d4a5d3c2ffc2fd998d048bd9135a584 GIT binary patch literal 2192 zcmbW1c{~$*9LIBYjfav4HEVO`$|PfMh8i&S9i6_{w86uIP=1c~7Gyi58O6ul-8{@g9frjaJZYCuP8zld zxDCPt=VgWZl_THYV?%gl!Q`YHbmVxPvgpDPuDS2zIS#+LT$SEo?bt(hPo;6YybH^zJ}s%^Yegnt9BcfUv3b8rY>WCkFZ83pyUxgaZZ4T*MZ zvQ|lnn6$E@(3P7fbq;jzx$i+0D$B}$ZhG4~>gLb|#z)^%Al>)*#29m7T$OeC#;v1l ze2TpD)QwN=Wd_Mw?tj#a?7WXn9Ex@oCh%P^e_o%io8OrYyU;S26dd+tt8(t=m#^Nv zp}y=&&3974Pt`);!13$Fk~{aok!d-`osqWumlb-6HEAb~d{J`ABGW!4dTrC&*w!<} zztg3hxt&uO8dS~d>XNGP-SVKqy(JrgpHi1efH>HLDuXq^8)tBgK))t;9zXEzXHcuS zERnsHqirmzBR-Iz6YnW#SkVx3i6CSbKlM^qRx$MfX4#^HFw+Kz9~2|?HLA9|^y)*Xul^Fkysz+lwHRh>#1&ey*MK%7lv zxGCym$)jY>T8b4Yl)vIx4>WMz_jK9IQIButk-PH8U3z0JXNj+toT}2<6<9>fd1Og+ zoq+MsIZ>pdceZ9PGMU~kB;HwYJ8*vzD@Pdun1-Z-wseSZ$?GQ+v~#=!gH%_SEaxP2 ztEgl3kbji=qtEdC$jMx*vTH}evV~Smdt0ANo#|F=`l~i}?6{j#HM+y5 zfqPc!B+=>4$q+^KDzX1F)KJTF@mX3*u#j`*yL2-f9_eeUp-95#x{gud(EEVu!pTv! z>_)q{j_YkgInFW2rlJbyHk+^Jm7d|b7>7;%b!w6r!*ho08)Kvk+$4e4E)$visnSYJ*NcWJRGl_`|7 zPK^ajOh>NgZuGTkm32CtE82=^pFhlvY0FFRI)CLxpOmJG^y*5N|`I6&TLwaNHrL(mWQV zVg8a|Rl2uN9Kr`uXB_T-p{AV$?r(HEOvx|IE>0L^prrJh9l1^#r4;t+^R~RHBd^Pq z($gie3y$4fIa^&d26WJ*qlJ6$m`owQ_J^v1?^;5Gw$8{gVICQGAEml)z|ED?M~0_R z2vl@qFf$4FQ0m_4PE`qM@~yJmd%+^MtBUp>Mlp-Spt0fNTn0{%W?Q2cJ(ZL-%yGd0--Bq|Lo+oBf9}d3A#CxD2a4(bGsU#?J$5MD zWWQm~Qo17{h{|y`c}64Ciht{)JbU9I%EA09@yV^|LP=#-kXti1yeJoqQIrx mBr%~XT_2tZ>P0mcfD<{LlkF0)&3EOR-+BmNh1P+)^8W?e;uZ%0 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/src/create_test_keyshares.rs b/crates/testing-utils/src/create_test_keyshares.rs index c3bf53d6b..7b80de562 100644 --- a/crates/testing-utils/src/create_test_keyshares.rs +++ b/crates/testing-utils/src/create_test_keyshares.rs @@ -38,18 +38,19 @@ where Params: SchemeParams, { let signing_key = SigningKey::from_bytes(&(distributed_secret_key_bytes).into()).unwrap(); - let signers = vec![alice.clone(), bob, charlie.clone()]; + let signers = vec![alice.clone(), bob.clone(), charlie.clone()]; let session_id = SessionId::from_seed(b"12345".as_slice()); let all_parties = signers.iter().map(|pair| PartyId::from(pair.public())).collect::>(); - let old_holders = all_parties.clone().into_iter().take(2).collect::>(); + let mut old_holders = all_parties.clone(); + old_holders.remove(&PartyId::from(charlie.clone().public())); let keyshares = KeyShare::::new_centralized(&mut OsRng, &old_holders, Some(&signing_key)); let aux_infos = AuxInfo::::new_centralized(&mut OsRng, &all_parties); - let alice_id = PartyId::from(alice.public()); + let alice_id = PartyId::from(bob.public()); let new_holder = NewHolder { verifying_key: keyshares[&alice_id].verifying_key(), old_threshold: 2, diff --git a/crates/threshold-signature-server/src/helpers/signing.rs b/crates/threshold-signature-server/src/helpers/signing.rs index ba8856d5c..609dde2f2 100644 --- a/crates/threshold-signature-server/src/helpers/signing.rs +++ b/crates/threshold-signature-server/src/helpers/signing.rs @@ -17,7 +17,7 @@ pub use entropy_client::Hasher; use std::time::Duration; -use entropy_client::user::UserSignatureRequest; +use entropy_client::user::RelayerSignatureRequest; use entropy_protocol::{Listener, RecoverableSignature, SessionId, SigningSessionInfo}; use entropy_shared::SETUP_TIMEOUT_SECONDS; use sp_core::Pair; @@ -41,7 +41,7 @@ use crate::{ #[tracing::instrument(skip(app_state), level = tracing::Level::DEBUG)] pub async fn do_signing( rpc: &LegacyRpcMethods, - user_signature_request: UserSignatureRequest, + relayer_signature_request: RelayerSignatureRequest, app_state: &AppState, signing_session_info: SigningSessionInfo, request_limit: u32, @@ -52,7 +52,7 @@ pub async fn do_signing( let state = &app_state.listener_state; let kv_manager = &app_state.kv_store; - let info = SignInit::new(user_signature_request.clone(), signing_session_info.clone()); + let info = SignInit::new(relayer_signature_request.clone(), signing_session_info.clone()); let signing_service = ThresholdSigningService::new(state, kv_manager); let (pair_signer, x25519_secret_key) = get_signer_and_x25519_secret(kv_manager) .await @@ -64,7 +64,7 @@ pub async fn do_signing( // Set up context for signing protocol execution let sign_context = signing_service.get_sign_context(info.clone(), derivation_path).await?; - let tss_accounts: Vec = user_signature_request + let tss_accounts: Vec = relayer_signature_request .validators_info .iter() .map(|validator_info| validator_info.tss_account.clone()) @@ -72,7 +72,7 @@ pub async fn do_signing( // subscribe to all other participating parties. Listener waits for other subscribers. let (rx_ready, rx_from_others, listener) = - Listener::new(user_signature_request.validators_info, &account_id); + Listener::new(relayer_signature_request.validators_info, &account_id); let session_id = SessionId::Sign(sign_context.sign_init.signing_session_info.clone()); diff --git a/crates/threshold-signature-server/src/helpers/substrate.rs b/crates/threshold-signature-server/src/helpers/substrate.rs index 8a937b249..a23da6503 100644 --- a/crates/threshold-signature-server/src/helpers/substrate.rs +++ b/crates/threshold-signature-server/src/helpers/substrate.rs @@ -28,6 +28,7 @@ use crate::{ }; pub use entropy_client::substrate::{query_chain, submit_transaction}; use entropy_shared::user::ValidatorInfo; +use rand::prelude::SliceRandom; use subxt::{backend::legacy::LegacyRpcMethods, utils::AccountId32, Config, OnlineClient}; /// Given a threshold server's account ID, return its corresponding stash (validator) address. @@ -108,3 +109,59 @@ pub async fn get_validators_info( } Ok(all_signers) } + +/// Returns a threshold of signer's ValidatorInfo from the chain +pub async fn get_signers_from_chain( + api: &OnlineClient, + rpc: &LegacyRpcMethods, +) -> Result<(Vec, Vec), UserErr> { + let signer_query = entropy::storage().staking_extension().signers(); + let signers = query_chain(api, rpc, signer_query, None) + .await? + .ok_or_else(|| UserErr::ChainFetch("Get all validators error"))?; + + let key_info_query = entropy::storage().parameters().signers_info(); + let threshold = query_chain(api, rpc, key_info_query, None) + .await? + .ok_or_else(|| UserErr::ChainFetch("Failed to get signers info"))? + .threshold; + + let selected_signers: Vec<_> = { + let cloned_signers = signers.clone(); + cloned_signers + .choose_multiple(&mut rand::thread_rng(), threshold as usize) + .cloned() + .collect() + }; + + let block_hash = rpc.chain_get_block_hash(None).await?; + let mut handles = Vec::new(); + + for signer in selected_signers { + let handle: tokio::task::JoinHandle> = tokio::task::spawn({ + let api = api.clone(); + let rpc = rpc.clone(); + async move { + let threshold_address_query = + entropy::storage().staking_extension().threshold_servers(signer); + let server_info = query_chain(&api, &rpc, threshold_address_query, block_hash) + .await? + .ok_or_else(|| UserErr::ChainFetch("threshold_servers query error"))?; + Ok(ValidatorInfo { + x25519_public_key: server_info.x25519_public_key, + ip_address: std::str::from_utf8(&server_info.endpoint)?.to_string(), + tss_account: server_info.tss_account, + }) + } + }); + + handles.push(handle); + } + + let mut all_selected_signers: Vec = vec![]; + for handle in handles { + all_selected_signers.push(handle.await??); + } + + Ok((all_selected_signers, signers)) +} diff --git a/crates/threshold-signature-server/src/helpers/tests.rs b/crates/threshold-signature-server/src/helpers/tests.rs index 172f9ab31..b523072ab 100644 --- a/crates/threshold-signature-server/src/helpers/tests.rs +++ b/crates/threshold-signature-server/src/helpers/tests.rs @@ -210,14 +210,22 @@ pub async fn spawn_testing_validators( } /// Add the pre-generated test keyshares to a kvdb -async fn put_keyshares_in_db(index: usize, validator_name: ValidatorName) { +async fn put_keyshares_in_db(_index: usize, validator_name: ValidatorName) { // Eve's keyshares are used as the network parent key let user_name = "eve"; + + let string_validator_name = match validator_name { + ValidatorName::Alice => "alice", + ValidatorName::Bob => "bob", + ValidatorName::Charlie => "charlie", + ValidatorName::Dave => "dave", + ValidatorName::Eve => "eve", + }; let keyshare_bytes = { let project_root = project_root::get_project_root().expect("Error obtaining project root."); let file_path = project_root.join(format!( - "crates/testing-utils/keyshares/production/{}-keyshare-{}.keyshare", - user_name, index + "crates/testing-utils/keyshares/production/{}-keyshare-held-by-{}.keyshare", + user_name, string_validator_name )); std::fs::read(file_path).unwrap() }; @@ -278,12 +286,13 @@ pub async fn jump_start_network_with_signer( api: &OnlineClient, rpc: &LegacyRpcMethods, signer: &PairSigner, -) { +) -> Option { let jump_start_request = entropy::tx().registry().jump_start_network(); let _result = submit_transaction(api, rpc, signer, &jump_start_request, None).await.unwrap(); let validators_names = vec![ValidatorName::Alice, ValidatorName::Bob, ValidatorName::Charlie, ValidatorName::Dave]; + let mut non_signer = None; let mut keyshare_index = 0; for validator_name in validators_names { let mnemonic = development_mnemonic(&Some(validator_name)); @@ -299,8 +308,11 @@ pub async fn jump_start_network_with_signer( { put_keyshares_in_db(keyshare_index, validator_name).await; keyshare_index += 1; + } else { + non_signer = Some(validator_name); } } + non_signer } /// Helper to store a program and register a user. Returns the verify key and program hash. diff --git a/crates/threshold-signature-server/src/lib.rs b/crates/threshold-signature-server/src/lib.rs index ea1ed07d9..960ccd47d 100644 --- a/crates/threshold-signature-server/src/lib.rs +++ b/crates/threshold-signature-server/src/lib.rs @@ -32,17 +32,57 @@ //! is an encrypted, signed message. //! //! -//! #### `/user/sign_tx` - POST +//! #### `/user/relay_tx` - POST //! -//! [crate::user::api::sign_tx()] +//! [crate::user::api::relay_tx()] //! -//! Called by a user to submit a transaction to sign (the new way of doing signing). Takes a +//! Called by a user to submit a transaction to sign. Takes a //! [UserSignatureRequest] encrypted in a [SignedMessage](crate::validation::SignedMessage). //! +//! Picks signers and gets them to sign a message then returns the responses to the user. +//! //! The response is chunked response stream. If the `UserSignatureRequest` could be processed, a //! success response header is sent. Then the signing protocol runs. When the it finishes, a single //! message will be sent on the response stream with the result. //! +//! If everything went well, the message will be a vector of JSON objects with a signle property "Ok" +//! containing an array which contains two strings. Each element in the vector is a response from a signer. +//! +//! For example: +//! +//! `[{"Ok":["t7Mcxfdigds3RoT6OO/P+uMFE+XigRjUpn72E1cRU4Q2u7cVxZlsNRYhnahA+DvSNHBddj0HRz5u/XPlJT9QOQE=","32d7c0bfd90b546993d1ad51c542e1fc9dd1706c7bca395c8bd7f9642ae842400769488404dabd25d438cf08785a6750f95e7489245b8760af115f450d5f0a83"]}]` +//! +//! The first string is a base64 encoded signature produced by the signing protocol. This is a 65 +//! byte signature, the final byte of which is a +//! [recovery ID](https://docs.rs/synedrion/latest/synedrion/ecdsa/struct.RecoveryId.html). +//! +//! The second string is a hex encoded sr25519 signature of the signature made by the TSS server, +//! which can be used to authenticate that this response really came from this TSS server. +//! +//! In case signing was not successfull, the message will be a JSON object with a signle property "Err" +//! containing an error message, for example: +//! +//! "[{\"Err\":\"Too many requests - wait a block\"},{\"Err\":\"Too many requests - wait a block\"}]" +//! +//! Curl example for `user/sign_tx`: +//! ```text +//! curl -X POST -H "Content-Type: application/json" \ +//! -d '{"msg" "0x174...hex encoded signedmessage...","sig":"821754409744cbb878b44bd1e3dc575a4ea721e12d781b074fcdb808fc79fd33dd1928b1a281c0b6261a30536a7c0106a102f27dad1bc3ef475b626f0e57c983","pk":[172,133,159,138,33,110,235,27,50,11,76,118,209,24,218,61,116,7,250,82,52,132,208,169,128,18,109,59,77,13,34,10],"recip":[10,192,41,240,184,83,178,59,237,101,45,109,13,230,155,124,195,141,148,249,55,50,238,252,133,181,134,30,144,247,58,34],"a":[169,94,23,7,19,184,134,70,233,117,2,84,242,135,246,95,159,14,218,125,209,191,175,89,41,196,182,96,117,5,159,98],"nonce":[114,93,158,35,209,188,96,248,85,131,95,237]}' \ +//! -H "Accept: application/json" \ +//! http://127.0.0.1:3001/user/relay_tx +//! ``` +//! +//! #### `/user/sign_tx` - POST +//! +//! [crate::user::api::sign_tx()] +//! +//! Called by a relayer to submit a transaction to sign. Takes a +//! [RelayerSignatureRequest] encrypted in a [SignedMessage](crate::validation::SignedMessage). +//! +//! The response is chunked response stream. If the `RelayerSignatureRequest` could be processed, a +//! success response header is sent. Then the signing protocol runs. When the it finishes, a single +//! message will be sent on the response stream with the result. +//! //! If everything went well, the message will be a JSON object with a signle property "Ok" //! containing an array which contains two strings. //! @@ -169,6 +209,7 @@ pub fn app(app_state: AppState) -> Router { let mut routes = Router::new() .route("/generate_network_key", post(generate_network_key)) .route("/user/sign_tx", post(sign_tx)) + .route("/user/relay_tx", post(relay_tx)) .route("/signer/proactive_refresh", post(proactive_refresh)) .route("/validator/reshare", post(new_reshare)) .route("/validator/rotate_network_key", post(rotate_network_key)) diff --git a/crates/threshold-signature-server/src/sign_init.rs b/crates/threshold-signature-server/src/sign_init.rs index e73910ae9..b8d98f5cf 100644 --- a/crates/threshold-signature-server/src/sign_init.rs +++ b/crates/threshold-signature-server/src/sign_init.rs @@ -17,7 +17,7 @@ use entropy_protocol::{SigningSessionInfo, ValidatorInfo}; use serde::{Deserialize, Serialize}; -use entropy_client::user::UserSignatureRequest; +use entropy_client::user::RelayerSignatureRequest; /// Information passed to the Signing Client, to initiate the signing process. /// Most of this information comes from a `Message` struct which gets propagated when a user's @@ -33,7 +33,7 @@ pub struct SignInit { impl SignInit { /// Creates new signing object based on passed in data #[allow(dead_code)] - pub fn new(message: UserSignatureRequest, signing_session_info: SigningSessionInfo) -> Self { + pub fn new(message: RelayerSignatureRequest, signing_session_info: SigningSessionInfo) -> Self { Self { signing_session_info, validators_info: message.validators_info } } } diff --git a/crates/threshold-signature-server/src/user/api.rs b/crates/threshold-signature-server/src/user/api.rs index 2b779be3e..f6da63a1b 100644 --- a/crates/threshold-signature-server/src/user/api.rs +++ b/crates/threshold-signature-server/src/user/api.rs @@ -13,13 +13,17 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::{str::FromStr, sync::Arc, time::SystemTime}; +use std::{ + str::{from_utf8, FromStr}, + sync::Arc, + time::SystemTime, +}; use axum::{ body::{Body, Bytes}, extract::State, http::StatusCode, - response::IntoResponse, + response::{IntoResponse, Response}, routing::{get, post}, Json, Router, }; @@ -40,8 +44,9 @@ use entropy_shared::{ }; use futures::{ channel::mpsc, - future::{join_all, FutureExt}, - Stream, + future::{join_all, try_join_all, FutureExt}, + stream::TryStreamExt, + Stream, StreamExt, }; use num::{bigint::BigInt, FromPrimitive, Num, ToPrimitive}; use parity_scale_codec::{Decode, DecodeAll, Encode}; @@ -62,13 +67,15 @@ use x25519_dalek::StaticSecret; use zeroize::Zeroize; use super::{ParsedUserInputPartyInfo, ProgramError, UserErr, UserInputPartyInfo}; +use crate::chain_api::entropy::runtime_types::pallet_registry::pallet::RegisteredInfo; use crate::{ chain_api::{entropy, get_api, get_rpc, EntropyConfig}, helpers::{ launch::LATEST_BLOCK_NUMBER_NEW_USER, signing::{do_signing, Hasher}, substrate::{ - get_oracle_data, get_program, get_stash_address, query_chain, submit_transaction, + get_oracle_data, get_program, get_signers_from_chain, get_stash_address, + get_validators_info, query_chain, submit_transaction, }, user::{check_in_registration_group, compute_hash, do_dkg}, validator::{get_signer, get_signer_and_x25519_secret}, @@ -79,7 +86,7 @@ use crate::{ AppState, Configuration, }; -pub use entropy_client::user::{get_signers_from_chain, UserSignatureRequest}; +pub use entropy_client::user::{RelayerSignatureRequest, UserSignatureRequest}; pub const REQUEST_KEY_HEADER: &str = "REQUESTS"; /// Type for validators to send user key's back and forth @@ -106,6 +113,137 @@ pub struct RequestLimitStorage { /// Called by a user to initiate the signing process for a message /// /// Takes an [EncryptedSignedMessage] containing a JSON serialized [UserSignatureRequest] +/// +/// Chooses signers and relays transactions to them and then results back to user +#[tracing::instrument(skip_all, fields(request_author))] +pub async fn relay_tx( + State(app_state): State, + Json(encrypted_msg): Json, +) -> Result<(StatusCode, Body), UserErr> { + let (signer, x25519_secret) = get_signer_and_x25519_secret(&app_state.kv_store).await?; + let api = get_api(&app_state.configuration.endpoint).await?; + let rpc = get_rpc(&app_state.configuration.endpoint).await?; + + // make sure is a validator and not a signer + let validators_query = entropy::storage().session().validators(); + let validators = query_chain(&api, &rpc, validators_query, None) + .await? + .ok_or_else(|| UserErr::ChainFetch("Error getting validators"))?; + + let validators_info = get_validators_info(&api, &rpc, validators).await?; + + validators_info + .iter() + .find(|validator| validator.tss_account == *signer.account_id()) + .ok_or_else(|| UserErr::NotValidator)?; + + let (selected_signers, all_signers) = get_signers_from_chain(&api, &rpc).await?; + + let signers_info = get_validators_info(&api, &rpc, all_signers).await?; + + signers_info + .iter() + .find(|signer_info| signer_info.tss_account == *signer.account_id()) + .map_or(Ok(()), |_| Err(UserErr::RelayMessageSigner))?; + + let signed_message = encrypted_msg.decrypt(&x25519_secret, &[])?; + + tracing::Span::current().record("request_author", signed_message.account_id().to_string()); + + let user_signature_request: UserSignatureRequest = + serde_json::from_slice(&signed_message.message.0)?; + let relayer_sig_req = + RelayerSignatureRequest { user_signature_request, validators_info: selected_signers }; + let block_number = rpc + .chain_get_header(None) + .await? + .ok_or_else(|| UserErr::OptionUnwrapError("Error Getting Block Number".to_string()))? + .number; + + let string_verifying_key = + hex::encode(relayer_sig_req.user_signature_request.signature_verifying_key.clone()); + + let _ = pre_sign_checks( + &api, + &rpc, + relayer_sig_req.user_signature_request.clone(), + block_number, + string_verifying_key, + ) + .await?; + + // relay message + let (mut response_tx, response_rx) = mpsc::channel(1); + + tokio::spawn(async move { + let result: Result<(), UserErr> = async { + let client = reqwest::Client::new(); + let results = join_all( + relayer_sig_req + .validators_info + .iter() + .map(|signer_info| async { + let signed_message = EncryptedSignedMessage::new( + signer.signer(), + serde_json::to_vec(&relayer_sig_req.clone())?, + &signer_info.x25519_public_key, + &[], + )?; + + let url = format!("http://{}/user/sign_tx", signer_info.ip_address.clone()); + + let response = client + .post(url) + .header("Content-Type", "application/json") + .body(serde_json::to_string(&signed_message)?) + .send() + .await?; + + Ok::<_, UserErr>(response) + }) + .collect::>(), + ) + .await; + + let mut send_back = vec![]; + + for result in results { + let mut resp = result?; + let chunk = resp + .chunk() + .await? + .ok_or(UserErr::OptionUnwrapError("No chunk data".to_string()))?; + + if resp.status() == 200 { + let signing_result: Result<(String, Signature), String> = + serde_json::from_slice(&chunk)?; + send_back.push(signing_result); + } else { + send_back.push(Err(String::from_utf8(chunk.to_vec())?)); + } + } + + if response_tx.try_send(serde_json::to_string(&send_back)?).is_err() { + tracing::warn!("Cannot send signing protocol output - connection is closed"); + } + + Ok(()) + } + .await; + + if let Err(e) = result { + tracing::error!("Error in tokio::spawn task: {:?}", e); + } + }); + + let result_stream = response_rx.map(Ok::<_, UserErr>); + + Ok((StatusCode::OK, Body::from_stream(result_stream))) +} + +/// Called by a relayer to initiate the signing process for a message +/// +/// Takes an [EncryptedSignedMessage] containing a JSON serialized [RelayerSignatureRequest] #[tracing::instrument(skip_all, fields(request_author))] pub async fn sign_tx( State(app_state): State, @@ -120,86 +258,92 @@ pub async fn sign_tx( let request_author = SubxtAccountId32(*signed_message.account_id().as_ref()); tracing::Span::current().record("request_author", signed_message.account_id().to_string()); + let validators_query = entropy::storage().session().validators(); + + let validators = query_chain(&api, &rpc, validators_query, None) + .await? + .ok_or_else(|| UserErr::ChainFetch("Error getting signers"))?; + + let validators_info = get_validators_info(&api, &rpc, validators).await?; + + validators_info + .iter() + .find(|validator| validator.tss_account == request_author) + .ok_or_else(|| UserErr::NotRelayedFromValidator)?; let request_limit_query = entropy::storage().parameters().request_limit(); let request_limit = query_chain(&api, &rpc, request_limit_query, None) .await? .ok_or_else(|| UserErr::ChainFetch("Failed to get request limit"))?; - let mut user_sig_req: UserSignatureRequest = serde_json::from_slice(&signed_message.message.0)?; + let relayer_sig_request: RelayerSignatureRequest = + serde_json::from_slice(&signed_message.message.0)?; - let string_verifying_key = hex::encode(user_sig_req.signature_verifying_key.clone()); - request_limit_check(&rpc, &app_state.kv_store, string_verifying_key.clone(), request_limit) - .await?; - - let block_number = rpc - .chain_get_header(None) + // check validator info > threshold + let key_info_query = entropy::storage().parameters().signers_info(); + let threshold = query_chain(&api, &rpc, key_info_query, None) .await? - .ok_or_else(|| UserErr::OptionUnwrapError("Error Getting Block Number".to_string()))? - .number; + .ok_or_else(|| UserErr::ChainFetch("Failed to get signers info"))? + .threshold; - check_stale(user_sig_req.block_number, block_number).await?; - - // Probably impossible but block signing from parent key anyways - if string_verifying_key == hex::encode(NETWORK_PARENT_KEY) { - return Err(UserErr::NoSigningFromParentKey); + if relayer_sig_request.validators_info.len() < threshold as usize { + return Err(UserErr::TooFewSigners); } + // validators are signers + let signer_query = entropy::storage().staking_extension().signers(); + let signers = query_chain(&api, &rpc, signer_query, None) + .await? + .ok_or_else(|| UserErr::ChainFetch("Get all validators error"))?; - let user_details = - get_registered_details(&api, &rpc, user_sig_req.signature_verifying_key.clone()).await?; - check_hash_pointer_out_of_bounds(&user_sig_req.hash, user_details.programs_data.0.len())?; + let validator_exists = { + let mut found = true; - let message = hex::decode(&user_sig_req.message)?; + for validator_info in &relayer_sig_request.validators_info { + let stash_address_query = entropy::storage() + .staking_extension() + .threshold_to_stash(validator_info.tss_account.clone()); - if user_details.programs_data.0.is_empty() { - return Err(UserErr::NoProgramPointerDefined()); - } + let stash_address = query_chain(&api, &rpc, stash_address_query, None) + .await? + .ok_or_else(|| UserErr::ChainFetch("Stash Fetch Error"))?; - // Handle aux data padding, if it is not explicit by client for ease send through None, error - // if incorrect length - let auxilary_data_vec; - if let Some(auxilary_data) = user_sig_req.clone().auxilary_data { - if auxilary_data.len() < user_details.programs_data.0.len() { - return Err(UserErr::MismatchAuxData); - } else { - auxilary_data_vec = auxilary_data; + // If the stash_address is found in signers, we can stop further checking + if !signers.contains(&stash_address) { + found = false; + break; + } } - } else { - auxilary_data_vec = vec![None; user_details.programs_data.0.len()]; - } - - // gets fuel from chain - let max_instructions_per_programs_query = - entropy::storage().parameters().max_instructions_per_programs(); - let fuel = query_chain(&api, &rpc, max_instructions_per_programs_query, None) - .await? - .ok_or_else(|| UserErr::ChainFetch("Max instructions per program error"))?; - - let mut runtime = Runtime::new(ProgramConfig { fuel }); + found + }; - for (i, program_data) in user_details.programs_data.0.iter().enumerate() { - let program_info = get_program(&api, &rpc, &program_data.program_pointer).await?; - let oracle_data = get_oracle_data(&api, &rpc, program_info.oracle_data_pointer).await?; - let auxilary_data = auxilary_data_vec[i].as_ref().map(hex::decode).transpose()?; - let signature_request = SignatureRequest { message: message.clone(), auxilary_data }; - runtime.evaluate( - &program_info.bytecode, - &signature_request, - Some(&program_data.program_config), - Some(&oracle_data), - )?; + if !validator_exists { + return Err(UserErr::IncorrectSigner); } - let signers = get_signers_from_chain(&api, &rpc).await?; + let string_verifying_key = + hex::encode(relayer_sig_request.user_signature_request.signature_verifying_key.clone()); + request_limit_check(&rpc, &app_state.kv_store, string_verifying_key.clone(), request_limit) + .await?; + + let block_number = rpc + .chain_get_header(None) + .await? + .ok_or_else(|| UserErr::OptionUnwrapError("Error Getting Block Number".to_string()))? + .number; - // Use the validator info from chain as we can be sure it is in the correct order and the - // details are correct - user_sig_req.validators_info = signers; + let (mut runtime, user_details, message) = pre_sign_checks( + &api, + &rpc, + relayer_sig_request.user_signature_request.clone(), + block_number, + string_verifying_key, + ) + .await?; let message_hash = compute_hash( &api, &rpc, - &user_sig_req.hash, + &relayer_sig_request.user_signature_request.hash, &mut runtime, &user_details.programs_data.0, message.as_slice(), @@ -207,7 +351,10 @@ pub async fn sign_tx( .await?; let signing_session_id = SigningSessionInfo { - signature_verifying_key: user_sig_req.signature_verifying_key.clone(), + signature_verifying_key: relayer_sig_request + .user_signature_request + .signature_verifying_key + .clone(), message_hash, request_author, }; @@ -227,7 +374,7 @@ pub async fn sign_tx( tokio::spawn(async move { let signing_protocol_output = do_signing( &rpc, - user_sig_req, + relayer_sig_request, &app_state, signing_session_id, request_limit, @@ -524,3 +671,63 @@ pub fn check_hash_pointer_out_of_bounds( _ => Ok(()), } } + +pub async fn pre_sign_checks( + api: &OnlineClient, + rpc: &LegacyRpcMethods, + user_sig_req: UserSignatureRequest, + block_number: u32, + string_verifying_key: String, +) -> Result<(Runtime, RegisteredInfo, Vec), UserErr> { + check_stale(user_sig_req.block_number, block_number).await?; + + // Probably impossible but block signing from parent key anyways + if string_verifying_key == hex::encode(NETWORK_PARENT_KEY) { + return Err(UserErr::NoSigningFromParentKey); + } + + let user_details = + get_registered_details(api, rpc, user_sig_req.signature_verifying_key.clone()).await?; + check_hash_pointer_out_of_bounds(&user_sig_req.hash, user_details.programs_data.0.len())?; + + let message = hex::decode(&user_sig_req.message)?; + + if user_details.programs_data.0.is_empty() { + return Err(UserErr::NoProgramPointerDefined()); + } + + // Handle aux data padding, if it is not explicit by client for ease send through None, error + // if incorrect length + let auxilary_data_vec = if let Some(auxilary_data) = user_sig_req.clone().auxilary_data { + if auxilary_data.len() < user_details.programs_data.0.len() { + return Err(UserErr::MismatchAuxData); + } + auxilary_data + } else { + vec![None; user_details.programs_data.0.len()] + }; + + // gets fuel from chain + let max_instructions_per_programs_query = + entropy::storage().parameters().max_instructions_per_programs(); + let fuel = query_chain(api, rpc, max_instructions_per_programs_query, None) + .await? + .ok_or_else(|| UserErr::ChainFetch("Max instructions per program error"))?; + + let mut runtime = Runtime::new(ProgramConfig { fuel }); + + for (i, program_data) in user_details.programs_data.0.iter().enumerate() { + let program_info = get_program(api, rpc, &program_data.program_pointer).await?; + let oracle_data = get_oracle_data(api, rpc, program_info.oracle_data_pointer).await?; + let auxilary_data = auxilary_data_vec[i].as_ref().map(hex::decode).transpose()?; + let signature_request = SignatureRequest { message: message.clone(), auxilary_data }; + runtime.evaluate( + &program_info.bytecode, + &signature_request, + Some(&program_data.program_config), + Some(&oracle_data), + )?; + } + + Ok((runtime, user_details, message)) +} diff --git a/crates/threshold-signature-server/src/user/errors.rs b/crates/threshold-signature-server/src/user/errors.rs index ada849df5..700df06dc 100644 --- a/crates/threshold-signature-server/src/user/errors.rs +++ b/crates/threshold-signature-server/src/user/errors.rs @@ -173,6 +173,16 @@ pub enum UserErr { UnknownHashingAlgorithm, #[error("Failed to derive BIP-32 account: {0}")] Bip32DerivationError(#[from] bip32::Error), + #[error("Message sent directly to signer")] + NotRelayedFromValidator, + #[error("Message not sent to a validator")] + NotValidator, + #[error("Relay message can not be sent to a signer")] + RelayMessageSigner, + #[error("Too few signers selected")] + TooFewSigners, + #[error("Non signer sent from relayer")] + IncorrectSigner, } impl From for UserErr { diff --git a/crates/threshold-signature-server/src/user/tests.rs b/crates/threshold-signature-server/src/user/tests.rs index 6dc2866f0..d82369f90 100644 --- a/crates/threshold-signature-server/src/user/tests.rs +++ b/crates/threshold-signature-server/src/user/tests.rs @@ -21,7 +21,7 @@ use entropy_client::substrate::get_registered_details; use entropy_client::{ client as test_client, client::{sign, update_programs}, - user::get_signers_from_chain, + user::get_all_signers_from_chain, }; use entropy_kvdb::{ clean_tests, @@ -72,6 +72,7 @@ use sp_keyring::{AccountKeyring, Sr25519Keyring}; use std::{ env, fs, path::PathBuf, + str, str::FromStr, sync::Arc, time::{Duration, SystemTime}, @@ -120,7 +121,7 @@ use crate::{ DEFAULT_ENDPOINT, DEFAULT_MNEMONIC, }, signing::Hasher, - substrate::{get_oracle_data, query_chain, submit_transaction}, + substrate::{get_oracle_data, get_signers_from_chain, query_chain, submit_transaction}, tests::{ create_clients, initialize_test_logger, jump_start_network_with_signer, remove_program, run_to_block, setup_client, spawn_testing_validators, store_program_and_register, @@ -134,7 +135,8 @@ use crate::{ user::{ api::{ check_hash_pointer_out_of_bounds, increment_or_wipe_request_limit, request_limit_check, - request_limit_key, RequestLimitStorage, UserRegistrationInfo, UserSignatureRequest, + request_limit_key, RelayerSignatureRequest, RequestLimitStorage, UserRegistrationInfo, + UserSignatureRequest, }, UserErr, }, @@ -170,8 +172,11 @@ async fn test_signature_requests_fail_on_different_conditions() { let one = AccountKeyring::One; let two = AccountKeyring::Two; - let (_validator_ips, _validator_ids) = + let (validator_ips, _validator_ids) = spawn_testing_validators(ChainSpecType::Integration).await; + let mnemonic = development_mnemonic(&Some(ValidatorName::Alice)); + let (tss_signer, _static_secret) = + get_signer_and_x25519_secret_from_mnemonic(&mnemonic.to_string()).unwrap(); // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. @@ -182,41 +187,81 @@ async fn test_signature_requests_fail_on_different_conditions() { // We first need to jump start the network and grab the resulting network wide verifying key // for later - jump_start_network(&entropy_api, &rpc).await; + let non_signer = jump_start_network(&entropy_api, &rpc).await.unwrap(); + let (relayer_ip_and_key, _) = + validator_name_to_relayer_info(non_signer, &entropy_api, &rpc).await; // Register the user with a test program let (verifying_key, program_hash) = store_program_and_register(&entropy_api, &rpc, &one.pair(), &two.pair()).await; // Test: We check that an account with a program succeeds in submiting a signature request - let (validators_info, mut signature_request, validator_ips_and_keys) = + let (_validators_info, mut signature_request, _validator_ips_and_keys) = get_sign_tx_data(&entropy_api, &rpc, hex::encode(PREIMAGE_SHOULD_SUCCEED), verifying_key) .await; // The account we registered does have a program pointer, so this should succeed let test_user_res = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), one) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), one) .await; let message_hash = Hasher::keccak(PREIMAGE_SHOULD_SUCCEED); let decoded_verifying_key = decode_verifying_key(verifying_key.as_slice().try_into().unwrap()).unwrap(); - verify_signature(test_user_res, message_hash, &decoded_verifying_key, &validators_info).await; + + let all_signers_info = get_all_signers_from_chain(&entropy_api, &rpc).await.unwrap(); + verify_signature(test_user_res, message_hash, &decoded_verifying_key, &all_signers_info).await; + + signature_request.block_number = rpc.chain_get_header(None).await.unwrap().unwrap().number; + + let mock_client = reqwest::Client::new(); + + let signed_message = EncryptedSignedMessage::new( + &one.pair(), + serde_json::to_vec(&signature_request.clone()).unwrap(), + &X25519_PUBLIC_KEYS[0], + &[], + ) + .unwrap(); + let url = format!("http://{}/user/sign_tx", validator_ips[0]); + let signature_request_responses_fail_not_relayer = mock_client + .post(url) + .header("Content-Type", "application/json") + .body(serde_json::to_string(&signed_message).unwrap()) + .send() + .await; + assert_eq!( + signature_request_responses_fail_not_relayer.unwrap().text().await.unwrap(), + "Message sent directly to signer" + ); // Test: A user that is not registered is not able to send a signature request signature_request.block_number = rpc.chain_get_header(None).await.unwrap().unwrap().number; signature_request.signature_verifying_key = DEFAULT_VERIFYING_KEY_NOT_REGISTERED.to_vec(); let test_user_res_not_registered = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), two) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), two) .await; - for res in test_user_res_not_registered { - assert_eq!( - res.unwrap().text().await.unwrap(), - "Substrate: User is not registered on-chain" - ); - } + assert_eq!( + test_user_res_not_registered.unwrap().text().await.unwrap(), + "Substrate: User is not registered on-chain" + ); + + let test_user_res_not_registered_sign_tx = submit_transaction_sign_tx_requests( + &entropy_api, + &rpc, + relayer_ip_and_key.clone(), + signature_request.clone(), + tss_signer.signer().clone(), + None, + ) + .await; + + assert_eq!( + test_user_res_not_registered_sign_tx.unwrap().text().await.unwrap(), + "Substrate: User is not registered on-chain" + ); // Test: Signature requests fail if no auxiliary data is set @@ -226,15 +271,28 @@ async fn test_signature_requests_fail_on_different_conditions() { signature_request.auxilary_data = None; let test_user_failed_programs_res = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), one) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), one) .await; - for res in test_user_failed_programs_res { - assert_eq!( - res.unwrap().text().await.unwrap(), + assert_eq!( + test_user_failed_programs_res.unwrap().text().await.unwrap(), "Runtime error: Runtime(Error::Evaluation(\"This program requires that `auxilary_data` be `Some`.\"))" ); - } + + let test_user_failed_programs_res_sign_tx = submit_transaction_sign_tx_requests( + &entropy_api, + &rpc, + relayer_ip_and_key.clone(), + signature_request.clone(), + tss_signer.signer().clone(), + None, + ) + .await; + + assert_eq!( + test_user_failed_programs_res_sign_tx.unwrap().text().await.unwrap(), + "Runtime error: Runtime(Error::Evaluation(\"This program requires that `auxilary_data` be `Some`.\"))" + ); // The test program is written to fail when `auxilary_data` is `None` but only on the second // program @@ -256,12 +314,28 @@ async fn test_signature_requests_fail_on_different_conditions() { signature_request.auxilary_data = Some(vec![Some(hex::encode(AUXILARY_DATA_SHOULD_SUCCEED))]); let test_user_failed_aux_data = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), one) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), one) .await; - for res in test_user_failed_aux_data { - assert_eq!(res.unwrap().text().await.unwrap(), "Auxilary data is mismatched"); - } + assert_eq!( + test_user_failed_aux_data.unwrap().text().await.unwrap(), + "Auxilary data is mismatched" + ); + + let test_user_failed_aux_data_sign_tx = submit_transaction_sign_tx_requests( + &entropy_api, + &rpc, + relayer_ip_and_key.clone(), + signature_request.clone(), + tss_signer.signer().clone(), + None, + ) + .await; + + assert_eq!( + test_user_failed_aux_data_sign_tx.unwrap().text().await.unwrap(), + "Auxilary data is mismatched" + ); // Test: Signature requests fails if a user provides an invalid hashing algorithm option @@ -270,44 +344,75 @@ async fn test_signature_requests_fail_on_different_conditions() { signature_request.hash = HashingAlgorithm::Custom(3); let test_user_custom_hash_out_of_bounds = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), two) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), two) .await; - for res in test_user_custom_hash_out_of_bounds { - assert_eq!(res.unwrap().text().await.unwrap(), "Custom hash choice out of bounds"); - } + assert_eq!( + test_user_custom_hash_out_of_bounds.unwrap().text().await.unwrap(), + "Custom hash choice out of bounds" + ); + + let test_user_custom_hash_out_of_bounds_sign_tx = submit_transaction_sign_tx_requests( + &entropy_api, + &rpc, + relayer_ip_and_key.clone(), + signature_request.clone(), + tss_signer.signer().clone(), + None, + ) + .await; + + assert_eq!( + test_user_custom_hash_out_of_bounds_sign_tx.unwrap().text().await.unwrap(), + "Custom hash choice out of bounds" + ); // Test: Signature requests fails if a the network parent key is used signature_request.block_number = rpc.chain_get_header(None).await.unwrap().unwrap().number; signature_request.signature_verifying_key = NETWORK_PARENT_KEY.as_bytes().to_vec(); - let test_user_sign_with_parent_key = submit_transaction_requests( - vec![validator_ips_and_keys[1].clone()], + let test_user_sign_with_parent_key = + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), one) + .await; + + assert_eq!( + test_user_sign_with_parent_key.unwrap().text().await.unwrap(), + "No signing from parent key" + ); + + let test_user_sign_with_parent_key_sign_tx = submit_transaction_sign_tx_requests( + &entropy_api, + &rpc, + relayer_ip_and_key.clone(), signature_request.clone(), - one, + tss_signer.signer().clone(), + None, ) .await; - for res in test_user_sign_with_parent_key { - assert_eq!(res.unwrap().text().await.unwrap(), "No signing from parent key"); - } + assert_eq!( + test_user_sign_with_parent_key_sign_tx.unwrap().text().await.unwrap(), + "No signing from parent key" + ); clean_tests(); } #[tokio::test] #[serial] -async fn signature_request_with_derived_account_works() { +async fn test_signature_requests_fail_validator_info_wrong() { initialize_test_logger().await; clean_tests(); - let alice = AccountKeyring::Alice; - let bob = AccountKeyring::Bob; - let charlie = AccountKeyring::Charlie; + let one = AccountKeyring::One; + let two = AccountKeyring::Two; let (_validator_ips, _validator_ids) = spawn_testing_validators(ChainSpecType::Integration).await; + let mnemonic = development_mnemonic(&Some(ValidatorName::Alice)); + let (tss_signer, _static_secret) = + get_signer_and_x25519_secret_from_mnemonic(&mnemonic.to_string()).unwrap(); // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. @@ -318,29 +423,105 @@ async fn signature_request_with_derived_account_works() { // We first need to jump start the network and grab the resulting network wide verifying key // for later - jump_start_network(&entropy_api, &rpc).await; + let non_signer = jump_start_network(&entropy_api, &rpc).await.unwrap(); + let (relayer_ip_and_key, tss_account) = + validator_name_to_relayer_info(non_signer, &entropy_api, &rpc).await; // Register the user with a test program let (verifying_key, _program_hash) = - store_program_and_register(&entropy_api, &rpc, &charlie.pair(), &bob.pair()).await; + store_program_and_register(&entropy_api, &rpc, &one.pair(), &two.pair()).await; - let (validators_info, signature_request, validator_ips_and_keys) = + // Test: We check that a relayed signature request with less than t validators selected fails + let (mut validators_info, signature_request, _validator_ips_and_keys) = get_sign_tx_data(&entropy_api, &rpc, hex::encode(PREIMAGE_SHOULD_SUCCEED), verifying_key) .await; - let signature_request_responses = submit_transaction_requests( - validator_ips_and_keys.clone(), + // Pops off a validator to trigger the too few validator check + validators_info.pop(); + + let test_user_res_not_registered_sign_tx = submit_transaction_sign_tx_requests( + &entropy_api, + &rpc, + relayer_ip_and_key.clone(), + signature_request.clone(), + tss_signer.signer().clone(), + Some(validators_info.clone()), + ) + .await; + + assert_eq!( + test_user_res_not_registered_sign_tx.unwrap().text().await.unwrap(), + "Too few signers selected" + ); + // Adds on a dummy validator to trigger the validator check + validators_info.push(ValidatorInfo { + x25519_public_key: relayer_ip_and_key.clone().1, + ip_address: relayer_ip_and_key.clone().0, + tss_account, + }); + + let test_user_res_wrong_validator = submit_transaction_sign_tx_requests( + &entropy_api, + &rpc, + relayer_ip_and_key.clone(), signature_request.clone(), - alice, + tss_signer.signer().clone(), + Some(validators_info), ) .await; + assert_eq!( + test_user_res_wrong_validator.unwrap().text().await.unwrap(), + "Non signer sent from relayer" + ); + + clean_tests(); +} + +#[tokio::test] +#[serial] +async fn signature_request_with_derived_account_works() { + initialize_test_logger().await; + clean_tests(); + + let alice = AccountKeyring::Alice; + let bob = AccountKeyring::Bob; + let charlie = AccountKeyring::Charlie; + + let (_idsvalidator_ips, _validator_ids) = + spawn_testing_validators(ChainSpecType::Integration).await; + + // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be + // able to get our chain in the right state to be jump started. + let force_authoring = true; + let substrate_context = test_node_process_testing_state(force_authoring).await; + let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); + let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); + + // We first need to jump start the network and grab the resulting network wide verifying key + // for later + let non_signer = jump_start_network(&entropy_api, &rpc).await.unwrap(); + let (relayer_ip_and_key, _) = + validator_name_to_relayer_info(non_signer, &entropy_api, &rpc).await; + + // Register the user with a test program + let (verifying_key, _program_hash) = + store_program_and_register(&entropy_api, &rpc, &charlie.pair(), &bob.pair()).await; + + let (_validators_info, signature_request, _validator_ips_and_keys) = + get_sign_tx_data(&entropy_api, &rpc, hex::encode(PREIMAGE_SHOULD_SUCCEED), verifying_key) + .await; + let signature_request_responses = + submit_transaction_request(relayer_ip_and_key, signature_request.clone(), alice).await; + // We expect that the signature we get back is valid let message_hash = Hasher::keccak(PREIMAGE_SHOULD_SUCCEED); let verifying_key = SynedrionVerifyingKey::try_from(signature_request.signature_verifying_key.as_slice()) .unwrap(); - verify_signature(signature_request_responses, message_hash, &verifying_key, &validators_info) + + let all_signers_info = get_all_signers_from_chain(&entropy_api, &rpc).await.unwrap(); + verify_signature(signature_request_responses, message_hash, &verifying_key, &all_signers_info) .await; clean_tests(); @@ -363,7 +544,10 @@ async fn test_signing_fails_if_wrong_participants_are_used() { let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); - jump_start_network(&entropy_api, &rpc).await; + let non_signer = jump_start_network(&entropy_api, &rpc).await.unwrap(); + let (relayer_ip_and_key, _) = + validator_name_to_relayer_info(non_signer, &entropy_api, &rpc).await; + let relayer_url = format!("http://{}/user/relay_tx", relayer_ip_and_key.0.clone()); let mock_client = reqwest::Client::new(); @@ -397,6 +581,19 @@ async fn test_signing_fails_if_wrong_participants_are_used() { "Encryption or signing error: Hpke: HPKE Error: OpenError" ); + let failed_res_relay = mock_client + .post(relayer_url.clone()) + .header("Content-Type", "application/json") + .body(serde_json::to_string(&failed_signed_message).unwrap()) + .send() + .await + .unwrap(); + assert_eq!(failed_res_relay.status(), 500); + assert_eq!( + failed_res_relay.text().await.unwrap(), + "Encryption or signing error: Hpke: HPKE Error: OpenError" + ); + let sig: [u8; 64] = [0; 64]; let user_input_bad = EncryptedSignedMessage::new_with_given_signature( &one.pair(), @@ -421,6 +618,29 @@ async fn test_signing_fails_if_wrong_participants_are_used() { "Encryption or signing error: Cannot verify signature" ); + let user_input_bad_relayer = EncryptedSignedMessage::new_with_given_signature( + &one.pair(), + serde_json::to_vec(&signature_request.clone()).unwrap(), + &relayer_ip_and_key.1, + &[], + sr25519::Signature::from_raw(sig), + ) + .unwrap(); + + let failed_sign_relay = mock_client + .post(relayer_url) + .header("Content-Type", "application/json") + .body(serde_json::to_string(&user_input_bad_relayer).unwrap()) + .send() + .await + .unwrap(); + + assert_eq!(failed_sign_relay.status(), 500); + assert_eq!( + failed_sign_relay.text().await.unwrap(), + "Encryption or signing error: Cannot verify signature" + ); + clean_tests(); } @@ -442,8 +662,9 @@ async fn test_request_limit_are_updated_during_signing() { let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); - jump_start_network(&entropy_api, &rpc).await; - + let non_signer = jump_start_network(&entropy_api, &rpc).await.unwrap(); + let (relayer_ip_and_key, _) = + validator_name_to_relayer_info(non_signer, &entropy_api, &rpc).await; // Register the user with a test program let (verifying_key, _program_hash) = store_program_and_register(&entropy_api, &rpc, &one.pair(), &two.pair()).await; @@ -451,18 +672,20 @@ async fn test_request_limit_are_updated_during_signing() { // Test: We check that the rate limiter changes as expected when signature requests are sent // First we need to get a signature request to populate the KVDB for our verifying key - let (validators_info, mut signature_request, validator_ips_and_keys) = + let (validators_info, mut signature_request, _validator_ips_and_keys) = get_sign_tx_data(&entropy_api, &rpc, hex::encode(PREIMAGE_SHOULD_SUCCEED), verifying_key) .await; let test_user_res = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), one) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), one) .await; let message_hash = Hasher::keccak(PREIMAGE_SHOULD_SUCCEED); let decoded_verifying_key = decode_verifying_key(verifying_key.as_slice().try_into().unwrap()).unwrap(); - verify_signature(test_user_res, message_hash, &decoded_verifying_key, &validators_info).await; + + let all_signers_info = get_all_signers_from_chain(&entropy_api, &rpc).await.unwrap(); + verify_signature(test_user_res, message_hash, &decoded_verifying_key, &all_signers_info).await; // Next we check request limiter increases let mock_client = reqwest::Client::new(); @@ -476,13 +699,15 @@ async fn test_request_limit_are_updated_during_signing() { .header("Content-Type", "application/json") .body(unsafe_get.clone()) .send() - .await - .unwrap(); - let serialized_request_amount = get_response.text().await.unwrap(); + .await; - let request_info: RequestLimitStorage = - RequestLimitStorage::decode(&mut serialized_request_amount.as_ref()).unwrap(); - assert_eq!(request_info.request_amount, 1); + if get_response.is_ok() { + let serialized_request_amount = get_response.unwrap().text().await.unwrap(); + + let request_info: RequestLimitStorage = + RequestLimitStorage::decode(&mut serialized_request_amount.as_ref()).unwrap(); + assert_eq!(request_info.request_amount, 1); + } // Test: If we send too many requests though, we'll be blocked from signing @@ -502,7 +727,7 @@ async fn test_request_limit_are_updated_during_signing() { ) .to_json(); - for validator_info in validators_info { + for validator_info in all_signers_info { mock_client .post(format!("http://{}/unsafe/put", validator_info.ip_address)) .header("Content-Type", "application/json") @@ -516,12 +741,10 @@ async fn test_request_limit_are_updated_during_signing() { signature_request.signature_verifying_key = verifying_key.to_vec(); let test_user_failed_request_limit = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), one) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), one) .await; - for res in test_user_failed_request_limit { - assert_eq!(res.unwrap().text().await.unwrap(), "Too many requests - wait a block"); - } + assert_eq!(test_user_failed_request_limit.unwrap().text().await.unwrap(), "[{\"Err\":\"Too many requests - wait a block\"},{\"Err\":\"Too many requests - wait a block\"}]"); clean_tests(); } @@ -544,8 +767,7 @@ async fn test_fails_to_sign_if_non_signing_group_participants_are_used() { let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); - jump_start_network(&entropy_api, &rpc).await; - + let non_signer = jump_start_network(&entropy_api, &rpc).await.unwrap(); // Register the user with a test program let (verifying_key, _program_hash) = store_program_and_register(&entropy_api, &rpc, &one.pair(), &two.pair()).await; @@ -555,19 +777,29 @@ async fn test_fails_to_sign_if_non_signing_group_participants_are_used() { .await; let message_hash = Hasher::keccak(PREIMAGE_SHOULD_SUCCEED); - let signature_request_account = subxtAccountId32(one.pair().public().0); + + let mnemonic = development_mnemonic(&Some(non_signer)); + let (tss_signer, _static_secret) = + get_signer_and_x25519_secret_from_mnemonic(&mnemonic.to_string()).unwrap(); + + let expected_account_id = tss_signer.account_id().clone(); + let session_id = SessionId::Sign(SigningSessionInfo { signature_verifying_key: verifying_key.to_vec(), message_hash, - request_author: signature_request_account.clone(), + request_author: expected_account_id, }); // Test attempting to connect over ws by someone who is not in the signing group - let validator_ip_and_key = validator_ips_and_keys[0].clone(); + let validator_ip_and_key: (String, [u8; 32], subxtAccountId32) = ( + validator_ips_and_keys[0].clone().0, + validator_ips_and_keys[0].clone().1, + one.to_account_id().into(), + ); let connection_attempt_handle = tokio::spawn(async move { // Wait for the "user" to submit the signing request tokio::time::sleep(Duration::from_millis(500)).await; - let ws_endpoint = format!("ws://{}/ws", validator_ip_and_key.0); + let ws_endpoint = format!("ws://{}/ws", &validator_ip_and_key.0.clone()); let (ws_stream, _response) = connect_async(ws_endpoint).await.unwrap(); let ferdie_pair = AccountKeyring::Ferdie.pair(); @@ -597,20 +829,20 @@ async fn test_fails_to_sign_if_non_signing_group_participants_are_used() { // returns true if this part of the test passes encrypted_connection.recv().await.is_err() }); + let validator_ip_and_key: (String, [u8; 32]) = + (validator_ips_and_keys[0].clone().0, validator_ips_and_keys[0].clone().1); - let test_user_bad_connection_res = submit_transaction_requests( - vec![validator_ips_and_keys[0].clone()], - signature_request, - one, + let test_user_bad_connection_res = submit_transaction_sign_tx_requests( + &entropy_api, + &rpc, + validator_ip_and_key, + signature_request.clone(), + tss_signer.signer().clone(), + None, ) .await; - for res in test_user_bad_connection_res { - assert_eq!( - res.unwrap().text().await.unwrap(), - "{\"Err\":\"Subscribe message rejected: NoListener(\\\"no listener\\\")\"}" - ); - } + assert!(test_user_bad_connection_res.unwrap().text().await.unwrap().contains("Err"),); assert!(connection_attempt_handle.await.unwrap()); @@ -635,7 +867,9 @@ async fn test_program_with_config() { let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); - jump_start_network(&entropy_api, &rpc).await; + let non_signer = jump_start_network(&entropy_api, &rpc).await.unwrap(); + let (relayer_ip_and_key, _) = + validator_name_to_relayer_info(non_signer, &entropy_api, &rpc).await; let program_hash = test_client::store_program( &entropy_api, @@ -686,17 +920,19 @@ async fn test_program_with_config() { .unwrap(); // Now we'll send off a signature request using the new program - let (validators_info, signature_request, validator_ips_and_keys) = + let (_validators_info, signature_request, _validator_ips_and_keys) = get_sign_tx_data(&entropy_api, &rpc, hex::encode(message), verifying_key).await; // Here we check that the signature request was indeed completed successfully let signature_request_responses = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), one) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), one) .await; let message_hash = Hasher::keccak(message.as_bytes()); let verifying_key = decode_verifying_key(verifying_key.as_slice().try_into().unwrap()).unwrap(); - verify_signature(signature_request_responses, message_hash, &verifying_key, &validators_info) + + let all_signers_info = get_all_signers_from_chain(&entropy_api, &rpc).await.unwrap(); + verify_signature(signature_request_responses, message_hash, &verifying_key, &all_signers_info) .await; clean_tests(); @@ -867,18 +1103,18 @@ async fn test_check_hash_pointer_out_of_bounds() { } pub async fn verify_signature( - test_user_res: Vec>, + test_user_res: Result, message_should_succeed_hash: [u8; 32], verifying_key: &VerifyingKey, validators_info: &Vec, ) { - let mut i = 0; - for res in test_user_res { - let mut res = res.unwrap(); - assert_eq!(res.status(), 200); - let chunk = res.chunk().await.unwrap().unwrap(); - let signing_result: Result<(String, Signature), String> = - serde_json::from_slice(&chunk).unwrap(); + let mut test_user_res = test_user_res.unwrap(); + assert_eq!(test_user_res.status(), 200); + let chunk = test_user_res.chunk().await.unwrap().unwrap(); + + let signing_results: Vec> = + serde_json::from_slice(&chunk).unwrap(); + for signing_result in signing_results { assert_eq!(signing_result.clone().unwrap().0.len(), 88); let mut decoded_sig = BASE64_STANDARD.decode(signing_result.clone().unwrap().0).unwrap(); let recovery_digit = decoded_sig.pop().unwrap(); @@ -891,13 +1127,18 @@ pub async fn verify_signature( ) .unwrap(); assert_eq!(verifying_key, &recovery_key_from_sig); - let sig_recovery = ::verify( - &signing_result.clone().unwrap().1, - BASE64_STANDARD.decode(signing_result.unwrap().0).unwrap(), - &sr25519::Public(validators_info[i].tss_account.0), - ); - assert!(sig_recovery); - i += 1; + let mut sig_recovery_results = vec![]; + + // do not know which validator created which message, run through them all + for validator_info in validators_info { + let sig_recovery = ::verify( + &signing_result.clone().unwrap().1, + BASE64_STANDARD.decode(signing_result.clone().unwrap().0).unwrap(), + &sr25519::Public(validator_info.tss_account.0), + ); + sig_recovery_results.push(sig_recovery) + } + assert!(sig_recovery_results.contains(&true)); } } @@ -913,13 +1154,18 @@ async fn test_fail_infinite_program() { let (_validator_ips, _validator_ids) = spawn_testing_validators(ChainSpecType::Integration).await; + let mnemonic = development_mnemonic(&Some(ValidatorName::Alice)); + let (tss_signer, _static_secret) = + get_signer_and_x25519_secret_from_mnemonic(&mnemonic.to_string()).unwrap(); + let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; let api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); - jump_start_network(&api, &rpc).await; + let non_signer = jump_start_network(&api, &rpc).await.unwrap(); + let (relayer_ip_and_key, _) = validator_name_to_relayer_info(non_signer, &api, &rpc).await; let program_hash = test_client::store_program( &api, @@ -945,16 +1191,29 @@ async fn test_fail_infinite_program() { .unwrap(); // Now we'll send off a signature request using the new program - let (_validators_info, signature_request, validator_ips_and_keys) = + let (_validators_info, signature_request, _validator_ips_and_keys) = get_sign_tx_data(&api, &rpc, hex::encode(PREIMAGE_SHOULD_SUCCEED), verifying_key).await; let test_infinite_loop = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), one) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), one) .await; - for res in test_infinite_loop { - assert_eq!(res.unwrap().text().await.unwrap(), "Runtime error: OutOfFuel"); - } + assert_eq!(test_infinite_loop.unwrap().text().await.unwrap(), "Runtime error: OutOfFuel"); + + let test_infinite_loop_sign_tx = submit_transaction_sign_tx_requests( + &api, + &rpc, + relayer_ip_and_key.clone(), + signature_request.clone(), + tss_signer.signer().clone(), + None, + ) + .await; + + assert_eq!( + test_infinite_loop_sign_tx.unwrap().text().await.unwrap(), + "Runtime error: OutOfFuel" + ); } #[tokio::test] @@ -1002,7 +1261,9 @@ async fn test_device_key_proxy() { // We first need to jump start the network and grab the resulting network wide verifying key // for later - jump_start_network(&entropy_api, &rpc).await; + let non_signer = jump_start_network(&entropy_api, &rpc).await.unwrap(); + let (relayer_ip_and_key, _) = + validator_name_to_relayer_info(non_signer, &entropy_api, &rpc).await; // We need to store a program in order to be able to register succesfully let program_hash = test_client::store_program( @@ -1083,20 +1344,20 @@ async fn test_device_key_proxy() { ))]); // Now we'll send off a signature request using the new program with auxilary data - let (validators_info, mut signature_request, validator_ips_and_keys) = + let (_validators_info, mut signature_request, _validator_ips_and_keys) = get_sign_tx_data(&entropy_api, &rpc, hex::encode(PREIMAGE_SHOULD_SUCCEED), verifying_key) .await; signature_request.auxilary_data = auxilary_data; let test_user_res = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), one) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), one) .await; let message_hash = Hasher::keccak(PREIMAGE_SHOULD_SUCCEED); let verifying_key = decode_verifying_key(verifying_key.as_slice().try_into().unwrap()).unwrap(); - - verify_signature(test_user_res, message_hash, &verifying_key, &validators_info).await; + let all_signers_info = get_all_signers_from_chain(&entropy_api, &rpc).await.unwrap(); + verify_signature(test_user_res, message_hash, &verifying_key, &all_signers_info).await; } /// FIXME (#909): Ignored due to block number changing message causing signing selection to be the incorrect nodes @@ -1128,8 +1389,9 @@ async fn test_faucet() { let two = AccountKeyring::Eve; let alice = AccountKeyring::Alice; - let (validator_ips, _validator_ids) = + let (_validator_ips, _validator_ids) = spawn_testing_validators(ChainSpecType::Development).await; + let relayer_ip_and_key = ("localhost:3001".to_string(), X25519_PUBLIC_KEYS[0]); let substrate_context = test_node_process_testing_state(true).await; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -1192,18 +1454,6 @@ async fn test_faucet() { .await .unwrap(); - let validators_info = vec![ - ValidatorInfo { - ip_address: "localhost:3001".to_string(), - x25519_public_key: X25519_PUBLIC_KEYS[0], - tss_account: TSS_ACCOUNTS[0].clone(), - }, - ValidatorInfo { - ip_address: "127.0.0.1:3002".to_string(), - x25519_public_key: X25519_PUBLIC_KEYS[1], - tss_account: TSS_ACCOUNTS[1].clone(), - }, - ]; // get tx data for aux data let spec_version = entropy_api.runtime_version().spec_version; let transaction_version = entropy_api.runtime_version().transaction_version; @@ -1226,28 +1476,20 @@ async fn test_faucet() { auxilary_data: Some(vec![Some(hex::encode( &serde_json::to_string(&aux_data.clone()).unwrap(), ))]), - validators_info, block_number: rpc.chain_get_header(None).await.unwrap().unwrap().number, hash: HashingAlgorithm::Blake2_256, signature_verifying_key: verifying_key.clone().to_vec(), }; - let validator_ips_and_keys = vec![ - (validator_ips[0].clone(), X25519_PUBLIC_KEYS[0]), - (validator_ips[1].clone(), X25519_PUBLIC_KEYS[1]), - ]; - signature_request.block_number = rpc.chain_get_header(None).await.unwrap().unwrap().number; let test_user_res = - submit_transaction_requests(validator_ips_and_keys.clone(), signature_request.clone(), one) + submit_transaction_request(relayer_ip_and_key.clone(), signature_request.clone(), one) .await; - let mut decoded_sig: Vec = vec![]; - for res in test_user_res { - let chunk = res.unwrap().chunk().await.unwrap().unwrap(); - let signing_result: Result<(String, Signature), String> = - serde_json::from_slice(&chunk).unwrap(); - decoded_sig = BASE64_STANDARD.decode(signing_result.clone().unwrap().0).unwrap(); - } + let chunk = test_user_res.unwrap().chunk().await.unwrap().unwrap(); + let signing_result: Vec> = + serde_json::from_slice(&chunk).unwrap(); + let decoded_sig = BASE64_STANDARD.decode(signing_result.clone()[0].clone().unwrap().0).unwrap(); + // take signed tx and repack it into a submitable tx let submittable_extrinsic = partial.sign_with_address_and_signature( &MultiAddress::Id(verfiying_key_account.clone().into()), @@ -1457,43 +1699,69 @@ async fn test_get_oracle_data() { assert_eq!(oracle_data_fail.len(), 0); } -pub async fn submit_transaction_requests( - validator_urls_and_keys: Vec<(String, [u8; 32])>, +pub async fn submit_transaction_request( + validator_urls_and_keys: (String, entropy_shared::X25519PublicKey), signature_request: UserSignatureRequest, keyring: Sr25519Keyring, -) -> Vec> { +) -> std::result::Result { let mock_client = reqwest::Client::new(); - join_all( - validator_urls_and_keys - .iter() - .map(|validator_tuple| async { - let signed_message = EncryptedSignedMessage::new( - &keyring.pair(), - serde_json::to_vec(&signature_request.clone()).unwrap(), - &validator_tuple.1, - &[], - ) - .unwrap(); - let url = format!("http://{}/user/sign_tx", validator_tuple.0.clone()); - mock_client - .post(url) - .header("Content-Type", "application/json") - .body(serde_json::to_string(&signed_message).unwrap()) - .send() - .await - }) - .collect::>(), + let signed_message = EncryptedSignedMessage::new( + &keyring.pair(), + serde_json::to_vec(&signature_request.clone()).unwrap(), + &validator_urls_and_keys.1, + &[], ) - .await + .unwrap(); + + let url = format!("http://{}/user/relay_tx", validator_urls_and_keys.0.clone()); + mock_client + .post(url) + .header("Content-Type", "application/json") + .body(serde_json::to_string(&signed_message).unwrap()) + .send() + .await } +pub async fn submit_transaction_sign_tx_requests( + api: &OnlineClient, + rpc: &LegacyRpcMethods, + validator_urls_and_keys: (String, entropy_shared::X25519PublicKey), + user_signature_request: UserSignatureRequest, + signer: sr25519::Pair, + validators_info_option: Option>, +) -> std::result::Result { + let mock_client = reqwest::Client::new(); + let validators_info = if let Some(validators_info) = validators_info_option { + validators_info + } else { + get_signers_from_chain(api, rpc).await.unwrap().0 + }; + + let relayer_sig_req = RelayerSignatureRequest { user_signature_request, validators_info }; + + let signed_message = EncryptedSignedMessage::new( + &signer, + serde_json::to_vec(&relayer_sig_req.clone()).unwrap(), + &validator_urls_and_keys.1, + &[], + ) + .unwrap(); + + let url = format!("http://{}/user/sign_tx", validator_urls_and_keys.0.clone()); + mock_client + .post(url) + .header("Content-Type", "application/json") + .body(serde_json::to_string(&signed_message).unwrap()) + .send() + .await +} pub async fn get_sign_tx_data( api: &OnlineClient, rpc: &LegacyRpcMethods, message: String, signature_verifying_key: [u8; 33], ) -> (Vec, UserSignatureRequest, Vec<(String, [u8; 32])>) { - let validators_info = get_signers_from_chain(api, rpc).await.unwrap(); + let (validators_info, _) = get_signers_from_chain(api, rpc).await.unwrap(); let signature_request = UserSignatureRequest { message, @@ -1501,7 +1769,6 @@ pub async fn get_sign_tx_data( Some(hex::encode(AUXILARY_DATA_SHOULD_SUCCEED)), Some(hex::encode(AUXILARY_DATA_SHOULD_SUCCEED)), ]), - validators_info: validators_info.clone(), block_number: rpc.chain_get_header(None).await.unwrap().unwrap().number, hash: HashingAlgorithm::Keccak, signature_verifying_key: signature_verifying_key.to_vec(), @@ -1517,8 +1784,36 @@ pub async fn get_sign_tx_data( pub async fn jump_start_network( api: &OnlineClient, rpc: &LegacyRpcMethods, -) { +) -> Option { let alice = AccountKeyring::Alice; let signer = PairSigner::::new(alice.clone().into()); - jump_start_network_with_signer(api, rpc, &signer).await; + jump_start_network_with_signer(api, rpc, &signer).await +} + +/// Takes a validator name and returns relayer info needed for tests +pub async fn validator_name_to_relayer_info( + validator_name: ValidatorName, + api: &OnlineClient, + rpc: &LegacyRpcMethods, +) -> ((String, entropy_shared::X25519PublicKey), subxtAccountId32) { + let stash_address = match validator_name { + ValidatorName::Alice => AccountKeyring::AliceStash, + ValidatorName::Bob => AccountKeyring::BobStash, + ValidatorName::Charlie => AccountKeyring::CharlieStash, + ValidatorName::Dave => AccountKeyring::DaveStash, + ValidatorName::Eve => AccountKeyring::EveStash, + }; + let block_hash = rpc.chain_get_block_hash(None).await.unwrap(); + let threshold_address_query = entropy::storage() + .staking_extension() + .threshold_servers(subxtAccountId32(stash_address.public().0)); + let server_info = + query_chain(&api, &rpc, threshold_address_query, block_hash).await.unwrap().unwrap(); + ( + ( + std::str::from_utf8(&server_info.endpoint).unwrap().to_string(), + server_info.x25519_public_key, + ), + server_info.tss_account, + ) } diff --git a/scripts/create-test-keyshares/src/main.rs b/scripts/create-test-keyshares/src/main.rs index 614830303..5c386ce43 100644 --- a/scripts/create-test-keyshares/src/main.rs +++ b/scripts/create-test-keyshares/src/main.rs @@ -20,7 +20,7 @@ use entropy_kvdb::kv_manager::helpers::serialize; use entropy_shared::{DETERMINISTIC_KEY_SHARE_DAVE, DETERMINISTIC_KEY_SHARE_EVE}; use entropy_testing_utils::create_test_keyshares::create_test_keyshares; use entropy_tss::helpers::{ - launch::{DEFAULT_ALICE_MNEMONIC, DEFAULT_BOB_MNEMONIC, DEFAULT_CHARLIE_MNEMONIC}, + launch::{DEFAULT_ALICE_MNEMONIC, DEFAULT_BOB_MNEMONIC, DEFAULT_DAVE_MNEMONIC}, validator::get_signer_and_x25519_secret_from_mnemonic, }; use std::{env::args, path::PathBuf}; @@ -34,7 +34,7 @@ async fn main() { get_signer_and_x25519_secret_from_mnemonic(DEFAULT_ALICE_MNEMONIC).unwrap(); let (bob_pair, _) = get_signer_and_x25519_secret_from_mnemonic(DEFAULT_BOB_MNEMONIC).unwrap(); let (charlie_pair, _) = - get_signer_and_x25519_secret_from_mnemonic(DEFAULT_CHARLIE_MNEMONIC).unwrap(); + get_signer_and_x25519_secret_from_mnemonic(DEFAULT_DAVE_MNEMONIC).unwrap(); let names_and_secret_keys = [("dave", *DETERMINISTIC_KEY_SHARE_DAVE), ("eve", *DETERMINISTIC_KEY_SHARE_EVE)]; @@ -65,7 +65,7 @@ async fn main() { } async fn write_keyshares(base_path: PathBuf, name: &str, keyshares_bytes: Vec>) { - let holder_names = ["alice", "bob", "charlie"]; + let holder_names = ["alice", "bob", "dave"]; for (i, bytes) in keyshares_bytes.iter().enumerate() { let filename = format!("{}-keyshare-held-by-{}.keyshare", name, holder_names[i]); let mut filepath = base_path.clone(); From e1eaf1244bb0f7993c1e273729e9fb9ac3b12e8a Mon Sep 17 00:00:00 2001 From: JesseAbram <33698952+JesseAbram@users.noreply.github.com> Date: Thu, 26 Sep 2024 22:05:44 -0400 Subject: [PATCH 05/17] No unbonding when signer or next signer (#1031) * No unbonding when signer or next signer * test for chill and unbond * fix bench * add unbond and chill benches * update benchmarks * Apply suggestions from code review Co-authored-by: peg * clean * lint * changelog * clean * add in nominating check * Update pallets/staking/src/benchmarking.rs Co-authored-by: Hernando Castano * add tests for nominators * clean function * fmt * fmt * fmt * Apply suggestions from code review Co-authored-by: Hernando Castano * clean * add nominator to benchmarks * fmt --------- Co-authored-by: peg Co-authored-by: Hernando Castano --- CHANGELOG.md | 5 + crates/client/entropy_metadata.scale | Bin 208772 -> 208976 bytes pallets/staking/src/benchmarking.rs | 104 +++++++- pallets/staking/src/lib.rs | 108 ++++++++- pallets/staking/src/mock.rs | 2 +- pallets/staking/src/tests.rs | 145 ++++++++++- pallets/staking/src/weights.rs | 226 ++++++++++++++++-- runtime/src/lib.rs | 2 + .../src/weights/pallet_staking_extension.rs | 164 ++++++++++--- 9 files changed, 686 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 299523c18..f8151e4c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ At the moment this project **does not** adhere to cleaned up. A lot of storage entries, events, and extrinsics were removed from the `Registry` pallet. The genesis build config was also removed. Additionally, the `new/user/` HTTP endpoint in the TSS was removed since it was no longer necessary. +- In [#1031](https://github.com/entropyxyz/entropy-core/pull/1031), more Staking calls were blocked + to go through the `staking_extention` pallet. This makes sure no funds can be unbonded from a + validator if they are currently in the signing comittee. This was applied to `unbond`, `chill`, + and `withdraw_unbonded` - In [#1045](https://github.com/entropyxyz/entropy-core/pull/1045), `ProgramsInfo` now takes `version_number` to maintain backwards compatibility if programs runtime is updated - In [#1050](https://github.com/entropyxyz/entropy-core/pull/1050), the flow for signing has changed. A user now sends their request to any validator that is not a signer. This will act as a relayer. @@ -45,6 +49,7 @@ At the moment this project **does not** adhere to ### Changed - Fix TSS `AccountId` keys in chainspec ([#993](https://github.com/entropyxyz/entropy-core/pull/993)) +- No unbonding when signer or next signer ([#1031](https://github.com/entropyxyz/entropy-core/pull/1031)) - Add relay tx endpoint ([#1050](https://github.com/entropyxyz/entropy-core/pull/1050)) ### Removed diff --git a/crates/client/entropy_metadata.scale b/crates/client/entropy_metadata.scale index 3c2856de606a1c8b1dd9303eb79fa3fcaf95cc33..d6d04ba7e8d3ffb04850718250248c8224e0d25a 100644 GIT binary patch delta 222 zcmZp<&vW4c&xVrcj0%%WpI@0Qc*}}IBsn89Cx?M~nhT@EWba#gj4YF@Zs|^5`ofu! zb@Iy>){JbERbQGhv$IT?e&35xY;(y=+i8pz(>K*K9E&f$X$Z+kRY-6xD#|ZP VnEtPaQM7$}1LOAT4NPy>0RXZiRY(8; delta 65 zcmV-H0KWgw;0%P{46t>QlX}`MlmF;L0Rxjm={o@glYi+p0R^+R X=~b2iD3=U?0mFwufdRKcfdUV&^cWmH diff --git a/pallets/staking/src/benchmarking.rs b/pallets/staking/src/benchmarking.rs index 088342a9a..3b9d612b9 100644 --- a/pallets/staking/src/benchmarking.rs +++ b/pallets/staking/src/benchmarking.rs @@ -15,23 +15,25 @@ //! Benchmarking setup for pallet-propgation #![allow(unused_imports)] +use super::*; +#[allow(unused_imports)] +use crate::Pallet as Staking; use entropy_shared::MAX_SIGNERS; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; use frame_support::{ assert_ok, ensure, sp_runtime::traits::StaticLookup, - traits::{Currency, Get}, + traits::{Currency, Defensive, Get}, BoundedVec, }; use frame_system::{EventRecord, RawOrigin}; use pallet_parameters::{SignersInfo, SignersSize}; -use pallet_staking::{Pallet as FrameStaking, RewardDestination, ValidatorPrefs}; +use pallet_staking::{ + Event as FrameStakingEvent, MaxNominationsOf, Nominations, Pallet as FrameStaking, + RewardDestination, ValidatorPrefs, +}; use sp_std::{vec, vec::Vec}; -use super::*; -#[allow(unused_imports)] -use crate::Pallet as Staking; - const NULL_ARR: [u8; 32] = [0; 32]; const SEED: u32 = 0; @@ -43,6 +45,16 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { assert_eq!(event, &system_event); } +fn assert_last_event_frame_staking( + generic_event: ::RuntimeEvent, +) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + // compare to the last event record + let EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + pub fn create_validators( count: u32, seed: u32, @@ -130,13 +142,88 @@ benchmarks! { assert_last_event::(Event::::ThresholdAccountChanged(bonder, server_info).into()); } + unbond { + let s in 0 .. MAX_SIGNERS as u32; + let n in 0 .. MaxNominationsOf::::get(); + + let caller: T::AccountId = whitelisted_caller(); + let validator_id_res = ::ValidatorId::try_from(caller.clone()).or(Err(Error::::InvalidValidatorId)).unwrap(); + let bonder: T::AccountId = account("bond", 0, SEED); + let threshold: T::AccountId = account("threshold", 0, SEED); + + let signers = vec![validator_id_res.clone(); s as usize]; + Signers::::put(signers.clone()); + NextSigners::::put(NextSignerInfo { + next_signers: signers, + confirmations: vec![], + }); + + prep_bond_and_validate::(true, caller.clone(), bonder.clone(), threshold.clone(), NULL_ARR); + + let targets = BoundedVec::try_from(vec![threshold.clone(); n as usize]).unwrap(); + let nominations = Nominations { targets, submitted_in: 0, suppressed: false }; + pallet_staking::Nominators::::insert(bonder.clone(), nominations); + }: _(RawOrigin::Signed(bonder.clone()), 10u32.into()) + verify { + assert_last_event_frame_staking::(FrameStakingEvent::Unbonded{ stash: bonder, amount: 10u32.into() }.into() ); + + } + + chill { + let c in 0 .. MAX_SIGNERS as u32; + let n in 0 .. MaxNominationsOf::::get(); + + let caller: T::AccountId = whitelisted_caller(); + let validator_id_res = ::ValidatorId::try_from(caller.clone()).or(Err(Error::::InvalidValidatorId)).unwrap(); + let bonder: T::AccountId = account("bond", 0, SEED); + let threshold: T::AccountId = account("threshold", 0, SEED); + + let signers = vec![validator_id_res.clone(); c as usize]; + Signers::::put(signers.clone()); + NextSigners::::put(NextSignerInfo { + next_signers: signers, + confirmations: vec![], + }); + + prep_bond_and_validate::(true, caller.clone(), bonder.clone(), threshold.clone(), NULL_ARR); + let bond = ::Currency::minimum_balance() * 10u32.into(); + + // assume fully unbonded as slightly more weight, but not enough to handle partial unbond + assert_ok!(>::unbond( + RawOrigin::Signed(bonder.clone()).into(), + bond, + )); + + let targets = BoundedVec::try_from(vec![threshold.clone(); n as usize]).unwrap(); + let nominations = Nominations { targets, submitted_in: 0, suppressed: false }; + pallet_staking::Nominators::::insert(bonder.clone(), nominations); + + let _ = pallet_staking::Validators::::clear(100, None); + + }: _(RawOrigin::Signed(bonder.clone())) + verify { + assert_last_event_frame_staking::(FrameStakingEvent::Chilled{ stash: bonder }.into() ); + + } + withdraw_unbonded { + let c in 0 .. MAX_SIGNERS as u32; + let n in 0 .. MaxNominationsOf::::get(); + let caller: T::AccountId = whitelisted_caller(); let bonder: T::AccountId = account("bond", 0, SEED); let threshold: T::AccountId = account("threshold", 0, SEED); + let validator_id_res = ::ValidatorId::try_from(caller.clone()).or(Err(Error::::InvalidValidatorId)).unwrap(); - prep_bond_and_validate::(true, caller.clone(), bonder.clone(), threshold, NULL_ARR); + let signers = vec![validator_id_res.clone(); c as usize]; + Signers::::put(signers.clone()); + NextSigners::::put(NextSignerInfo { + next_signers: signers, + confirmations: vec![], + }); + + prep_bond_and_validate::(true, caller.clone(), bonder.clone(), threshold.clone(), NULL_ARR); let bond = ::Currency::minimum_balance() * 10u32.into(); // assume fully unbonded as slightly more weight, but not enough to handle partial unbond @@ -145,6 +232,9 @@ benchmarks! { bond, )); + let targets = BoundedVec::try_from(vec![threshold.clone(); n as usize]).unwrap(); + let nominations = Nominations { targets, submitted_in: 0, suppressed: false }; + pallet_staking::Nominators::::insert(bonder.clone(), nominations); }: _(RawOrigin::Signed(bonder.clone()), 0u32) verify { diff --git a/pallets/staking/src/lib.rs b/pallets/staking/src/lib.rs index 85b51ae5a..c83e94eef 100644 --- a/pallets/staking/src/lib.rs +++ b/pallets/staking/src/lib.rs @@ -35,7 +35,7 @@ use core::convert::TryInto; pub use pallet::*; -use pallet_staking::ValidatorPrefs; +use pallet_staking::{MaxNominationsOf, ValidatorPrefs}; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -307,6 +307,10 @@ pub mod pallet { NotNextSigner, ReshareNotInProgress, AlreadyConfirmed, + NoUnbondingWhenSigner, + NoUnbondingWhenNextSigner, + NoUnnominatingWhenSigner, + NoUnnominatingWhenNextSigner, } #[pallet::event] @@ -400,9 +404,46 @@ pub mod pallet { Ok(()) } - /// Wraps's substrate withdraw unbonded but clears extra state if fully unbonded + /// Wraps's Substrate's `unbond` extrinsic but checks to make sure targeted account is not a signer or next signer #[pallet::call_index(2)] - #[pallet::weight(::WeightInfo::withdraw_unbonded())] + #[pallet::weight(::WeightInfo::unbond(MAX_SIGNERS as u32, MaxNominationsOf::::get()))] + pub fn unbond( + origin: OriginFor, + #[pallet::compact] value: BalanceOf, + ) -> DispatchResultWithPostInfo { + let controller = ensure_signed(origin.clone())?; + let ledger = + pallet_staking::Pallet::::ledger(StakingAccount::Controller(controller.clone())) + .map_err(|_| Error::::NoThresholdKey)?; + + let (signers_length, nominators_length) = + Self::ensure_not_signer_or_next_signer_or_nominating(&ledger.stash)?; + + pallet_staking::Pallet::::unbond(origin, value)?; + + Ok(Some(::WeightInfo::unbond(signers_length, nominators_length)).into()) + } + + /// Wraps's Substrate's `chill` extrinsic but checks to make sure the targeted account is not a signer or next signer + #[pallet::call_index(3)] + #[pallet::weight(::WeightInfo::chill(MAX_SIGNERS as u32, MaxNominationsOf::::get()))] + pub fn chill(origin: OriginFor) -> DispatchResultWithPostInfo { + let controller = ensure_signed(origin.clone())?; + let ledger = + pallet_staking::Pallet::::ledger(StakingAccount::Controller(controller.clone())) + .map_err(|_| Error::::NoThresholdKey)?; + + let (signers_length, nominators_length) = + Self::ensure_not_signer_or_next_signer_or_nominating(&ledger.stash)?; + + pallet_staking::Pallet::::chill(origin)?; + + Ok(Some(::WeightInfo::chill(signers_length, nominators_length)).into()) + } + + /// Wraps's Substrate's `withdraw_unbonded` extrinsic but clears extra state if fully unbonded + #[pallet::call_index(4)] + #[pallet::weight(::WeightInfo::withdraw_unbonded(MAX_SIGNERS as u32, MaxNominationsOf::::get()))] pub fn withdraw_unbonded( origin: OriginFor, num_slashing_spans: u32, @@ -412,8 +453,12 @@ pub mod pallet { pallet_staking::Pallet::::ledger(StakingAccount::Controller(controller.clone())) .map_err(|_| Error::::NoThresholdKey)?; - let validator_id = ::ValidatorId::try_from(ledger.stash) - .or(Err(Error::::InvalidValidatorId))?; + let validator_id = + ::ValidatorId::try_from(ledger.stash.clone()) + .or(Err(Error::::InvalidValidatorId))?; + + let (signers_length, nominators_length) = + Self::ensure_not_signer_or_next_signer_or_nominating(&ledger.stash)?; pallet_staking::Pallet::::withdraw_unbonded(origin, num_slashing_spans)?; // TODO: do not allow unbonding of validator if not enough validators https://github.com/entropyxyz/entropy-core/issues/942 @@ -424,7 +469,11 @@ pub mod pallet { IsValidatorSynced::::remove(&validator_id); Self::deposit_event(Event::NodeInfoRemoved(controller)); } - Ok(().into()) + Ok(Some(::WeightInfo::withdraw_unbonded( + signers_length, + nominators_length, + )) + .into()) } /// Wrap's Substrate's `staking_pallet::validate()` extrinsic, but enforces that @@ -432,7 +481,7 @@ pub mod pallet { /// /// Note that - just like the original `validate()` extrinsic - the effects of this are /// only applied in the following era. - #[pallet::call_index(3)] + #[pallet::call_index(5)] #[pallet::weight(::WeightInfo::validate())] pub fn validate( origin: OriginFor, @@ -471,7 +520,7 @@ pub mod pallet { /// Let a validator declare if their kvdb is synced or not synced /// `synced`: State of validator's kvdb - #[pallet::call_index(4)] + #[pallet::call_index(6)] #[pallet::weight(::WeightInfo::declare_synced())] pub fn declare_synced(origin: OriginFor, synced: bool) -> DispatchResult { let who = ensure_signed(origin.clone())?; @@ -481,7 +530,7 @@ pub mod pallet { Ok(()) } - #[pallet::call_index(5)] + #[pallet::call_index(7)] #[pallet::weight(({ ::WeightInfo::confirm_key_reshare_confirmed(MAX_SIGNERS as u32) .max(::WeightInfo::confirm_key_reshare_completed()) @@ -531,6 +580,47 @@ pub mod pallet { Ok(ledger.stash) } + /// Ensures that the current validator is not a signer or a next signer + pub fn ensure_not_signer_or_next_signer_or_nominating( + stash: &T::AccountId, + ) -> Result<(u32, u32), DispatchError> { + let nominations = pallet_staking::Nominators::::get(stash) + .map_or_else(Vec::new, |x| x.targets.into_inner()); + + let signers = Self::signers(); + + // Check if the validator_id or any nominated validator is in signers + let in_signers = |id: &T::AccountId| { + let validator_id = ::ValidatorId::try_from(id.clone()); + match validator_id { + Ok(v_id) => signers.contains(&v_id), + Err(_) => false, + } + }; + + ensure!(!in_signers(stash), Error::::NoUnbondingWhenSigner); + ensure!(!nominations.iter().any(in_signers), Error::::NoUnnominatingWhenSigner); + + if let Some(next_signers) = Self::next_signers() { + let next_signers_contains = |id: &T::AccountId| { + let validator_id = + ::ValidatorId::try_from(id.clone()); + match validator_id { + Ok(v_id) => next_signers.next_signers.contains(&v_id), + Err(_) => false, + } + }; + + ensure!(!next_signers_contains(stash), Error::::NoUnbondingWhenNextSigner); + ensure!( + !nominations.iter().any(next_signers_contains), + Error::::NoUnnominatingWhenNextSigner + ); + } + + Ok((signers.len() as u32, nominations.len() as u32)) + } + pub fn get_randomness() -> ChaCha20Rng { let phrase = b"signer_rotation"; // TODO: Is randomness freshness an issue here diff --git a/pallets/staking/src/mock.rs b/pallets/staking/src/mock.rs index 9ab987bfd..716132b87 100644 --- a/pallets/staking/src/mock.rs +++ b/pallets/staking/src/mock.rs @@ -397,7 +397,7 @@ impl pallet_parameters::Config for Test { pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = system::GenesisConfig::::default().build_storage().unwrap(); let pallet_balances = pallet_balances::GenesisConfig:: { - balances: vec![(1, 100), (2, 100), (3, 100), (4, 100)], + balances: vec![(1, 100), (2, 100), (3, 100), (4, 100), (7, 100), (8, 100), (9, 200)], }; let pallet_staking_extension = pallet_staking_extension::GenesisConfig:: { // (ValidatorID, (AccountId, X25519PublicKey, TssServerURL, VerifyingKey)) diff --git a/pallets/staking/src/tests.rs b/pallets/staking/src/tests.rs index 7f1c21ba1..70c0c80a5 100644 --- a/pallets/staking/src/tests.rs +++ b/pallets/staking/src/tests.rs @@ -286,7 +286,7 @@ fn it_will_not_allow_existing_tss_account_when_changing_threshold_account() { #[test] fn it_deletes_when_no_bond_left() { new_test_ext().execute_with(|| { - Signers::::put(vec![5, 6]); + Signers::::put(vec![5, 6, 7]); start_active_era(1); assert_ok!(FrameStaking::bond( RuntimeOrigin::signed(2), @@ -359,6 +359,49 @@ fn it_deletes_when_no_bond_left() { assert_eq!(Staking::threshold_to_stash(3), None); // validator no longer synced assert_eq!(Staking::is_validator_synced(2), false); + + assert_ok!(FrameStaking::bond( + RuntimeOrigin::signed(7), + 100u64, + pallet_staking::RewardDestination::Account(1), + )); + + assert_noop!( + Staking::withdraw_unbonded(RuntimeOrigin::signed(7), 0), + Error::::NoUnbondingWhenSigner + ); + + // test nominating flow + assert_ok!(FrameStaking::bond( + RuntimeOrigin::signed(9), + 100u64, + pallet_staking::RewardDestination::Account(1), + )); + assert_ok!(FrameStaking::nominate(RuntimeOrigin::signed(9), vec![7])); + assert_noop!( + Staking::withdraw_unbonded(RuntimeOrigin::signed(9), 0), + Error::::NoUnnominatingWhenSigner + ); + + assert_ok!(FrameStaking::bond( + RuntimeOrigin::signed(8), + 100u64, + pallet_staking::RewardDestination::Account(1), + )); + + NextSigners::::put(NextSignerInfo { next_signers: vec![8], confirmations: vec![] }); + + assert_noop!( + Staking::withdraw_unbonded(RuntimeOrigin::signed(8), 0), + Error::::NoUnbondingWhenNextSigner + ); + + // test nominating flow + assert_ok!(FrameStaking::nominate(RuntimeOrigin::signed(9), vec![8])); + assert_noop!( + Staking::withdraw_unbonded(RuntimeOrigin::signed(9), 0), + Error::::NoUnnominatingWhenNextSigner + ); }); } @@ -507,3 +550,103 @@ fn it_confirms_keyshare() { assert_eq!(Staking::signers(), [6, 5], "next signers rotated into current signers"); }); } + +#[test] +fn it_stops_unbonded_when_signer_or_next_signer() { + new_test_ext().execute_with(|| { + Signers::::put(vec![7]); + start_active_era(1); + + // test nominating flow + assert_ok!(FrameStaking::bond( + RuntimeOrigin::signed(9), + 100u64, + pallet_staking::RewardDestination::Account(1), + )); + assert_ok!(FrameStaking::nominate(RuntimeOrigin::signed(9), vec![7])); + assert_noop!( + Staking::unbond(RuntimeOrigin::signed(9), 100u64), + Error::::NoUnnominatingWhenSigner + ); + + assert_ok!(FrameStaking::bond( + RuntimeOrigin::signed(7), + 100u64, + pallet_staking::RewardDestination::Account(1), + )); + + assert_noop!( + Staking::unbond(RuntimeOrigin::signed(7), 0), + Error::::NoUnbondingWhenSigner + ); + + assert_ok!(FrameStaking::bond( + RuntimeOrigin::signed(8), + 100u64, + pallet_staking::RewardDestination::Account(1), + )); + + NextSigners::::put(NextSignerInfo { next_signers: vec![8], confirmations: vec![] }); + assert_noop!( + Staking::unbond(RuntimeOrigin::signed(8), 0), + Error::::NoUnbondingWhenNextSigner + ); + + // test nominating flow + assert_ok!(FrameStaking::nominate(RuntimeOrigin::signed(9), vec![8])); + assert_noop!( + Staking::unbond(RuntimeOrigin::signed(9), 100u64), + Error::::NoUnnominatingWhenNextSigner + ); + }); +} + +#[test] +fn it_stops_chill_when_signer_or_next_signer() { + new_test_ext().execute_with(|| { + Signers::::put(vec![7]); + start_active_era(1); + + // test nominating flow + assert_ok!(FrameStaking::bond( + RuntimeOrigin::signed(9), + 100u64, + pallet_staking::RewardDestination::Account(1), + )); + assert_ok!(FrameStaking::nominate(RuntimeOrigin::signed(9), vec![7])); + assert_noop!( + Staking::chill(RuntimeOrigin::signed(9)), + Error::::NoUnnominatingWhenSigner + ); + + assert_ok!(FrameStaking::bond( + RuntimeOrigin::signed(7), + 100u64, + pallet_staking::RewardDestination::Account(1), + )); + + assert_noop!( + Staking::chill(RuntimeOrigin::signed(7)), + Error::::NoUnbondingWhenSigner + ); + + assert_ok!(FrameStaking::bond( + RuntimeOrigin::signed(8), + 100u64, + pallet_staking::RewardDestination::Account(1), + )); + + NextSigners::::put(NextSignerInfo { next_signers: vec![8], confirmations: vec![] }); + + assert_noop!( + Staking::chill(RuntimeOrigin::signed(8)), + Error::::NoUnbondingWhenNextSigner + ); + // test nominating flow + assert_ok!(FrameStaking::nominate(RuntimeOrigin::signed(9), vec![8])); + assert_noop!( + Staking::chill(RuntimeOrigin::signed(9)), + Error::::NoUnnominatingWhenNextSigner + ); + }); +} diff --git a/pallets/staking/src/weights.rs b/pallets/staking/src/weights.rs index 25be1c558..fedc25021 100644 --- a/pallets/staking/src/weights.rs +++ b/pallets/staking/src/weights.rs @@ -54,7 +54,9 @@ use core::marker::PhantomData; pub trait WeightInfo { fn change_endpoint() -> Weight; fn change_threshold_accounts() -> Weight; - fn withdraw_unbonded() -> Weight; + fn chill(c: u32, n: u32) -> Weight; + fn unbond(c: u32, n: u32) -> Weight; + fn withdraw_unbonded(c: u32, n: u32) -> Weight; fn validate() -> Weight; fn declare_synced() -> Weight; fn confirm_key_reshare_confirmed(c: u32) -> Weight; @@ -96,22 +98,117 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `StakingExtension::NextSigners` (r:1 w:0) + /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn withdraw_unbonded() -> Weight { + /// Storage: `BagsList::ListNodes` (r:1 w:1) + /// Proof: `BagsList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 15]`. + /// The range of component `n` is `[0, 16]`. + fn unbond(s: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1039` - // Estimated: `4764` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(41_000_000, 4764) - .saturating_add(T::DbWeight::get().reads(5_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) + // Measured: `1986 + n * (32 ±0) + s * (64 ±0)` + // Estimated: `4764 + n * (32 ±0) + s * (64 ±0)` + // Minimum execution time: 72_000_000 picoseconds. + Weight::from_parts(71_588_925, 0) + .saturating_add(Weight::from_parts(0, 4764)) + // Standard Error: 254_432 + .saturating_add(Weight::from_parts(266_286, 0).saturating_mul(s.into())) + // Standard Error: 244_899 + .saturating_add(Weight::from_parts(241_693, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(s.into())) + } + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `StakingExtension::NextSigners` (r:1 w:0) + /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `BagsList::ListNodes` (r:2 w:2) + /// Proof: `BagsList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `BagsList::ListBags` (r:1 w:1) + /// Proof: `BagsList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `BagsList::CounterForListNodes` (r:1 w:1) + /// Proof: `BagsList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 15]`. + /// The range of component `n` is `[0, 16]`. + fn chill(c: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1864 + c * (64 ±0) + n * (32 ±0)` + // Estimated: `6248 + c * (64 ±0) + n * (32 ±0)` + // Minimum execution time: 59_000_000 picoseconds. + Weight::from_parts(57_194_136, 0) + .saturating_add(Weight::from_parts(0, 6248)) + // Standard Error: 195_789 + .saturating_add(Weight::from_parts(161_563, 0).saturating_mul(c.into())) + // Standard Error: 188_454 + .saturating_add(Weight::from_parts(295_602, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(n.into())) + } + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `StakingExtension::NextSigners` (r:1 w:0) + /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 15]`. + /// The range of component `n` is `[0, 16]`. + fn withdraw_unbonded(c: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1534 + c * (64 ±0) + n * (32 ±0)` + // Estimated: `4764 + c * (64 ±0) + n * (32 ±0)` + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(47_473_941, 0) + .saturating_add(Weight::from_parts(0, 4764)) + // Standard Error: 190_804 + .saturating_add(Weight::from_parts(73_615, 0).saturating_mul(c.into())) + // Standard Error: 183_655 + .saturating_add(Weight::from_parts(405_456, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -269,22 +366,117 @@ impl WeightInfo for () { } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `StakingExtension::NextSigners` (r:1 w:0) + /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(49), added: 2524, mode: `MaxEncodedLen`) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn withdraw_unbonded() -> Weight { + /// Storage: `BagsList::ListNodes` (r:1 w:1) + /// Proof: `BagsList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 15]`. + /// The range of component `n` is `[0, 16]`. + fn unbond(s: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1039` - // Estimated: `4764` - // Minimum execution time: 40_000_000 picoseconds. - Weight::from_parts(41_000_000, 4764) - .saturating_add(RocksDbWeight::get().reads(5_u64)) - .saturating_add(RocksDbWeight::get().writes(3_u64)) + // Measured: `1986 + n * (32 ±0) + s * (64 ±0)` + // Estimated: `4764 + n * (32 ±0) + s * (64 ±0)` + // Minimum execution time: 72_000_000 picoseconds. + Weight::from_parts(71_588_925, 0) + .saturating_add(Weight::from_parts(0, 4764)) + // Standard Error: 254_432 + .saturating_add(Weight::from_parts(266_286, 0).saturating_mul(s.into())) + // Standard Error: 244_899 + .saturating_add(Weight::from_parts(241_693, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11)) + .saturating_add(RocksDbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(s.into())) + } + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `StakingExtension::NextSigners` (r:1 w:0) + /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `BagsList::ListNodes` (r:2 w:2) + /// Proof: `BagsList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `BagsList::ListBags` (r:1 w:1) + /// Proof: `BagsList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `BagsList::CounterForListNodes` (r:1 w:1) + /// Proof: `BagsList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 15]`. + /// The range of component `n` is `[0, 16]`. + fn chill(c: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1864 + c * (64 ±0) + n * (32 ±0)` + // Estimated: `6248 + c * (64 ±0) + n * (32 ±0)` + // Minimum execution time: 59_000_000 picoseconds. + Weight::from_parts(57_194_136, 0) + .saturating_add(Weight::from_parts(0, 6248)) + // Standard Error: 195_789 + .saturating_add(Weight::from_parts(161_563, 0).saturating_mul(c.into())) + // Standard Error: 188_454 + .saturating_add(Weight::from_parts(295_602, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(11)) + .saturating_add(RocksDbWeight::get().writes(6)) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(n.into())) + } + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `StakingExtension::NextSigners` (r:1 w:0) + /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 15]`. + /// The range of component `n` is `[0, 16]`. + fn withdraw_unbonded(c: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1534 + c * (64 ±0) + n * (32 ±0)` + // Estimated: `4764 + c * (64 ±0) + n * (32 ±0)` + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(47_473_941, 0) + .saturating_add(Weight::from_parts(0, 4764)) + // Standard Error: 190_804 + .saturating_add(Weight::from_parts(73_615, 0).saturating_mul(c.into())) + // Standard Error: 183_655 + .saturating_add(Weight::from_parts(405_456, 0).saturating_mul(n.into())) + .saturating_add(RocksDbWeight::get().reads(9)) + .saturating_add(RocksDbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(n.into())) } /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index d5a469662..5985de516 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -318,6 +318,8 @@ impl Contains for BaseCallFilter { call, RuntimeCall::Staking(pallet_staking::Call::withdraw_unbonded { .. }) | RuntimeCall::Staking(pallet_staking::Call::validate { .. }) + | RuntimeCall::Staking(pallet_staking::Call::unbond { .. }) + | RuntimeCall::Staking(pallet_staking::Call::chill { .. }) ); if is_paused || system_reject { // no paused call diff --git a/runtime/src/weights/pallet_staking_extension.rs b/runtime/src/weights/pallet_staking_extension.rs index f3232611b..158c1fb48 100644 --- a/runtime/src/weights/pallet_staking_extension.rs +++ b/runtime/src/weights/pallet_staking_extension.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `pallet_staking_extension` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 33.0.0 -//! DATE: 2024-08-21, STEPS: `5`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-09-21, STEPS: `5`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `hcastano`, CPU: `` +//! HOSTNAME: `Jesses-MacBook-Pro.local`, CPU: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 // Executed Command: @@ -55,8 +55,8 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `1309` // Estimated: `4774` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(30_000_000, 0) + // Minimum execution time: 24_000_000 picoseconds. + Weight::from_parts(26_000_000, 0) .saturating_add(Weight::from_parts(0, 4774)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -73,8 +73,8 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `1430` // Estimated: `4895` - // Minimum execution time: 31_000_000 picoseconds. - Weight::from_parts(32_000_000, 0) + // Minimum execution time: 28_000_000 picoseconds. + Weight::from_parts(28_000_000, 0) .saturating_add(Weight::from_parts(0, 4895)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -83,6 +83,14 @@ impl pallet_staking_extension::WeightInfo for WeightInf /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `StakingExtension::NextSigners` (r:1 w:0) + /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::MinNominatorBond` (r:1 w:0) + /// Proof: `Staking::MinNominatorBond` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Staking::CurrentEra` (r:1 w:0) /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// Storage: `Balances::Locks` (r:1 w:1) @@ -91,15 +99,99 @@ impl pallet_staking_extension::WeightInfo for WeightInf /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn withdraw_unbonded() -> Weight { + /// Storage: `BagsList::ListNodes` (r:1 w:1) + /// Proof: `BagsList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// The range of component `s` is `[0, 15]`. + /// The range of component `n` is `[0, 16]`. + fn unbond(s: u32, n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1262` - // Estimated: `4764` - // Minimum execution time: 45_000_000 picoseconds. - Weight::from_parts(48_000_000, 0) + // Measured: `1986 + n * (32 ±0) + s * (64 ±0)` + // Estimated: `4764 + n * (32 ±0) + s * (64 ±0)` + // Minimum execution time: 72_000_000 picoseconds. + Weight::from_parts(71_588_925, 0) .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(6)) + // Standard Error: 254_432 + .saturating_add(Weight::from_parts(266_286, 0).saturating_mul(s.into())) + // Standard Error: 244_899 + .saturating_add(Weight::from_parts(241_693, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(s.into())) + } + /// Storage: `Staking::Ledger` (r:1 w:0) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:1) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `StakingExtension::NextSigners` (r:1 w:0) + /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::Validators` (r:1 w:0) + /// Proof: `Staking::Validators` (`max_values`: None, `max_size`: Some(45), added: 2520, mode: `MaxEncodedLen`) + /// Storage: `Staking::CounterForNominators` (r:1 w:1) + /// Proof: `Staking::CounterForNominators` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `BagsList::ListNodes` (r:2 w:2) + /// Proof: `BagsList::ListNodes` (`max_values`: None, `max_size`: Some(154), added: 2629, mode: `MaxEncodedLen`) + /// Storage: `BagsList::ListBags` (r:1 w:1) + /// Proof: `BagsList::ListBags` (`max_values`: None, `max_size`: Some(82), added: 2557, mode: `MaxEncodedLen`) + /// Storage: `BagsList::CounterForListNodes` (r:1 w:1) + /// Proof: `BagsList::CounterForListNodes` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 15]`. + /// The range of component `n` is `[0, 16]`. + fn chill(c: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1864 + c * (64 ±0) + n * (32 ±0)` + // Estimated: `6248 + c * (64 ±0) + n * (32 ±0)` + // Minimum execution time: 59_000_000 picoseconds. + Weight::from_parts(57_194_136, 0) + .saturating_add(Weight::from_parts(0, 6248)) + // Standard Error: 195_789 + .saturating_add(Weight::from_parts(161_563, 0).saturating_mul(c.into())) + // Standard Error: 188_454 + .saturating_add(Weight::from_parts(295_602, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(11)) + .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(n.into())) + } + /// Storage: `Staking::Ledger` (r:1 w:1) + /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `Staking::Nominators` (r:1 w:0) + /// Proof: `Staking::Nominators` (`max_values`: None, `max_size`: Some(558), added: 3033, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `StakingExtension::NextSigners` (r:1 w:0) + /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::CurrentEra` (r:1 w:0) + /// Proof: `Staking::CurrentEra` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(193), added: 2668, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `c` is `[0, 15]`. + /// The range of component `n` is `[0, 16]`. + fn withdraw_unbonded(c: u32, n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1534 + c * (64 ±0) + n * (32 ±0)` + // Estimated: `4764 + c * (64 ±0) + n * (32 ±0)` + // Minimum execution time: 47_000_000 picoseconds. + Weight::from_parts(47_473_941, 0) + .saturating_add(Weight::from_parts(0, 4764)) + // Standard Error: 190_804 + .saturating_add(Weight::from_parts(73_615, 0).saturating_mul(c.into())) + // Standard Error: 183_655 + .saturating_add(Weight::from_parts(405_456, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 64).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(n.into())) } /// Storage: `StakingExtension::ThresholdToStash` (r:1 w:1) /// Proof: `StakingExtension::ThresholdToStash` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -131,8 +223,8 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `1918` // Estimated: `6248` - // Minimum execution time: 76_000_000 picoseconds. - Weight::from_parts(184_000_000, 0) + // Minimum execution time: 64_000_000 picoseconds. + Weight::from_parts(66_000_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(8)) @@ -145,8 +237,8 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `320` // Estimated: `3785` - // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(13_000_000, 0) + // Minimum execution time: 9_000_000 picoseconds. + Weight::from_parts(18_000_000, 0) .saturating_add(Weight::from_parts(0, 3785)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -160,11 +252,11 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `797 + c * (32 ±0)` // Estimated: `4298 + c * (29 ±1)` - // Minimum execution time: 13_000_000 picoseconds. - Weight::from_parts(14_248_618, 0) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(11_715_469, 0) .saturating_add(Weight::from_parts(0, 4298)) - // Standard Error: 122_082 - .saturating_add(Weight::from_parts(90_469, 0).saturating_mul(c.into())) + // Standard Error: 48_988 + .saturating_add(Weight::from_parts(11_740, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 29).saturating_mul(c.into())) @@ -175,15 +267,17 @@ impl pallet_staking_extension::WeightInfo for WeightInf /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `StakingExtension::Signers` (r:0 w:1) /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `StakingExtension::RotateKeyshares` (r:0 w:1) + /// Proof: `StakingExtension::RotateKeyshares` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) fn confirm_key_reshare_completed() -> Weight { // Proof Size summary in bytes: // Measured: `1309` // Estimated: `4774` - // Minimum execution time: 14_000_000 picoseconds. - Weight::from_parts(14_000_000, 0) + // Minimum execution time: 11_000_000 picoseconds. + Weight::from_parts(13_000_000, 0) .saturating_add(Weight::from_parts(0, 4774)) .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `StakingExtension::Signers` (r:1 w:0) /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -192,11 +286,11 @@ impl pallet_staking_extension::WeightInfo for WeightInf /// The range of component `s` is `[2, 15]`. fn new_session_base_weight(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `254 + s * (32 ±0)` - // Estimated: `1739 + s * (32 ±0)` - // Minimum execution time: 7_000_000 picoseconds. - Weight::from_parts(7_682_879, 0) - .saturating_add(Weight::from_parts(0, 1739)) + // Measured: `266 + s * (32 ±0)` + // Estimated: `1751 + s * (32 ±0)` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_171_206, 0) + .saturating_add(Weight::from_parts(0, 1751)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(s.into())) } @@ -218,13 +312,13 @@ impl pallet_staking_extension::WeightInfo for WeightInf /// The range of component `l` is `[0, 15]`. fn new_session(c: u32, _l: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482 + c * (32 ±0)` - // Estimated: `1966 + c * (32 ±0)` - // Minimum execution time: 15_000_000 picoseconds. - Weight::from_parts(16_252_259, 0) - .saturating_add(Weight::from_parts(0, 1966)) - // Standard Error: 101_760 - .saturating_add(Weight::from_parts(74_486, 0).saturating_mul(c.into())) + // Measured: `494 + c * (32 ±0)` + // Estimated: `1978 + c * (32 ±0)` + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(12_883_398, 0) + .saturating_add(Weight::from_parts(0, 1978)) + // Standard Error: 33_391 + .saturating_add(Weight::from_parts(69_713, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into())) From 383ccfca5fbdece7d2da1183426105fd51cfa4bb Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 27 Sep 2024 07:58:23 +0200 Subject: [PATCH 06/17] Unignore register and sign integration test, and do a non-mock jumpstart (#1070) * Unignore register and sign test, and do a non-mock jumpstart * Make jumpstart helper and unignore other test * Clippy * Comments, tidy --- .../src/helpers/tests.rs | 68 ++++++++++++++++++- .../src/user/tests.rs | 62 +---------------- .../tests/register_and_sign.rs | 23 +++---- .../tests/sign_eth_tx.rs | 20 +++--- 4 files changed, 89 insertions(+), 84 deletions(-) diff --git a/crates/threshold-signature-server/src/helpers/tests.rs b/crates/threshold-signature-server/src/helpers/tests.rs index b523072ab..abbbb9ffc 100644 --- a/crates/threshold-signature-server/src/helpers/tests.rs +++ b/crates/threshold-signature-server/src/helpers/tests.rs @@ -39,14 +39,17 @@ use crate::{ AppState, }; use axum::{routing::IntoMakeService, Router}; +use entropy_client::substrate::query_chain; use entropy_kvdb::{encrypted_sled::PasswordMethod, get_db_path, kv_manager::KvManager}; use entropy_protocol::PartyId; #[cfg(test)] use entropy_shared::EncodedVerifyingKey; -use entropy_shared::{EVE_VERIFYING_KEY, NETWORK_PARENT_KEY}; +use entropy_shared::{OcwMessageDkg, EVE_VERIFYING_KEY, NETWORK_PARENT_KEY}; +use futures::future::join_all; +use parity_scale_codec::Encode; use std::time::Duration; use subxt::{ - backend::legacy::LegacyRpcMethods, ext::sp_core::sr25519, tx::PairSigner, + backend::legacy::LegacyRpcMethods, events::EventsClient, ext::sp_core::sr25519, tx::PairSigner, utils::AccountId32 as SubxtAccountId32, Config, OnlineClient, }; use tokio::sync::OnceCell; @@ -355,3 +358,64 @@ pub async fn store_program_and_register( (verifying_key, program_hash) } + +/// Do a network jumpstart DKG +pub async fn do_jump_start( + api: &OnlineClient, + rpc: &LegacyRpcMethods, + pair: sr25519::Pair, +) { + let block_number = rpc.chain_get_header(None).await.unwrap().unwrap().number + 1; + put_jumpstart_request_on_chain(api, rpc, pair).await; + + run_to_block(rpc, block_number + 1).await; + + let selected_validators_query = entropy::storage().registry().jumpstart_dkg(block_number); + let validators_info = + query_chain(api, rpc, selected_validators_query, None).await.unwrap().unwrap(); + let validators_info: Vec<_> = validators_info.into_iter().map(|v| v.0).collect(); + let onchain_user_request = OcwMessageDkg { block_number, validators_info }; + + let client = reqwest::Client::new(); + let response_results = join_all( + [3002, 3003, 3004] + .iter() + .map(|port| { + client + .post(format!("http://127.0.0.1:{}/generate_network_key", port)) + .body(onchain_user_request.clone().encode()) + .send() + }) + .collect::>(), + ) + .await; + for response_result in response_results { + assert_eq!(response_result.unwrap().text().await.unwrap(), ""); + } + + // Wait for jump start event + let mut got_jumpstart_event = false; + for _ in 0..75 { + std::thread::sleep(std::time::Duration::from_millis(1000)); + let block_hash = rpc.chain_get_block_hash(None).await.unwrap(); + let events = EventsClient::new(api.clone()).at(block_hash.unwrap()).await.unwrap(); + let jump_start_event = events.find::(); + if let Some(_event) = jump_start_event.flatten().next() { + got_jumpstart_event = true; + break; + }; + } + assert!(got_jumpstart_event); +} + +/// Submit a jumpstart extrinsic +async fn put_jumpstart_request_on_chain( + api: &OnlineClient, + rpc: &LegacyRpcMethods, + pair: sr25519::Pair, +) { + let account = PairSigner::::new(pair); + + let registering_tx = entropy::tx().registry().jump_start_network(); + submit_transaction(api, rpc, &account, ®istering_tx, None).await.unwrap(); +} diff --git a/crates/threshold-signature-server/src/user/tests.rs b/crates/threshold-signature-server/src/user/tests.rs index d82369f90..2379d3920 100644 --- a/crates/threshold-signature-server/src/user/tests.rs +++ b/crates/threshold-signature-server/src/user/tests.rs @@ -105,6 +105,7 @@ use tokio_tungstenite::{connect_async, tungstenite::Message}; use x25519_dalek::{PublicKey, StaticSecret}; use super::UserInputPartyInfo; +use crate::helpers::tests::do_jump_start; use crate::{ chain_api::{ entropy, entropy::runtime_types::bounded_collections::bounded_vec::BoundedVec, @@ -944,8 +945,6 @@ async fn test_jumpstart_network() { initialize_test_logger().await; clean_tests(); - let alice = AccountKeyring::Alice; - let (_validator_ips, _validator_ids) = spawn_testing_validators(ChainSpecType::Integration).await; @@ -955,52 +954,9 @@ async fn test_jumpstart_network() { let api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); - let client = reqwest::Client::new(); - - let block_number = rpc.chain_get_header(None).await.unwrap().unwrap().number + 1; - - put_jumpstart_request_on_chain(&api, &rpc, &alice).await; - - run_to_block(&rpc, block_number + 1).await; - - let selected_validators_query = entropy::storage().registry().jumpstart_dkg(block_number); - let validators_info = - query_chain(&api, &rpc, selected_validators_query, None).await.unwrap().unwrap(); - let validators_info: Vec<_> = validators_info.into_iter().map(|v| v.0).collect(); - let onchain_user_request = OcwMessageDkg { block_number, validators_info }; - - // succeeds - let response_results = join_all( - vec![3002, 3003, 3004] - .iter() - .map(|port| { - client - .post(format!("http://127.0.0.1:{}/generate_network_key", port)) - .body(onchain_user_request.clone().encode()) - .send() - }) - .collect::>(), - ) - .await; - - for response_result in response_results { - assert_eq!(response_result.unwrap().text().await.unwrap(), ""); - } - - // wait for jump start event check that key exists in kvdb - let mut got_jumpstart_event = false; - for _ in 0..75 { - std::thread::sleep(std::time::Duration::from_millis(1000)); - let block_hash = rpc.chain_get_block_hash(None).await.unwrap(); - let events = EventsClient::new(api.clone()).at(block_hash.unwrap()).await.unwrap(); - let jump_start_event = events.find::(); - for _event in jump_start_event.flatten() { - got_jumpstart_event = true; - break; - } - } - assert!(got_jumpstart_event); + do_jump_start(&api, &rpc, AccountKeyring::Alice.pair()).await; + let client = reqwest::Client::new(); let response_key = unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), 3001).await; // check to make sure keyshare is correct @@ -1043,18 +999,6 @@ pub async fn put_register_request_on_chain( Ok(registered_event) } -pub async fn put_jumpstart_request_on_chain( - api: &OnlineClient, - rpc: &LegacyRpcMethods, - sig_req_keyring: &Sr25519Keyring, -) { - let sig_req_account = - PairSigner::::new(sig_req_keyring.pair()); - - let registering_tx = entropy::tx().registry().jump_start_network(); - submit_transaction(api, rpc, &sig_req_account, ®istering_tx, None).await.unwrap(); -} - #[tokio::test] async fn test_compute_hash() { initialize_test_logger().await; diff --git a/crates/threshold-signature-server/tests/register_and_sign.rs b/crates/threshold-signature-server/tests/register_and_sign.rs index c2d8353dd..2ecb2403a 100644 --- a/crates/threshold-signature-server/tests/register_and_sign.rs +++ b/crates/threshold-signature-server/tests/register_and_sign.rs @@ -17,7 +17,6 @@ use entropy_client::{ chain_api::{ entropy::runtime_types::bounded_collections::bounded_vec::BoundedVec, entropy::runtime_types::pallet_registry::pallet::ProgramInstance, get_api, get_rpc, - EntropyConfig, }, client as test_client, Hasher, }; @@ -26,36 +25,36 @@ use entropy_testing_utils::{ constants::{ AUXILARY_DATA_SHOULD_SUCCEED, PREIMAGE_SHOULD_SUCCEED, TEST_PROGRAM_WASM_BYTECODE, }, - jump_start_network, spawn_testing_validators, test_node_process_testing_state, ChainSpecType, + spawn_testing_validators, test_node_process_testing_state, ChainSpecType, }; -use entropy_tss::helpers::tests::initialize_test_logger; +use entropy_tss::helpers::tests::{do_jump_start, initialize_test_logger}; use serial_test::serial; -use sp_core::{sr25519, Pair}; +use sp_core::Pair; use sp_keyring::AccountKeyring; -use subxt::{tx::PairSigner, utils::AccountId32}; +use subxt::utils::AccountId32; use synedrion::k256::ecdsa::VerifyingKey; -#[ignore] #[tokio::test] #[serial] async fn integration_test_register_and_sign() { initialize_test_logger().await; clean_tests(); - let account_owner = AccountKeyring::Ferdie.pair(); - let signature_request_author = AccountKeyring::One; let (_validator_ips, _validator_ids) = spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; + let api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); - // Jumpstart the network - let alice = AccountKeyring::Alice; - let signer = PairSigner::::new(alice.clone().into()); - jump_start_network(&api, &rpc, &signer).await; + // First jumpstart the network + do_jump_start(&api, &rpc, AccountKeyring::Alice.pair()).await; + + // Now register an account + let account_owner = AccountKeyring::Ferdie.pair(); + let signature_request_author = AccountKeyring::One; // Store a program let program_pointer = test_client::store_program( diff --git a/crates/threshold-signature-server/tests/sign_eth_tx.rs b/crates/threshold-signature-server/tests/sign_eth_tx.rs index 6fb139ec4..58656be6f 100644 --- a/crates/threshold-signature-server/tests/sign_eth_tx.rs +++ b/crates/threshold-signature-server/tests/sign_eth_tx.rs @@ -17,7 +17,6 @@ use entropy_client::{ chain_api::{ entropy::runtime_types::bounded_collections::bounded_vec::BoundedVec, entropy::runtime_types::pallet_registry::pallet::ProgramInstance, get_api, get_rpc, - EntropyConfig, }, client as test_client, Hasher, }; @@ -25,8 +24,9 @@ use entropy_kvdb::clean_tests; use entropy_protocol::{decode_verifying_key, RecoverableSignature}; use entropy_testing_utils::{ constants::{AUXILARY_DATA_SHOULD_SUCCEED, TEST_PROGRAM_WASM_BYTECODE}, - jump_start_network, spawn_testing_validators, test_node_process_testing_state, ChainSpecType, + spawn_testing_validators, test_node_process_testing_state, ChainSpecType, }; +use entropy_tss::helpers::tests::do_jump_start; use ethers_core::{ abi::ethabi::ethereum_types::{H160, H256}, types::{RecoveryMessage, Transaction, TransactionRequest, U256}, @@ -36,20 +36,17 @@ use ethers_core::{ }, }; use serial_test::serial; -use sp_core::{sr25519, Pair}; +use sp_core::Pair; use sp_keyring::AccountKeyring; -use subxt::{tx::PairSigner, utils::AccountId32}; +use subxt::utils::AccountId32; use synedrion::k256::ecdsa::VerifyingKey; const GOERLI_CHAIN_ID: u64 = 5; -#[ignore] #[tokio::test] #[serial] async fn integration_test_sign_eth_tx() { clean_tests(); - let account_owner = AccountKeyring::Ferdie.pair(); - let signature_request_author = AccountKeyring::One; let (_validator_ips, _validator_ids) = spawn_testing_validators(ChainSpecType::Integration).await; @@ -60,10 +57,11 @@ async fn integration_test_sign_eth_tx() { let api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); - // Jumpstart the network - let alice = AccountKeyring::Alice; - let signer = PairSigner::::new(alice.clone().into()); - jump_start_network(&api, &rpc, &signer).await; + // First jumpstart the network + do_jump_start(&api, &rpc, AccountKeyring::Alice.pair()).await; + + let account_owner = AccountKeyring::Ferdie.pair(); + let signature_request_author = AccountKeyring::One; // Store a program let program_pointer = test_client::store_program( From 4279ed6db225a300c597e9f846ab708184e05f1a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 07:37:32 +0000 Subject: [PATCH 07/17] Bump axum from 0.7.6 to 0.7.7 in the patch-dependencies group (#1075) Bumps the patch-dependencies group with 1 update: [axum](https://github.com/tokio-rs/axum). Updates `axum` from 0.7.6 to 0.7.7 - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.7.6...axum-v0.7.7) --- updated-dependencies: - dependency-name: axum dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 48 ++++---------------- crates/protocol/Cargo.toml | 2 +- crates/testing-utils/Cargo.toml | 2 +- crates/threshold-signature-server/Cargo.toml | 2 +- 4 files changed, 12 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b7e2d384a..5ce7bfb91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -647,13 +647,13 @@ checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "axum" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", - "base64 0.21.7", + "base64 0.22.1", "bytes", "futures-util", "http 1.1.0", @@ -675,7 +675,7 @@ dependencies = [ "sha1", "sync_wrapper 1.0.1", "tokio", - "tokio-tungstenite 0.23.1", + "tokio-tungstenite", "tower 0.5.1", "tower-layer", "tower-service", @@ -684,9 +684,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -2601,7 +2601,7 @@ dependencies = [ "synedrion", "thiserror", "tokio", - "tokio-tungstenite 0.24.0", + "tokio-tungstenite", "tracing", "wasm-bindgen", "wasm-bindgen-derive", @@ -2814,7 +2814,7 @@ dependencies = [ "tdx-quote", "thiserror", "tokio", - "tokio-tungstenite 0.24.0", + "tokio-tungstenite", "tower-http 0.6.1", "tracing", "tracing-bunyan-formatter", @@ -14392,18 +14392,6 @@ dependencies = [ "tokio-util", ] -[[package]] -name = "tokio-tungstenite" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.23.0", -] - [[package]] name = "tokio-tungstenite" version = "0.24.0" @@ -14413,7 +14401,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.24.0", + "tungstenite", ] [[package]] @@ -14849,24 +14837,6 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" -[[package]] -name = "tungstenite" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.1.0", - "httparse", - "log", - "rand", - "sha1", - "thiserror", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.24.0" diff --git a/crates/protocol/Cargo.toml b/crates/protocol/Cargo.toml index 0b9adbcc0..7f7417f7c 100644 --- a/crates/protocol/Cargo.toml +++ b/crates/protocol/Cargo.toml @@ -34,7 +34,7 @@ hpke-rs-rust-crypto="0.2.0" num ="0.4.3" # Used only with the `server` feature to implement the WsConnection trait -axum ={ version="0.7.6", features=["ws"], optional=true } +axum ={ version="0.7.7", features=["ws"], optional=true } tokio-tungstenite={ version="0.24.0", optional=true } # Used only with the `wasm` feature diff --git a/crates/testing-utils/Cargo.toml b/crates/testing-utils/Cargo.toml index 686c14f39..ad5e50a74 100644 --- a/crates/testing-utils/Cargo.toml +++ b/crates/testing-utils/Cargo.toml @@ -17,7 +17,7 @@ parity-scale-codec="3.6.12" lazy_static ="1.5.0" hex-literal ="0.4.1" tokio ={ version="1.40", features=["macros", "fs", "rt-multi-thread", "io-util", "process"] } -axum ={ version="0.7.5" } +axum ={ version="0.7.7" } entropy-shared ={ version="0.2.0", path="../shared" } entropy-kvdb ={ version="0.2.0", path="../kvdb", default-features=false } entropy-tss ={ version="0.2.0", path="../threshold-signature-server", features=["test_helpers"] } diff --git a/crates/threshold-signature-server/Cargo.toml b/crates/threshold-signature-server/Cargo.toml index e8f20d734..2b5629d32 100644 --- a/crates/threshold-signature-server/Cargo.toml +++ b/crates/threshold-signature-server/Cargo.toml @@ -32,7 +32,7 @@ tokio ={ version="1.40", features=["macros", "fs", "rt-multi-thread", "io-util" # HTTP reqwest={ version="0.12.7", features=["json", "stream"] } -axum ={ version="0.7.6", features=["ws"] } +axum ={ version="0.7.7", features=["ws"] } # Substrate subxt ="0.35.3" From 508f6ef75db7153ed7f293f651e0163fa905575c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:15:24 +0200 Subject: [PATCH 08/17] Bump tempfile from 3.12.0 to 3.13.0 (#1076) Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.12.0 to 3.13.0. - [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md) - [Commits](https://github.com/Stebalien/tempfile/compare/v3.12.0...v3.13.0) --- updated-dependencies: - dependency-name: tempfile dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 50 ++++++++++++++++++++++----------------------- node/cli/Cargo.toml | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ce7bfb91..4174f76c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -511,7 +511,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 0.38.32", + "rustix 0.38.37", "slab", "tracing", "windows-sys 0.52.0", @@ -563,7 +563,7 @@ dependencies = [ "cfg-if", "event-listener 5.3.0", "futures-lite", - "rustix 0.38.32", + "rustix 0.38.37", "tracing", "windows-sys 0.52.0", ] @@ -580,7 +580,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.32", + "rustix 0.38.37", "signal-hook-registry", "slab", "windows-sys 0.48.0", @@ -3058,9 +3058,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fdlimit" @@ -3668,7 +3668,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" dependencies = [ - "rustix 0.38.32", + "rustix 0.38.37", "windows-sys 0.48.0", ] @@ -5148,9 +5148,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libloading" @@ -5686,9 +5686,9 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lioness" @@ -5896,7 +5896,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.38.32", + "rustix 0.38.37", ] [[package]] @@ -8075,7 +8075,7 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite 0.2.14", - "rustix 0.38.32", + "rustix 0.38.37", "tracing", "windows-sys 0.52.0", ] @@ -9029,14 +9029,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.5.0", "errno", "libc", - "linux-raw-sys 0.4.13", + "linux-raw-sys 0.4.14", "windows-sys 0.52.0", ] @@ -14150,14 +14150,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", "once_cell", - "rustix 0.38.32", + "rustix 0.38.37", "windows-sys 0.59.0", ] @@ -14176,7 +14176,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.32", + "rustix 0.38.37", "windows-sys 0.48.0", ] @@ -15526,7 +15526,7 @@ dependencies = [ "directories-next", "file-per-thread-logger 0.2.0", "log", - "rustix 0.38.32", + "rustix 0.38.37", "serde", "sha2 0.10.8", "toml 0.5.11", @@ -15681,7 +15681,7 @@ checksum = "fc8c8410c03a79073ea06806ccde3da4854c646bd646b3b2707b99b3746c3f70" dependencies = [ "cc", "cfg-if", - "rustix 0.38.32", + "rustix 0.38.37", "wasmtime-asm-macros 12.0.2", "wasmtime-versioned-export-macros", "windows-sys 0.48.0", @@ -15727,7 +15727,7 @@ dependencies = [ "log", "object 0.31.1", "rustc-demangle", - "rustix 0.38.32", + "rustix 0.38.37", "serde", "target-lexicon", "wasmtime-environ 12.0.2", @@ -15756,7 +15756,7 @@ checksum = "aef27ea6c34ef888030d15560037fe7ef27a5609fbbba8e1e3e41dc4245f5bb2" dependencies = [ "object 0.31.1", "once_cell", - "rustix 0.38.32", + "rustix 0.38.37", "wasmtime-versioned-export-macros", ] @@ -15824,7 +15824,7 @@ dependencies = [ "memoffset 0.9.1", "paste", "rand", - "rustix 0.38.32", + "rustix 0.38.37", "sptr", "wasm-encoder 0.31.1", "wasmtime-asm-macros 12.0.2", @@ -15959,7 +15959,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.32", + "rustix 0.38.37", ] [[package]] diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 9fe29671e..e1305e632 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -106,7 +106,7 @@ substrate-build-script-utils={ version="11.0.0" } try-runtime-cli ={ version="0.42.0" } [dev-dependencies] -tempfile ="3.12.0" +tempfile ="3.13.0" sp-tracing={ version="16.0.0" } [features] From 61c77d4fe18765bce269560a9753ac848e6880db Mon Sep 17 00:00:00 2001 From: JesseAbram <33698952+JesseAbram@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:23:58 -0400 Subject: [PATCH 09/17] Run multiple test validator (#1074) * run multiple test validators * change same tss_endpoints * fix test --- crates/client/src/tests.rs | 2 +- crates/shared/src/constants.rs | 2 +- crates/testing-utils/src/helpers.rs | 2 +- crates/testing-utils/src/node_proc.rs | 33 +++++++- crates/testing-utils/src/substrate_context.rs | 75 +++++++++++++++---- .../src/signing_client/tests.rs | 2 +- .../src/user/tests.rs | 24 +++--- .../src/validator/tests.rs | 4 +- .../tests/register_and_sign.rs | 2 +- .../tests/sign_eth_tx.rs | 2 +- 10 files changed, 110 insertions(+), 38 deletions(-) diff --git a/crates/client/src/tests.rs b/crates/client/src/tests.rs index f84b221d9..819bf8bae 100644 --- a/crates/client/src/tests.rs +++ b/crates/client/src/tests.rs @@ -138,7 +138,7 @@ async fn test_remove_program_reference_counter() { spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); diff --git a/crates/shared/src/constants.rs b/crates/shared/src/constants.rs index 20304caa9..c2bc4d689 100644 --- a/crates/shared/src/constants.rs +++ b/crates/shared/src/constants.rs @@ -75,7 +75,7 @@ pub const MAX_SIGNERS: u8 = 15; pub const SIGNER_THRESHOLD: u8 = 2; /// For testing to line up chain mock data and reshare_test -pub const TEST_RESHARE_BLOCK_NUMBER: u32 = 5; +pub const TEST_RESHARE_BLOCK_NUMBER: u32 = 7; /// Program version number, must be incremented if version number changes pub const PROGRAM_VERSION_NUMBER: u8 = 0; diff --git a/crates/testing-utils/src/helpers.rs b/crates/testing-utils/src/helpers.rs index 246720958..9da5745e3 100644 --- a/crates/testing-utils/src/helpers.rs +++ b/crates/testing-utils/src/helpers.rs @@ -43,7 +43,7 @@ pub async fn spawn_tss_nodes_and_start_chain( // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &&test_node_process_testing_state(force_authoring).await[0]; ( get_api(&substrate_context.ws_url).await.unwrap(), get_rpc(&substrate_context.ws_url).await.unwrap(), diff --git a/crates/testing-utils/src/node_proc.rs b/crates/testing-utils/src/node_proc.rs index bc52588f3..9fd860329 100644 --- a/crates/testing-utils/src/node_proc.rs +++ b/crates/testing-utils/src/node_proc.rs @@ -45,11 +45,17 @@ where R: Config, { /// Construct a builder for spawning a test node process. - pub fn build(program: S, chain_type: String, force_authoring: bool) -> TestNodeProcessBuilder + pub fn build( + program: S, + chain_type: String, + force_authoring: bool, + bootnode: Option, + threshold_url: Option, + ) -> TestNodeProcessBuilder where S: AsRef + Clone, { - TestNodeProcessBuilder::new(program, chain_type, force_authoring) + TestNodeProcessBuilder::new(program, chain_type, force_authoring, bootnode, threshold_url) } /// Attempt to kill the running substrate process. @@ -76,10 +82,18 @@ pub struct TestNodeProcessBuilder { scan_port_range: bool, chain_type: String, force_authoring: bool, + bootnode: Option, + tss_server_endpoint: Option, } impl TestNodeProcessBuilder { - pub fn new

(node_path: P, chain_type: String, force_authoring: bool) -> TestNodeProcessBuilder + pub fn new

( + node_path: P, + chain_type: String, + force_authoring: bool, + bootnode: Option, + tss_server_endpoint: Option, + ) -> TestNodeProcessBuilder where P: AsRef, { @@ -89,6 +103,8 @@ impl TestNodeProcessBuilder { scan_port_range: false, chain_type, force_authoring, + bootnode, + tss_server_endpoint, } } @@ -122,10 +138,19 @@ impl TestNodeProcessBuilder { cmd.arg(arg); } + if let Some(bootnode) = &self.bootnode { + let arg = format!("--bootnodes={}", bootnode.as_str()); + cmd.arg(arg); + } + + if let Some(tss_server_endpoint) = &self.tss_server_endpoint { + let arg = format!("--tss-server-endpoint={}", tss_server_endpoint.as_str()); + cmd.arg(arg); + } + let ws_port = if self.scan_port_range { let (p2p_port, _http_port, ws_port) = next_open_port() .ok_or_else(|| "No available ports in the given port range".to_owned())?; - cmd.arg(format!("--port={p2p_port}")); cmd.arg(format!("--rpc-port={ws_port}")); tracing::info!("ws port: {ws_port}"); diff --git a/crates/testing-utils/src/substrate_context.rs b/crates/testing-utils/src/substrate_context.rs index 2382cb0fd..7571e3c09 100644 --- a/crates/testing-utils/src/substrate_context.rs +++ b/crates/testing-utils/src/substrate_context.rs @@ -18,7 +18,6 @@ use subxt::{config::substrate::SubstrateExtrinsicParams, OnlineClient}; use super::node_proc::TestNodeProcess; use crate::chain_api::*; - /// Verifies that the Entropy node binary exists. /// /// If a path is provided using the `ENTROPY_NODE` environment variable, that will take priority. @@ -62,15 +61,23 @@ pub async fn test_node_process_with( key: AccountKeyring, chain_type: String, force_authoring: bool, + bootnode: Option, + tss_server_endpoint: Option, ) -> TestNodeProcess { let path = get_path(); let path = path.to_str().expect("Path should've been checked to be valid earlier."); - let proc = TestNodeProcess::::build(path, chain_type, force_authoring) - .with_authority(key) - .scan_for_open_ports() - .spawn::() - .await; + let proc = TestNodeProcess::::build( + path, + chain_type, + force_authoring, + bootnode, + tss_server_endpoint, + ) + .with_authority(key) + .scan_for_open_ports() + .spawn::() + .await; proc.unwrap() } @@ -78,23 +85,25 @@ pub async fn test_node( key: AccountKeyring, chain_type: String, force_authoring: bool, + bootnode: Option, ) -> TestNodeProcess { let path = get_path(); let path = path.to_str().expect("Path should've been checked to be valid earlier."); - let proc = TestNodeProcess::::build(path, chain_type, force_authoring) - .with_authority(key) - .spawn::() - .await; + let proc = + TestNodeProcess::::build(path, chain_type, force_authoring, bootnode, None) + .with_authority(key) + .spawn::() + .await; proc.unwrap() } pub async fn test_node_process() -> TestNodeProcess { - test_node_process_with(AccountKeyring::Alice, "--dev".to_string(), false).await + test_node_process_with(AccountKeyring::Alice, "--dev".to_string(), false, None, None).await } pub async fn test_node_process_stationary() -> TestNodeProcess { - test_node(AccountKeyring::Alice, "--dev".to_string(), false).await + test_node(AccountKeyring::Alice, "--dev".to_string(), false, None).await } /// Tests chain with test state in chain config @@ -102,8 +111,46 @@ pub async fn test_node_process_stationary() -> TestNodeProcess { /// Allowing `force_authoring` will produce blocks. pub async fn test_node_process_testing_state( force_authoring: bool, -) -> TestNodeProcess { - test_node(AccountKeyring::Alice, "--chain=integration-tests".to_string(), force_authoring).await +) -> Vec> { + let alice_bootnode = Some( + "/ip4/127.0.0.1/tcp/30333/p2p/12D3KooWM7EoKJfwgzAR1nAVmYRuuFq2f3GpJPLrdfhQaRsKjn38" + .to_string(), + ); + // reduses message from chain to same TSS cleaning up a lot of logging + let fuck_off_tss_ip = Some("127.0.0.1:4010".to_string()); + let result = test_node( + AccountKeyring::Alice, + "--chain=integration-tests".to_string(), + force_authoring, + None, + ) + .await; + let result_bob = test_node_process_with( + AccountKeyring::Bob, + "--chain=integration-tests".to_string(), + force_authoring, + alice_bootnode.clone(), + fuck_off_tss_ip.clone(), + ) + .await; + let result_charlie = test_node_process_with( + AccountKeyring::Charlie, + "--chain=integration-tests".to_string(), + force_authoring, + alice_bootnode.clone(), + fuck_off_tss_ip.clone(), + ) + .await; + let result_dave = test_node_process_with( + AccountKeyring::Dave, + "--chain=integration-tests".to_string(), + force_authoring, + alice_bootnode.clone(), + fuck_off_tss_ip.clone(), + ) + .await; + + vec![result, result_bob, result_charlie, result_dave] } /// Spins up Substrate node and a connected `subxt` client. diff --git a/crates/threshold-signature-server/src/signing_client/tests.rs b/crates/threshold-signature-server/src/signing_client/tests.rs index e1822ea44..d5b9d454d 100644 --- a/crates/threshold-signature-server/src/signing_client/tests.rs +++ b/crates/threshold-signature-server/src/signing_client/tests.rs @@ -44,7 +44,7 @@ use sp_keyring::AccountKeyring; async fn test_proactive_refresh() { initialize_test_logger().await; clean_tests(); - let _cxt = test_node_process_testing_state(false).await; + let _cxt = &test_node_process_testing_state(false).await[0]; let (validator_ips, _ids) = spawn_testing_validators(ChainSpecType::Integration).await; let signing_committee_ips = &validator_ips[..3].to_vec(); diff --git a/crates/threshold-signature-server/src/user/tests.rs b/crates/threshold-signature-server/src/user/tests.rs index 2379d3920..99226ae1e 100644 --- a/crates/threshold-signature-server/src/user/tests.rs +++ b/crates/threshold-signature-server/src/user/tests.rs @@ -182,7 +182,7 @@ async fn test_signature_requests_fail_on_different_conditions() { // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -418,7 +418,7 @@ async fn test_signature_requests_fail_validator_info_wrong() { // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -495,7 +495,7 @@ async fn signature_request_with_derived_account_works() { // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -540,7 +540,7 @@ async fn test_signing_fails_if_wrong_participants_are_used() { spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -658,7 +658,7 @@ async fn test_request_limit_are_updated_during_signing() { spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -763,7 +763,7 @@ async fn test_fails_to_sign_if_non_signing_group_participants_are_used() { spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -863,7 +863,7 @@ async fn test_program_with_config() { spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -949,7 +949,7 @@ async fn test_jumpstart_network() { spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -1103,7 +1103,7 @@ async fn test_fail_infinite_program() { get_signer_and_x25519_secret_from_mnemonic(&mnemonic.to_string()).unwrap(); let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -1199,7 +1199,7 @@ async fn test_device_key_proxy() { // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -1336,7 +1336,7 @@ async fn test_faucet() { let (_validator_ips, _validator_ids) = spawn_testing_validators(ChainSpecType::Development).await; let relayer_ip_and_key = ("localhost:3001".to_string(), X25519_PUBLIC_KEYS[0]); - let substrate_context = test_node_process_testing_state(true).await; + let substrate_context = &test_node_process_testing_state(true).await[0]; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); @@ -1493,7 +1493,7 @@ async fn test_registration_flow() { // Here we need to use `--chain=integration-tests` and force authoring otherwise we won't be // able to get our chain in the right state to be jump started. let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let entropy_api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); diff --git a/crates/threshold-signature-server/src/validator/tests.rs b/crates/threshold-signature-server/src/validator/tests.rs index ffa4ab534..20190b421 100644 --- a/crates/threshold-signature-server/src/validator/tests.rs +++ b/crates/threshold-signature-server/src/validator/tests.rs @@ -71,7 +71,7 @@ async fn test_reshare() { initialize_test_logger().await; clean_tests(); - let cxt = test_node_process_testing_state(true).await; + let cxt = &test_node_process_testing_state(true).await[0]; let (_validator_ips, _validator_ids) = spawn_testing_validators(ChainSpecType::Integration).await; @@ -316,7 +316,7 @@ async fn test_reshare_validation_fail() { clean_tests(); let dave = AccountKeyring::Dave; - let cxt = test_node_process_testing_state(true).await; + let cxt = &test_node_process_testing_state(true).await[0]; let api = get_api(&cxt.ws_url).await.unwrap(); let rpc = get_rpc(&cxt.ws_url).await.unwrap(); let kv = setup_client().await; diff --git a/crates/threshold-signature-server/tests/register_and_sign.rs b/crates/threshold-signature-server/tests/register_and_sign.rs index 2ecb2403a..5dc3921f5 100644 --- a/crates/threshold-signature-server/tests/register_and_sign.rs +++ b/crates/threshold-signature-server/tests/register_and_sign.rs @@ -44,7 +44,7 @@ async fn integration_test_register_and_sign() { spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); diff --git a/crates/threshold-signature-server/tests/sign_eth_tx.rs b/crates/threshold-signature-server/tests/sign_eth_tx.rs index 58656be6f..16f946baf 100644 --- a/crates/threshold-signature-server/tests/sign_eth_tx.rs +++ b/crates/threshold-signature-server/tests/sign_eth_tx.rs @@ -52,7 +52,7 @@ async fn integration_test_sign_eth_tx() { spawn_testing_validators(ChainSpecType::Integration).await; let force_authoring = true; - let substrate_context = test_node_process_testing_state(force_authoring).await; + let substrate_context = &test_node_process_testing_state(force_authoring).await[0]; let api = get_api(&substrate_context.ws_url).await.unwrap(); let rpc = get_rpc(&substrate_context.ws_url).await.unwrap(); From c5bb5cca1fbe17f58159216f5bfac8366e25cdeb Mon Sep 17 00:00:00 2001 From: JesseAbram <33698952+JesseAbram@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:50:44 -0400 Subject: [PATCH 10/17] Block tss chain when signer (#1078) * Block tss change when next signer * benches * changelog --- CHANGELOG.md | 1 + pallets/staking/src/benchmarking.rs | 5 +- pallets/staking/src/lib.rs | 14 ++- pallets/staking/src/tests.rs | 6 ++ pallets/staking/src/weights.rs | 52 +++++++---- .../src/weights/pallet_staking_extension.rs | 90 ++++++++++--------- 6 files changed, 101 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8151e4c9..f74fd62a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ At the moment this project **does not** adhere to - Select validators for jumpstart DKG [#1053](https://github.com/entropyxyz/entropy-core/pull/1053)) - Add a programs version ([#1045](https://github.com/entropyxyz/entropy-core/pull/1045)) - Handle Provisioning Certification Keys (PCKs) ([#1051](https://github.com/entropyxyz/entropy-core/pull/1051)) +- Block tss chain when signer ([#1078](https://github.com/entropyxyz/entropy-core/pull/1078)) ### Changed - Fix TSS `AccountId` keys in chainspec ([#993](https://github.com/entropyxyz/entropy-core/pull/993)) diff --git a/pallets/staking/src/benchmarking.rs b/pallets/staking/src/benchmarking.rs index 3b9d612b9..6e3731f2f 100644 --- a/pallets/staking/src/benchmarking.rs +++ b/pallets/staking/src/benchmarking.rs @@ -122,14 +122,17 @@ benchmarks! { } change_threshold_accounts { + let s in 0 .. MAX_SIGNERS as u32; let caller: T::AccountId = whitelisted_caller(); let _bonder: T::AccountId = account("bond", 0, SEED); let validator_id_res = ::ValidatorId::try_from(_bonder.clone()).or(Err(Error::::InvalidValidatorId)); + let validator_id_signers = ::ValidatorId::try_from(caller.clone()).or(Err(Error::::InvalidValidatorId)).unwrap(); let bonder: T::ValidatorId = validator_id_res.expect("Issue converting account id into validator id"); let threshold: T::AccountId = account("threshold", 0, SEED); let x25519_public_key: [u8; 32] = NULL_ARR; prep_bond_and_validate::(true, caller.clone(), _bonder.clone(), threshold, NULL_ARR); - + let signers = vec![validator_id_signers.clone(); s as usize]; + Signers::::put(signers.clone()); }: _(RawOrigin::Signed(_bonder.clone()), _bonder.clone(), NULL_ARR) verify { diff --git a/pallets/staking/src/lib.rs b/pallets/staking/src/lib.rs index c83e94eef..6fafa0a00 100644 --- a/pallets/staking/src/lib.rs +++ b/pallets/staking/src/lib.rs @@ -311,6 +311,7 @@ pub mod pallet { NoUnbondingWhenNextSigner, NoUnnominatingWhenSigner, NoUnnominatingWhenNextSigner, + NoChangingThresholdAccountWhenSigner, } #[pallet::event] @@ -373,12 +374,12 @@ pub mod pallet { /// Allows a validator to change their threshold key so can confirm done when coms manager /// `new_account`: nodes's threshold account #[pallet::call_index(1)] - #[pallet::weight(::WeightInfo::change_threshold_accounts())] + #[pallet::weight(::WeightInfo::change_threshold_accounts(MAX_SIGNERS as u32))] pub fn change_threshold_accounts( origin: OriginFor, tss_account: T::AccountId, x25519_public_key: X25519PublicKey, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { ensure!( !ThresholdToStash::::contains_key(&tss_account), Error::::TssAccountAlreadyExists @@ -389,6 +390,12 @@ pub mod pallet { let validator_id = ::ValidatorId::try_from(stash) .or(Err(Error::::InvalidValidatorId))?; + let signers = Self::signers(); + ensure!( + !signers.contains(&validator_id), + Error::::NoChangingThresholdAccountWhenSigner + ); + let new_server_info: ServerInfo = ThresholdServers::::try_mutate(&validator_id, |maybe_server_info| { if let Some(server_info) = maybe_server_info { @@ -401,7 +408,8 @@ pub mod pallet { } })?; Self::deposit_event(Event::ThresholdAccountChanged(validator_id, new_server_info)); - Ok(()) + Ok(Some(::WeightInfo::change_threshold_accounts(signers.len() as u32)) + .into()) } /// Wraps's Substrate's `unbond` extrinsic but checks to make sure targeted account is not a signer or next signer diff --git a/pallets/staking/src/tests.rs b/pallets/staking/src/tests.rs index 70c0c80a5..b4ae4137b 100644 --- a/pallets/staking/src/tests.rs +++ b/pallets/staking/src/tests.rs @@ -233,6 +233,12 @@ fn it_changes_threshold_account() { Staking::change_threshold_accounts(RuntimeOrigin::signed(1), 5, NULL_ARR), Error::::TssAccountAlreadyExists ); + + Signers::::put(vec![1]); + assert_noop!( + Staking::change_threshold_accounts(RuntimeOrigin::signed(1), 9, NULL_ARR,), + Error::::NoChangingThresholdAccountWhenSigner + ); }); } diff --git a/pallets/staking/src/weights.rs b/pallets/staking/src/weights.rs index fedc25021..5faf7880e 100644 --- a/pallets/staking/src/weights.rs +++ b/pallets/staking/src/weights.rs @@ -53,7 +53,7 @@ use core::marker::PhantomData; /// Weight functions needed for pallet_staking_extension. pub trait WeightInfo { fn change_endpoint() -> Weight; - fn change_threshold_accounts() -> Weight; + fn change_threshold_accounts(s: u32) -> Weight; fn chill(c: u32, n: u32) -> Weight; fn unbond(c: u32, n: u32) -> Weight; fn withdraw_unbonded(c: u32, n: u32) -> Weight; @@ -81,20 +81,27 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: `StakingExtension::ThresholdToStash` (r:1 w:1) + /// Proof: `StakingExtension::ThresholdToStash` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `StakingExtension::ThresholdServers` (r:1 w:1) /// Proof: `StakingExtension::ThresholdServers` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `StakingExtension::ThresholdToStash` (r:0 w:1) - /// Proof: `StakingExtension::ThresholdToStash` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn change_threshold_accounts() -> Weight { + /// The range of component `s` is `[0, 15]`. + fn change_threshold_accounts(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1118` - // Estimated: `4583` - // Minimum execution time: 23_000_000 picoseconds. - Weight::from_parts(24_000_000, 4583) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + // Measured: `1455 + s * (32 ±0)` + // Estimated: `4918 + s * (32 ±0)` + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(31_058_011, 0) + .saturating_add(Weight::from_parts(0, 4918)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(s.into())) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -349,20 +356,27 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: `StakingExtension::ThresholdToStash` (r:1 w:1) + /// Proof: `StakingExtension::ThresholdToStash` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Staking::Ledger` (r:1 w:0) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) + /// Storage: `Staking::Bonded` (r:1 w:0) + /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `StakingExtension::ThresholdServers` (r:1 w:1) /// Proof: `StakingExtension::ThresholdServers` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `StakingExtension::ThresholdToStash` (r:0 w:1) - /// Proof: `StakingExtension::ThresholdToStash` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn change_threshold_accounts() -> Weight { + /// The range of component `s` is `[0, 15]`. + fn change_threshold_accounts(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1118` - // Estimated: `4583` - // Minimum execution time: 23_000_000 picoseconds. - Weight::from_parts(24_000_000, 4583) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + // Measured: `1455 + s * (32 ±0)` + // Estimated: `4918 + s * (32 ±0)` + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(31_058_011, 0) + .saturating_add(Weight::from_parts(0, 4918)) + .saturating_add(RocksDbWeight::get().reads(5)) + .saturating_add(RocksDbWeight::get().writes(2)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(s.into())) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) diff --git a/runtime/src/weights/pallet_staking_extension.rs b/runtime/src/weights/pallet_staking_extension.rs index 158c1fb48..6364cbdef 100644 --- a/runtime/src/weights/pallet_staking_extension.rs +++ b/runtime/src/weights/pallet_staking_extension.rs @@ -16,7 +16,7 @@ //! Autogenerated weights for `pallet_staking_extension` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 33.0.0 -//! DATE: 2024-09-21, STEPS: `5`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-09-30, STEPS: `5`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `Jesses-MacBook-Pro.local`, CPU: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 @@ -53,11 +53,11 @@ impl pallet_staking_extension::WeightInfo for WeightInf /// Proof: `StakingExtension::ThresholdServers` (`max_values`: None, `max_size`: None, mode: `Measured`) fn change_endpoint() -> Weight { // Proof Size summary in bytes: - // Measured: `1309` - // Estimated: `4774` - // Minimum execution time: 24_000_000 picoseconds. - Weight::from_parts(26_000_000, 0) - .saturating_add(Weight::from_parts(0, 4774)) + // Measured: `1310` + // Estimated: `4775` + // Minimum execution time: 22_000_000 picoseconds. + Weight::from_parts(24_000_000, 0) + .saturating_add(Weight::from_parts(0, 4775)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -67,17 +67,21 @@ impl pallet_staking_extension::WeightInfo for WeightInf /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) /// Storage: `Staking::Bonded` (r:1 w:0) /// Proof: `Staking::Bonded` (`max_values`: None, `max_size`: Some(72), added: 2547, mode: `MaxEncodedLen`) + /// Storage: `StakingExtension::Signers` (r:1 w:0) + /// Proof: `StakingExtension::Signers` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `StakingExtension::ThresholdServers` (r:1 w:1) /// Proof: `StakingExtension::ThresholdServers` (`max_values`: None, `max_size`: None, mode: `Measured`) - fn change_threshold_accounts() -> Weight { + /// The range of component `s` is `[0, 15]`. + fn change_threshold_accounts(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1430` - // Estimated: `4895` - // Minimum execution time: 28_000_000 picoseconds. - Weight::from_parts(28_000_000, 0) - .saturating_add(Weight::from_parts(0, 4895)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `1455 + s * (32 ±0)` + // Estimated: `4918 + s * (32 ±0)` + // Minimum execution time: 27_000_000 picoseconds. + Weight::from_parts(31_058_011, 0) + .saturating_add(Weight::from_parts(0, 4918)) + .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(s.into())) } /// Storage: `Staking::Ledger` (r:1 w:1) /// Proof: `Staking::Ledger` (`max_values`: None, `max_size`: Some(1091), added: 3566, mode: `MaxEncodedLen`) @@ -107,13 +111,13 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `1986 + n * (32 ±0) + s * (64 ±0)` // Estimated: `4764 + n * (32 ±0) + s * (64 ±0)` - // Minimum execution time: 72_000_000 picoseconds. - Weight::from_parts(71_588_925, 0) + // Minimum execution time: 70_000_000 picoseconds. + Weight::from_parts(66_699_022, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 254_432 - .saturating_add(Weight::from_parts(266_286, 0).saturating_mul(s.into())) - // Standard Error: 244_899 - .saturating_add(Weight::from_parts(241_693, 0).saturating_mul(n.into())) + // Standard Error: 268_057 + .saturating_add(Weight::from_parts(210_260, 0).saturating_mul(s.into())) + // Standard Error: 258_014 + .saturating_add(Weight::from_parts(711_767, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(n.into())) @@ -145,13 +149,11 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `1864 + c * (64 ±0) + n * (32 ±0)` // Estimated: `6248 + c * (64 ±0) + n * (32 ±0)` - // Minimum execution time: 59_000_000 picoseconds. - Weight::from_parts(57_194_136, 0) + // Minimum execution time: 55_000_000 picoseconds. + Weight::from_parts(60_245_602, 0) .saturating_add(Weight::from_parts(0, 6248)) - // Standard Error: 195_789 - .saturating_add(Weight::from_parts(161_563, 0).saturating_mul(c.into())) - // Standard Error: 188_454 - .saturating_add(Weight::from_parts(295_602, 0).saturating_mul(n.into())) + // Standard Error: 151_233 + .saturating_add(Weight::from_parts(59_201, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(11)) .saturating_add(T::DbWeight::get().writes(6)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(c.into())) @@ -181,13 +183,9 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `1534 + c * (64 ±0) + n * (32 ±0)` // Estimated: `4764 + c * (64 ±0) + n * (32 ±0)` - // Minimum execution time: 47_000_000 picoseconds. - Weight::from_parts(47_473_941, 0) + // Minimum execution time: 46_000_000 picoseconds. + Weight::from_parts(56_933_876, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 190_804 - .saturating_add(Weight::from_parts(73_615, 0).saturating_mul(c.into())) - // Standard Error: 183_655 - .saturating_add(Weight::from_parts(405_456, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(c.into())) @@ -223,8 +221,8 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `1918` // Estimated: `6248` - // Minimum execution time: 64_000_000 picoseconds. - Weight::from_parts(66_000_000, 0) + // Minimum execution time: 61_000_000 picoseconds. + Weight::from_parts(68_000_000, 0) .saturating_add(Weight::from_parts(0, 6248)) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(8)) @@ -237,8 +235,8 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `320` // Estimated: `3785` - // Minimum execution time: 9_000_000 picoseconds. - Weight::from_parts(18_000_000, 0) + // Minimum execution time: 10_000_000 picoseconds. + Weight::from_parts(10_000_000, 0) .saturating_add(Weight::from_parts(0, 3785)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -253,10 +251,10 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Measured: `797 + c * (32 ±0)` // Estimated: `4298 + c * (29 ±1)` // Minimum execution time: 11_000_000 picoseconds. - Weight::from_parts(11_715_469, 0) + Weight::from_parts(11_892_265, 0) .saturating_add(Weight::from_parts(0, 4298)) - // Standard Error: 48_988 - .saturating_add(Weight::from_parts(11_740, 0).saturating_mul(c.into())) + // Standard Error: 236_921 + .saturating_add(Weight::from_parts(181_629, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 29).saturating_mul(c.into())) @@ -273,7 +271,7 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `1309` // Estimated: `4774` - // Minimum execution time: 11_000_000 picoseconds. + // Minimum execution time: 13_000_000 picoseconds. Weight::from_parts(13_000_000, 0) .saturating_add(Weight::from_parts(0, 4774)) .saturating_add(T::DbWeight::get().reads(2)) @@ -289,8 +287,10 @@ impl pallet_staking_extension::WeightInfo for WeightInf // Measured: `266 + s * (32 ±0)` // Estimated: `1751 + s * (32 ±0)` // Minimum execution time: 5_000_000 picoseconds. - Weight::from_parts(6_171_206, 0) + Weight::from_parts(6_448_443, 0) .saturating_add(Weight::from_parts(0, 1751)) + // Standard Error: 246_978 + .saturating_add(Weight::from_parts(18_482, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(s.into())) } @@ -310,15 +310,17 @@ impl pallet_staking_extension::WeightInfo for WeightInf /// Proof: `StakingExtension::NextSigners` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// The range of component `c` is `[1, 14]`. /// The range of component `l` is `[0, 15]`. - fn new_session(c: u32, _l: u32, ) -> Weight { + fn new_session(c: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `494 + c * (32 ±0)` // Estimated: `1978 + c * (32 ±0)` // Minimum execution time: 12_000_000 picoseconds. - Weight::from_parts(12_883_398, 0) + Weight::from_parts(12_568_591, 0) .saturating_add(Weight::from_parts(0, 1978)) - // Standard Error: 33_391 - .saturating_add(Weight::from_parts(69_713, 0).saturating_mul(c.into())) + // Standard Error: 87_519 + .saturating_add(Weight::from_parts(2_584, 0).saturating_mul(c.into())) + // Standard Error: 74_987 + .saturating_add(Weight::from_parts(69_217, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(c.into())) From 1c0f1af4b187f42c9cbbe369289588c9ada4d2ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 07:41:31 +0000 Subject: [PATCH 11/17] Bump reqwest from 0.12.7 to 0.12.8 in the patch-dependencies group (#1082) Bumps the patch-dependencies group with 1 update: [reqwest](https://github.com/seanmonstar/reqwest). Updates `reqwest` from 0.12.7 to 0.12.8 - [Release notes](https://github.com/seanmonstar/reqwest/releases) - [Changelog](https://github.com/seanmonstar/reqwest/blob/master/CHANGELOG.md) - [Commits](https://github.com/seanmonstar/reqwest/compare/v0.12.7...v0.12.8) --- updated-dependencies: - dependency-name: reqwest dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- crates/client/Cargo.toml | 2 +- crates/threshold-signature-server/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4174f76c0..807a0ba74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8785,9 +8785,9 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.12.7" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", diff --git a/crates/client/Cargo.toml b/crates/client/Cargo.toml index 5da179d02..7f5f68d42 100644 --- a/crates/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -26,7 +26,7 @@ rand_core ={ version="0.6.4", optional=true } serde_json ={ version="1.0", optional=true } x25519-dalek ={ version="2.0.1", features=["static_secrets"], optional=true } entropy-protocol={ version="0.2.0", path="../protocol", optional=true, default-features=false } -reqwest ={ version="0.12.7", features=["json", "stream"], optional=true } +reqwest ={ version="0.12.8", features=["json", "stream"], optional=true } base64 ={ version="0.22.0", optional=true } synedrion ={ git="https://github.com/entropyxyz/synedrion", rev="1d210d149dfeb0dca1dd41d7fac4d0bf03c686fa", optional=true } hex ={ version="0.4.3", optional=true } diff --git a/crates/threshold-signature-server/Cargo.toml b/crates/threshold-signature-server/Cargo.toml index 2b5629d32..bd49ebd0d 100644 --- a/crates/threshold-signature-server/Cargo.toml +++ b/crates/threshold-signature-server/Cargo.toml @@ -31,7 +31,7 @@ futures="0.3" tokio ={ version="1.40", features=["macros", "fs", "rt-multi-thread", "io-util", "process", "sync"] } # HTTP -reqwest={ version="0.12.7", features=["json", "stream"] } +reqwest={ version="0.12.8", features=["json", "stream"] } axum ={ version="0.7.7", features=["ws"] } # Substrate From 0b8d54a472d5dd01c758a87bf0da72da391fde5e Mon Sep 17 00:00:00 2001 From: JesseAbram <33698952+JesseAbram@users.noreply.github.com> Date: Tue, 1 Oct 2024 09:02:42 -0400 Subject: [PATCH 12/17] Fix master build (#1079) * Fix master build * fix --- .../src/helpers/tests.rs | 43 ++++++++++++------- .../src/validator/tests.rs | 2 +- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/crates/threshold-signature-server/src/helpers/tests.rs b/crates/threshold-signature-server/src/helpers/tests.rs index abbbb9ffc..71a72e099 100644 --- a/crates/threshold-signature-server/src/helpers/tests.rs +++ b/crates/threshold-signature-server/src/helpers/tests.rs @@ -21,7 +21,10 @@ use crate::{ app, chain_api::{ - entropy::{self, runtime_types::bounded_collections::bounded_vec::BoundedVec}, + entropy::{ + self, runtime_types::bounded_collections::bounded_vec::BoundedVec, + runtime_types::pallet_staking_extension::pallet::JumpStartStatus, + }, EntropyConfig, }, get_signer, @@ -49,7 +52,7 @@ use futures::future::join_all; use parity_scale_codec::Encode; use std::time::Duration; use subxt::{ - backend::legacy::LegacyRpcMethods, events::EventsClient, ext::sp_core::sr25519, tx::PairSigner, + backend::legacy::LegacyRpcMethods, ext::sp_core::sr25519, tx::PairSigner, utils::AccountId32 as SubxtAccountId32, Config, OnlineClient, }; use tokio::sync::OnceCell; @@ -389,23 +392,31 @@ pub async fn do_jump_start( .collect::>(), ) .await; - for response_result in response_results { - assert_eq!(response_result.unwrap().text().await.unwrap(), ""); + + let jump_start_status_query = entropy::storage().staking_extension().jump_start_progress(); + let mut jump_start_status = query_chain(api, rpc, jump_start_status_query.clone(), None) + .await + .unwrap() + .unwrap() + .jump_start_status; + let mut i = 0; + while format!("{:?}", jump_start_status) != format!("{:?}", JumpStartStatus::Done) { + tokio::time::sleep(Duration::from_secs(1)).await; + jump_start_status = query_chain(api, rpc, jump_start_status_query.clone(), None) + .await + .unwrap() + .unwrap() + .jump_start_status; + i += 1; + if i > 75 { + panic!("Jump start failed"); + } } - // Wait for jump start event - let mut got_jumpstart_event = false; - for _ in 0..75 { - std::thread::sleep(std::time::Duration::from_millis(1000)); - let block_hash = rpc.chain_get_block_hash(None).await.unwrap(); - let events = EventsClient::new(api.clone()).at(block_hash.unwrap()).await.unwrap(); - let jump_start_event = events.find::(); - if let Some(_event) = jump_start_event.flatten().next() { - got_jumpstart_event = true; - break; - }; + assert_eq!(format!("{:?}", jump_start_status), format!("{:?}", JumpStartStatus::Done)); + for response_result in response_results { + assert_eq!(response_result.unwrap().text().await.unwrap(), ""); } - assert!(got_jumpstart_event); } /// Submit a jumpstart extrinsic diff --git a/crates/threshold-signature-server/src/validator/tests.rs b/crates/threshold-signature-server/src/validator/tests.rs index 20190b421..a82e0aa58 100644 --- a/crates/threshold-signature-server/src/validator/tests.rs +++ b/crates/threshold-signature-server/src/validator/tests.rs @@ -221,7 +221,7 @@ async fn test_reshare() { } // Check that rotating the network key wont work again later - run_to_block(&rpc, block_number + 7).await; + run_to_block(&rpc, block_number + 9).await; let response_stale = client.post("http://127.0.0.1:3001/validator/rotate_network_key").send().await.unwrap(); From 367fccb6d4e803a5a5935020c1567da6d57ef2ed Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 1 Oct 2024 18:05:06 +0200 Subject: [PATCH 13/17] Pregenerate keyshares sets for all possible initial signer comittees (#1073) * Pregenerate keyshares for all combinations of non-signers * Dont add keyshare for the non-signer * Tidy how validator names are represented in create-test-keyshares * Tidy create test keyshares fn * Rm comment * Ignore absense of non-signer * Add publish=false to create-test-keyshares crate * Readme * Readme * Update crates/threshold-signature-server/src/helpers/tests.rs Co-authored-by: Hernando Castano * Minor improvement to create test keyshare crate --------- Co-authored-by: Hernando Castano --- Cargo.lock | 1 + README.md | 10 +++ crates/testing-utils/keyshares/README.md | 2 + .../alice/keyshare-held-by-bob.keyshare | Bin 0 -> 3472 bytes .../alice/keyshare-held-by-charlie.keyshare | Bin 0 -> 3472 bytes .../alice/keyshare-held-by-dave.keyshare | Bin 0 -> 3472 bytes .../bob/keyshare-held-by-alice.keyshare | Bin 0 -> 3472 bytes .../bob/keyshare-held-by-charlie.keyshare | Bin 0 -> 3472 bytes .../bob/keyshare-held-by-dave.keyshare | Bin 0 -> 3472 bytes .../charlie/keyshare-held-by-alice.keyshare | Bin 0 -> 3472 bytes .../charlie/keyshare-held-by-bob.keyshare | Bin 0 -> 3472 bytes .../charlie/keyshare-held-by-dave.keyshare | Bin 0 -> 3472 bytes .../production/dave-keyshare-0.keyshare | Bin 3472 -> 0 bytes .../production/dave-keyshare-1.keyshare | Bin 3472 -> 0 bytes .../production/dave-keyshare-2.keyshare | Bin 3472 -> 0 bytes .../dave-keyshare-held-by-alice.keyshare | Bin 3472 -> 0 bytes .../dave-keyshare-held-by-bob.keyshare | Bin 3472 -> 0 bytes .../dave-keyshare-held-by-dave.keyshare | Bin 3472 -> 0 bytes .../dave/keyshare-held-by-alice.keyshare | Bin 0 -> 3472 bytes .../dave/keyshare-held-by-bob.keyshare | Bin 0 -> 3472 bytes .../dave/keyshare-held-by-charlie.keyshare | Bin 0 -> 3472 bytes .../production/eve-keyshare-0.keyshare | Bin 3472 -> 0 bytes .../production/eve-keyshare-1.keyshare | Bin 3472 -> 0 bytes .../production/eve-keyshare-2.keyshare | Bin 3472 -> 0 bytes .../eve-keyshare-held-by-alice.keyshare | Bin 3472 -> 0 bytes .../eve-keyshare-held-by-bob.keyshare | Bin 3472 -> 0 bytes .../eve-keyshare-held-by-dave.keyshare | Bin 3472 -> 0 bytes .../test/alice/keyshare-held-by-bob.keyshare | Bin 0 -> 2192 bytes .../alice/keyshare-held-by-charlie.keyshare | Bin 0 -> 2192 bytes .../test/alice/keyshare-held-by-dave.keyshare | Bin 0 -> 2192 bytes .../test/bob/keyshare-held-by-alice.keyshare | Bin 0 -> 2192 bytes .../bob/keyshare-held-by-charlie.keyshare | Bin 0 -> 2192 bytes .../test/bob/keyshare-held-by-dave.keyshare | Bin 0 -> 2192 bytes .../charlie/keyshare-held-by-alice.keyshare | Bin 0 -> 2192 bytes .../charlie/keyshare-held-by-bob.keyshare | Bin 0 -> 2192 bytes .../charlie/keyshare-held-by-dave.keyshare | Bin 0 -> 2192 bytes .../keyshares/test/dave-keyshare-0.keyshare | Bin 2192 -> 0 bytes .../keyshares/test/dave-keyshare-1.keyshare | Bin 2192 -> 0 bytes .../keyshares/test/dave-keyshare-2.keyshare | Bin 2192 -> 0 bytes .../test/dave-keyshare-held-by-alice.keyshare | Bin 2192 -> 0 bytes .../test/dave-keyshare-held-by-bob.keyshare | Bin 2192 -> 0 bytes .../dave-keyshare-held-by-charlie.keyshare | Bin 2192 -> 0 bytes .../test/dave/keyshare-held-by-alice.keyshare | Bin 0 -> 2192 bytes .../test/dave/keyshare-held-by-bob.keyshare | Bin 0 -> 2192 bytes .../dave/keyshare-held-by-charlie.keyshare | Bin 0 -> 2192 bytes .../keyshares/test/eve-keyshare-0.keyshare | Bin 2192 -> 0 bytes .../keyshares/test/eve-keyshare-1.keyshare | Bin 2192 -> 0 bytes .../keyshares/test/eve-keyshare-2.keyshare | Bin 2192 -> 0 bytes .../test/eve-keyshare-held-by-alice.keyshare | Bin 2192 -> 0 bytes .../test/eve-keyshare-held-by-bob.keyshare | Bin 2192 -> 0 bytes .../eve-keyshare-held-by-charlie.keyshare | Bin 2192 -> 0 bytes .../src/create_test_keyshares.rs | 20 ++--- .../src/helpers/launch.rs | 6 ++ .../src/helpers/tests.rs | 35 ++++---- scripts/create-test-keyshares/Cargo.toml | 2 + scripts/create-test-keyshares/README.md | 17 ++++ scripts/create-test-keyshares/src/main.rs | 84 +++++++++++------- 57 files changed, 112 insertions(+), 65 deletions(-) create mode 100644 crates/testing-utils/keyshares/README.md create mode 100644 crates/testing-utils/keyshares/production/alice/keyshare-held-by-bob.keyshare create mode 100644 crates/testing-utils/keyshares/production/alice/keyshare-held-by-charlie.keyshare create mode 100644 crates/testing-utils/keyshares/production/alice/keyshare-held-by-dave.keyshare create mode 100644 crates/testing-utils/keyshares/production/bob/keyshare-held-by-alice.keyshare create mode 100644 crates/testing-utils/keyshares/production/bob/keyshare-held-by-charlie.keyshare create mode 100644 crates/testing-utils/keyshares/production/bob/keyshare-held-by-dave.keyshare create mode 100644 crates/testing-utils/keyshares/production/charlie/keyshare-held-by-alice.keyshare create mode 100644 crates/testing-utils/keyshares/production/charlie/keyshare-held-by-bob.keyshare create mode 100644 crates/testing-utils/keyshares/production/charlie/keyshare-held-by-dave.keyshare delete mode 100644 crates/testing-utils/keyshares/production/dave-keyshare-0.keyshare delete mode 100644 crates/testing-utils/keyshares/production/dave-keyshare-1.keyshare delete mode 100644 crates/testing-utils/keyshares/production/dave-keyshare-2.keyshare delete mode 100644 crates/testing-utils/keyshares/production/dave-keyshare-held-by-alice.keyshare delete mode 100644 crates/testing-utils/keyshares/production/dave-keyshare-held-by-bob.keyshare delete mode 100644 crates/testing-utils/keyshares/production/dave-keyshare-held-by-dave.keyshare create mode 100644 crates/testing-utils/keyshares/production/dave/keyshare-held-by-alice.keyshare create mode 100644 crates/testing-utils/keyshares/production/dave/keyshare-held-by-bob.keyshare create mode 100644 crates/testing-utils/keyshares/production/dave/keyshare-held-by-charlie.keyshare delete mode 100644 crates/testing-utils/keyshares/production/eve-keyshare-0.keyshare delete mode 100644 crates/testing-utils/keyshares/production/eve-keyshare-1.keyshare delete mode 100644 crates/testing-utils/keyshares/production/eve-keyshare-2.keyshare delete mode 100644 crates/testing-utils/keyshares/production/eve-keyshare-held-by-alice.keyshare delete mode 100644 crates/testing-utils/keyshares/production/eve-keyshare-held-by-bob.keyshare delete mode 100644 crates/testing-utils/keyshares/production/eve-keyshare-held-by-dave.keyshare create mode 100644 crates/testing-utils/keyshares/test/alice/keyshare-held-by-bob.keyshare create mode 100644 crates/testing-utils/keyshares/test/alice/keyshare-held-by-charlie.keyshare create mode 100644 crates/testing-utils/keyshares/test/alice/keyshare-held-by-dave.keyshare create mode 100644 crates/testing-utils/keyshares/test/bob/keyshare-held-by-alice.keyshare create mode 100644 crates/testing-utils/keyshares/test/bob/keyshare-held-by-charlie.keyshare create mode 100644 crates/testing-utils/keyshares/test/bob/keyshare-held-by-dave.keyshare create mode 100644 crates/testing-utils/keyshares/test/charlie/keyshare-held-by-alice.keyshare create mode 100644 crates/testing-utils/keyshares/test/charlie/keyshare-held-by-bob.keyshare create mode 100644 crates/testing-utils/keyshares/test/charlie/keyshare-held-by-dave.keyshare delete mode 100644 crates/testing-utils/keyshares/test/dave-keyshare-0.keyshare delete mode 100644 crates/testing-utils/keyshares/test/dave-keyshare-1.keyshare delete mode 100644 crates/testing-utils/keyshares/test/dave-keyshare-2.keyshare delete mode 100644 crates/testing-utils/keyshares/test/dave-keyshare-held-by-alice.keyshare delete mode 100644 crates/testing-utils/keyshares/test/dave-keyshare-held-by-bob.keyshare delete mode 100644 crates/testing-utils/keyshares/test/dave-keyshare-held-by-charlie.keyshare create mode 100644 crates/testing-utils/keyshares/test/dave/keyshare-held-by-alice.keyshare create mode 100644 crates/testing-utils/keyshares/test/dave/keyshare-held-by-bob.keyshare create mode 100644 crates/testing-utils/keyshares/test/dave/keyshare-held-by-charlie.keyshare delete mode 100644 crates/testing-utils/keyshares/test/eve-keyshare-0.keyshare delete mode 100644 crates/testing-utils/keyshares/test/eve-keyshare-1.keyshare delete mode 100644 crates/testing-utils/keyshares/test/eve-keyshare-2.keyshare delete mode 100644 crates/testing-utils/keyshares/test/eve-keyshare-held-by-alice.keyshare delete mode 100644 crates/testing-utils/keyshares/test/eve-keyshare-held-by-bob.keyshare delete mode 100644 crates/testing-utils/keyshares/test/eve-keyshare-held-by-charlie.keyshare create mode 100644 scripts/create-test-keyshares/README.md diff --git a/Cargo.lock b/Cargo.lock index 807a0ba74..8070e6e3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2519,6 +2519,7 @@ dependencies = [ "entropy-shared", "entropy-testing-utils", "entropy-tss", + "sp-core 31.0.0", "synedrion", "tokio", ] diff --git a/README.md b/README.md index 0d7d3d69d..2e2d584dc 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,16 @@ It is however only intended for use with test networks and has no secure private Everytime a change to the chain's interface happens, metadata needs to be pulled. You'll need to install Subxt using `cargo install subxt-cli`. Then [run a development chain](#getting-started-with-docker) and then invoke [the `./scripts/pull_entropy_metadata.sh` script](./scripts/pull_entropy_metadata.sh). +## Regenerating test keyshares + +To speed up running tests, some tests use pre-generated keyshares rather than running a distributed key generation during the test. If you need to regenerate these keyshares because something has changed in either Synedrion or the identities of the test TS servers, you can run: + +```sh +./scripts/create-test-keyshares.sh` +``` + +from the project root. For an explanation of how the test keyshare sets are structured, see [`create-test-keyshares`](./scripts/create-test-keyshares). + ## Support Need help with something not necessarily related to `entropy-core`? diff --git a/crates/testing-utils/keyshares/README.md b/crates/testing-utils/keyshares/README.md new file mode 100644 index 000000000..84645bb23 --- /dev/null +++ b/crates/testing-utils/keyshares/README.md @@ -0,0 +1,2 @@ +See [`create-test-keyshares`](../../../scripts/create-test-keyshares) for an explanation of how +these are generated and what the different keyshare sets represent. diff --git a/crates/testing-utils/keyshares/production/alice/keyshare-held-by-bob.keyshare b/crates/testing-utils/keyshares/production/alice/keyshare-held-by-bob.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..b0f17866c1449059e2a753deb0f071e8917abf42 GIT binary patch literal 3472 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 G?fyT)o+cy! literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/alice/keyshare-held-by-dave.keyshare b/crates/testing-utils/keyshares/production/alice/keyshare-held-by-dave.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..5ae742022253e5ce3660c661a12110b1c3120564 GIT binary patch literal 3472 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 E5AA~&761SM literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/bob/keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/production/bob/keyshare-held-by-alice.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..9a912171111a5bab2c222dcd6b1828a5cadc2fd3 GIT binary patch literal 3472 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 IJR{4009kxBbpQYW literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/charlie/keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/production/charlie/keyshare-held-by-alice.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..2ee39900df1f68d53e69b00730b9b8342b4e1dfd GIT binary patch literal 3472 zcmbW22Rj=K+lEV`MyXM)QS-5D3(=s8goHF!#Hu|~dlR%q)l4agqE>~Xs8zF-qFO}} zqPC}sQhU#;^?lzT_}-)M{R7V9KJVi?u3JF`rVWJ}JTNf_2O@l}Fi5N!T-V*(#YHdF zRS|4xVEMo^9AOPIg+ffAI%qc(f>wwy&!Mv7uXG?df{%0Q;R=^m|5DZ8Ww%`Dj++F# zxZ460RGMKl6ph;cPHM|fi)Xah9D0D^RP4#I$7fx0G&LGEBzjMIN2 z(*7^;@4WvL5%Blg!ho+V#=Bl)WU5D~sOXljX}uh_Va8PM3XjRz$Aa%eM0cFpvPZ}3j;*Ol!lzzm}F!!vi{}vXeSMJ zlVvP_mvQ>ToC3Cf{`-Gh{@pEW3c9nG1qf~NhOZwfRbJ6%XUQbO_&T<@%ma5yO1r10iXiuYktJIE zy!_`$&^u6phCX?7C_cHp%y2b3<>g9A63{Ab)sCufUx!bKb|6;A2;26m3I?`+ITO%L z=V)eD_*w&T?JamH$H9`r|7vaK7#P76WRn?3(XnX(@Cdv-vu=C$9XxzX2T3z&?gOLW zO~Xt@KAr#Npx!^8si-*2-UK}c)HRGtm6B*?BCP9IIEIcaPOFMf#+*irgOr+GF2RzX zFVW@aHIX0W$xBvRby+9T3(tC<<%O!NGPr(6o36Gex09G< zs?M?P$?0}#TIsol`oE(l-k0ffr!>--@_ch1s0Vff^ev!ek_+D%r)PF@<64-mFzwZF zNU`#fOX*9yigtH27DjEfdsh;#ev4lim+8LtkcE!Fc&WBbDTj>#H~!a{8~jrnYhU2gg>JvZP;d?h#E2bYhEn z!F2B8E$4k|DA%s5NUYzYNd{Z@NN25U?VKh4&(oQql12O|;=@oaJ#Gv2l(ey9^XK#2 zCM}+#H$D50>~qPCe167L$jzvSaSVSZj@wgzUSi2+1D#<5%AY)N{jORr>oWBi*v?}kC=Z`Y_G-K?v`E`;fObbMLD)pbr#=f7()t0Gw{|O`k3F&JUBRc4| zCgwC6eG4?~z4jHv`s6msp6WqsaVtw*Q#IhySIoL@wLqBUYi|dmbV^bEPk*(;M?+Vi z;mCAXxS|faLLp+$F@CNWhblBX8w^LY$DZ%N7(V@s4&6u@U!%Fc--YYEGxW)ZFA3xN z*B422w_S)!%y0tN3j{LR;b;RB=$DN8HCDHghax zoADBsl&hNd07?5b@qPbc{jMK*zb1+HQp&Y*9{9*bw9>&E?rv-cF>bX; zQa>ykvtu8W_x)3aHH;tNUC0?Nk>2O?f`h?S&wK0kp_R(lM?2zv9WD7A1#L44+n9*A zhfvEdJlmp$1V?$5gX?Jg&{Jk^&6sm;ej4Nb@(7S}0(Ya`iGdaS`J7jR+nWn*Df?8G zy162LP|7{F@vzAw&1#{to+$^`&}NV5`@QSWNNX9dAJfGx3$3$ntG8BQao_gC3f(%C zKK*WMA6UWZsX1IHg-nZVT3_X*pWfU3BoiEdxuoU%hFC9N;cR`vyzE>$9jk~8lJ&#F zFU;2*LP%VfORtxz^$qzD80cnT?~-GPuD`2=sV|O{_e1ALmIH3A<4Sq2>Nfs!rF?sR zV&k7m(+auG48K(RZTeR=-DM~7b%HyChN|{)<+de}WGrLSZWv%?>$@}j_^0)?xQIYA z3ANnh<(T@*X4KD5F~sY%iD;&HxsUH!1lwkF8l=4LGIpb~a?D<>uSY?7jxGReBLcKzpLtbwTw3eTW46+_)?$Sy!XB?@eXskTDz!IV!FS zTxv`&?8|R03nKpbb?qK4yo9=7v0<@?h;-kh9Wqd$tGxfmkp|%W*No;Q-v%P&u3th2 zuVM1Rw_8UU>$0c?aK@tnw~cIR{o3k3X|c%A6Kv6yqYxZpGTaQj@x_f??(kQt?K}ntJSA7hMyVZH0-^MN zn@^eSEJ7c1F!5}e_LZ-x1)OFZ0jik7^$QRGRf!PLUQOi^ZT#{0$DfV&E=#=(aelSf zo!%}*(UzB);Q~>rySHs-Dg7VsP2A z>G-{Q38@GN2L!6(+b5QrQi2{sA$^V6MZg)lqgOv4M`CudC6GLH@!{8ZU!sT_nhf&P zdWr^`Gw$>}S|>Z-(JL7GY`_p3m8ICAMwd#y%ydD_e11paqvH6jMDHl*gfsaLLW|k@ zk}kqnEGdEdBXK$2_1Q62Oa2BfFY$>FGzpQ~CLrdrbW@nj-e8s96Cm4FVr%?O`zfOX zv1&~9=``4wvIHm+4PldD#O)Abfs|_h!(3K3-ln3HvQhMFfA@}%!01}!oQOf!nnYg6 zUNrMTzPfy~MJvXxum~8hhjKGY;U&3rIVlWd*!%%3G!7xdW2G^&lEkywQ%S%CsSLsQ z@TXXL)p6Jn;YzoWX|dbBHa>|5o>i|9CC$Su6(_y1D(F}d=HtAs+nJDGm8J6Rqcc0zjYTmd?5-?7IpVJF!sscC$)#!R= Ruh8x@TA@yK;P223{{t;hDJ=j1 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/charlie/keyshare-held-by-bob.keyshare b/crates/testing-utils/keyshares/production/charlie/keyshare-held-by-bob.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..81c53944d1779cb4fe07ad3847e6532b888d40b5 GIT binary patch literal 3472 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 KnuvE8#{U2#nKrfn literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/charlie/keyshare-held-by-dave.keyshare b/crates/testing-utils/keyshares/production/charlie/keyshare-held-by-dave.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..4bf9c77318385e076c264f2d5687065eb3dcf16d GIT binary patch literal 3472 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 ME%rbk*@ENvA92AgQvd(} literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-0.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-0.keyshare deleted file mode 100644 index 9158d42d7b42bebb252e88a8631eb03e5c4303d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3472 zcmbW3i8~XHAIIHyX-dhhCFDM~8WM(WZZ>n@wj4Rem&3U^LgG1ARR3zRR4|{8jOScT3Z-kQ7~N(Z#Or+P>dqj zSl{Z7S2)~8*>ngK8t)jo=KTzKj`64Tl>8nO!H-PK%P9XKsmH*qjxdz>9NNQmE)t zMg@=#$S4GC>0%jTja5X#A;uOMG#c)Wg&_5jaD9k@hijmPvJOtyOfk>{jInSLrThQG z@DK6tQvMr}UICkEs^(M36z)>MjQmAVyE!b#vc7y+PL?0BZIPP?fu+K#+r=UH$OAmwH;K+_ys&q(x0R3M$7N4@m* zbfwj!7FTU+ax#8b#CKfb^hfbNbxrjg3MH0D-NjElRR6$b^OV1`_d~{tqkmRB>fG69 zmQyf6AA_bvCtRZR9+hvv4Z>AfU2Wda@~f)rrt{g>GtZ7Zp;PrinoaTOG_<_-^|s%aLM?7_ zdjLuAX8G1|mnx#c0uvSd>#Gyfm~8Ztes+3u;K7R{f>h}BiUcotQ3)-qBV08`+9-HSDo!Hkk_hJYQVSyLi>73j+|_|6!LH)mZ!$ zfSKi^H%=hasEPto)i&9*9X5dt&0U`bc#2EroRK_JwbXYcg0CBNg4#5X2J|y44?osQ zTo07nU-1sr`2eBA`ti}zh*kZsc=r;tDIPwx1BW+)AE(1(HAF+h5&M~KYyK$^ zW6Xg)mLm9ZRE@#GR$i@rVD|@uH`5UwkQLe@1N`0%^AO|>s7Zd|BIH9aJC@$kAngnw zJ^}QhZx{ z{Cm0=Wh?d}U+>y$E1Kt$lX`0WgdwcdRU&jVM=G-C(BHcyS|jfQ zb!cLW`8u6^A;2X=l`m_q$s^>PV4R$1Jj=m6PQZJPuk;dlx5IKPZ|H&~mLJWM6t0%D=HgWEa?WoudpwFo-F-fWJ z)pS2-RtDmXv}IH3nX380eK#2tMAinhBl^Cx{{FBnG&QG1SaTDP+KFv7h&DzC2$Okm zM*)1^0I8w7Q0vw;5n#uK(DMA>n4HT_!MXHwA9WOY_b+TQ-U>ucOn(EEYbu(Yq<2|Q z&<7|wdD4gzySoL69$f7={P=C@3yn5FuSjvA7W{VtTWauGY){TCnZ@?O?)a}q_b3g+ z3DjpnZ+j~^$gS6VH^hqKMY5wlscwjFJ#ZO2naRH-A3o$hqp~OG(9P5#M}^-Q_!VGU zeXY6mci=9(vTLx|(RZP4`4khjI*SoxOlK+o1{&VDO;cfhH_D4xu%BtL?J*IpejXf@ zFmml`Ed=7nhJM-z6{PwXy(v9iH}WvHPCXaX1d}O}x;7Wrc5H|6BUZYqEIvI}uAbw8kfbRU==&}M~? zXtxnCX}V%)Ch+H(X%1;|~elD0M(m~yWM&a!mP6hM2d z_b&fw;+D=sDGnoD*1nzNqj`!}<-AerReai^h)JD;@sN>bA-T1H45}4Quh+3J7Z+X& zoIEEZEOA*u?sG1I@(69rLMQ(t5nRSSnN;*}btjL@0xju(AOF%tN_er|cE4(HpG8al zlFXO@r_9tQZGBU!#B0jyY(PJ$Eg@6bHYA5sa`%^EzSH{AeTz& zMA7|O?tH%@VErvD+->_gKs z;xQV#2s7=N@!si2G^LHYvY1!GvRpIwqGUlC-ha%0m@o`q01K`=HkU!}^_{=rg6?e9 zCitq*?f|Z@OqrKB<}IC9&%w#`|8vdQT+0{Jj|kc3=bjqm(O<0j?WG?ze$lk8);{|@ zKlRG{vUN={qdGM`o#7WVi@~s%(r=q8`g6QyxHvIeLw-)Zv{$MJDOry0%n`LKf_dE> zcGUR|s|YIwx@`M2#}it)_xB>c=7+aiK0V`LPViCAjgqzb28(KY`&BbU#B#>b+#@ZB zo86ziys5Kd5wL8iP2{UtH^9dn1BP_;vCMh8>ajCy;U_F1{fYUc-LVzmYLmbeOLFvY zxv7bS*x`AJu#vhbOP{Jp4=ow=n8w?J;f2w@TXSAI4geBPSqV03@*lcHe4HD6tT@G! z$>B0OWrf5aT_{bk2rffKs`9ImBZV6?iIrOB^rkfn%(^{%PPusk+N==w@{gv?)={wH z5oLd!d*8a8$?OO~$1$zLpXX?loVix-S*`*`+9x|+?N$v8Ia}a2i%QyBN;!!yD;}-i z$gU2F-xSVW4|$9tG9@w9v92|b{*b`92nB2q_ib+}1tmwkr@Tzd0!UcY{JDb?0FMCe zwu!3oVXH3`)hcY0=&-^8pKTiL>coTd21G_3$MpGTH0}oMYU9+%+O1U{stE~@%JkeX;n9@5LLMA|cg^(}NiBUXb;3NdX~#FF<6G|4!s92svX}ODIBF&h z4qJ4Eo~iG{B_|p!!fzfnlBE^2R-N~(7TCU2-L-tmH1ucWtG&Y5EpeqAi*K#3BwZ8+ zuq75(7m_4W@x5oIlhj&P%mo%3N)DHyB7O~*8hqWjeibtWQP1b{@x}rBvQL=;7QW12 z^5QhbUT%vAFR8^`YdVr4PL76laC~^&C1?Wq}Sg{bkjFa6aha5 zpGcR8yNedfac+-g5c%Ws$HNQ&%Ld&ND}tByMws@~*%(DNIgEf5y*MDD@7ToaeA|~I zG23eeXa~!v*1+goZXfM5U+nwIkdi^z;3}qF`sy4~1nQ26{7Rf9>?^j{Z1(Xkg^s8E z5FZPoDtX%gkbAB3t9+w8#sL$W(7xf+u!~c{;_uhOl`&Hd7jV~9U+FDAkOi*{tqK>_ O*a|3J`ZhLMkoiCNy(upM diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-1.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-1.keyshare deleted file mode 100644 index 695bf5969da2d2815d1fe4855bf31967517acaec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3472 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 Rm|I~hq;h3xa3nkB{{RUxCtv^o diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-2.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-2.keyshare deleted file mode 100644 index 702cc0def9590796c033e5a14ef7de6ab3f610e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3472 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 JtuW*2e*nqs6RQ9K diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-held-by-bob.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-held-by-bob.keyshare deleted file mode 100644 index 2176adf506710028b355e9d88ecf3b25b80f0559..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3472 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 diff --git a/crates/testing-utils/keyshares/production/dave-keyshare-held-by-dave.keyshare b/crates/testing-utils/keyshares/production/dave-keyshare-held-by-dave.keyshare deleted file mode 100644 index 24c31777057e8dec19c7e92a1475635e1fdcc1ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3472 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 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/dave/keyshare-held-by-charlie.keyshare b/crates/testing-utils/keyshares/production/dave/keyshare-held-by-charlie.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..e56bd6bdd3de4dfaf85daa304e592d30977012b5 GIT binary patch literal 3472 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 J#;w?!{{a~}AYuRj literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/production/eve-keyshare-0.keyshare b/crates/testing-utils/keyshares/production/eve-keyshare-0.keyshare deleted file mode 100644 index a79f3962a7fcdc85ffd2e7949ffab0fa74ad5717..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3472 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 Qq1h&f=I)*hqp!e!01YoEK>z>% diff --git a/crates/testing-utils/keyshares/production/eve-keyshare-1.keyshare b/crates/testing-utils/keyshares/production/eve-keyshare-1.keyshare deleted file mode 100644 index 6f79608fcf89ed702983df0eb3b350f94a341ff7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3472 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 L-#?I|L-YOz;L;rg diff --git a/crates/testing-utils/keyshares/production/eve-keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/production/eve-keyshare-held-by-alice.keyshare deleted file mode 100644 index c9ff36c6e0411be8637727acca773c87d43396f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3472 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 HTD<-PR~0r5 diff --git a/crates/testing-utils/keyshares/production/eve-keyshare-held-by-dave.keyshare b/crates/testing-utils/keyshares/production/eve-keyshare-held-by-dave.keyshare deleted file mode 100644 index 8f8d8a98e913cead294b0d666b89c55107fbfda3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3472 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 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/alice/keyshare-held-by-dave.keyshare b/crates/testing-utils/keyshares/test/alice/keyshare-held-by-dave.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..41689821365f495e29bff929383daa86773df813 GIT binary patch literal 2192 zcmbW1dpr|r7{}S7&KjE?*HkVY*Qnt$8gktjvzTqJoyv7sGA!CBv$G=PmZRLN>EyUX zjK&$$g^;C=XdID{lw6ky$)R)poj>%^```DE_jx|w-}Al?9O3BdheA=zDQ+GZUn~Xb zh^I%nI>bgqpCuvf2|msiNGDem4(l2iMmGs?^9luMuB+*NaY?cYtii$1B5HnT+~+4# zFc&i7rC;3fiOPpvK=^iRYD#T=q~Qn@0vB)Y9q1kJ8)`zpAditkyu2`xp-6%&0pp6q zh6m9|W~f*+-h>uz9zqKIUPS;L;pFKQ?M4rdLy#?y_z<5c8af;ii#ZqRn*%e%s<&08A30t-h^m>J%BI z&Y#9f8RDz$>Kxew&%?Ql`?C06A;&tC{v?rvir5#$B)1t>7?qnmU@*L z7<%2So9YJCvpI~u{92q!5SgGX`95q%p{haV!h)+VH}x|+5(gQOwU&7EmH|-C#K?3e zRDTVbjv_?`w8eU29u!wFw?e)GHPw7_vSb<8k4{jU;|U&X8?J zn*0yU5*S^*#x}G`BSiSgF$*~U)@Hd;(yb(M_3%6Jd#GKv)=%IdX8{NE+0bi^$EZ3T^w4{ZX+vPv^$!;+@;bx7+W9=!xCZR4n}>TF%g{ZMS|w|J)SeN zUd8(<3JzYfS@8Im!IGPlIe}}B4lQpmu(kAId1OgTYD&_ciS(F%P^p#=df(ngk_7$? zUw1m?mUdf?k$#D9@8tYZ>VZ}7Pg#-UE7bZ{)YG9tnT?eRKiB)crUy0RJ6I4wC2{RE zZZ$$%#)-?nTzB3yp@|!A1u`b43qw#}{ylutE)%`uxs@1{QqFuvfd!E*`4+lpR;$Y9xYHy@xDe zcAONfrRu26?7Bd`Sb9`+QIJX8Mf+rDrXYph(*FnklEw=5+uC9oPW|0Z{V3k^n#=hl zEdS<>042O-d3YQv{!R1z8J*!JVSh;60g!q1U=StFD6D(YncNcEbx4dM2VLN4Jra*T z-+M!4E|S<)A{rrrhKt$`FOAEuPo+&HDs}R)Hyz>dXD8AD_n?jNR;p(|D$mM$)j$l4Kkm8>TZuJC{_iihUMJ;29RDtTbzqKp~a zVDM_a^p4%$J?QRM&H#gKCR*N^U)Tsgom}!#_jVRSZAQ`Wg^^{_YqfK<)XXi?Tv9mJ(KMJmxV%; zdj=TRZb0Qf%p>sgGCGEkkrCDIV0C6U^a%QvRr;iw0^ICKev2R=*du$MF&S$jQD6|GoM|FVWu9|a{8pVi&kk&D|DQa<5TW4o0Md4RDIRml;I}qS7zkS$4?;n#kICd zFJ(Nc_IQ~;uW4$0V=~`S1U$bNgf0I3)a2hG$n@%=KvE!A+|2F-T#gtmhL7-!D5}l2 qUzm0Z+~l!^v?FP`gUTHn{x*6YhQsVJ=q+Qfd#AzxBJWKdCGkHKJ{;o! literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/bob/keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/test/bob/keyshare-held-by-alice.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..c4741402ac623e61ceea3d8dce5dd191737d2ac2 GIT binary patch literal 2192 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 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/bob/keyshare-held-by-dave.keyshare b/crates/testing-utils/keyshares/test/bob/keyshare-held-by-dave.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..fbd5288bd15c5c056037ad5e41a2544a6c972264 GIT binary patch literal 2192 zcmbVMYdq5n7-m{-xsH_7FD%b6G-@Hsyp-#6igAaB5P-FPGd- zl-pUEG0L@Ea>*r^qZEadozME9pYwiuKD^KSd*0`HUp*rL>uPOHGp6AjF%&zRDS&4N zW3A|cp_fRemP9fdVQPc5wztE2`7`xBan4kbDpMEIzJDqLdw=SXDM6l_*C`~$RnEw* zj?Ng+m$A;mnZ|s02`_UpW zu5bciiU+KS{`Qz(F@p4rYzQ`?IHpgyksrbo?@JC2Lj@SoF^nKG!Jg>^=+h`pA$};= z5H#KrLo^_we#I!VbJhCXZ8$JO`JbC0^&T@;D$q3B3{^jRBiABVjGCI~kX2-&zph5BWm>GPyEGAEVj+O6^ zUDF-B8woVNOY`Bxu`dHIJNBDfA-Z{r2SqqW$(Dd|iwtMSr zRzj0uam971%vt8bPN}F`JM)rlV-pP%Qi0KnzOVc!DOu4zId7fRv z|MBv|NgbFZ=D6U63gA%T47YF>ff#u0g4fkI1C^;W+I5dd|Jh}ZxSk-cWB&Op^zfbL zn^QPBUJxJ}9pt+_9|c^+d`=dJ?|W0-yy&1g&$C4&v(%7BACwd7bRAm?J=q)l6mz@H z0kz1q=E?OcTUpm4?uZCe{)#YDA^g#f3{2YNmmUIm@F z`fiF%p~5I@?QwE0&<_(dCn?R)^U;>a`@Mby3U8gb6*Xk7rtBe$zTQ|oyLQ_oCQs6! zU)38d`!&p~0AEg+jR!m)hDyL4-ygMGbm8rR%3q9|UmBAZQ=VsyIY`ubT(hd0OdVW6 z!$r*SO|OErHDJ$W-B{*{4Ll2Dw|pIB#lFA4Z##eIw2H8Oj_KRFUBh zW4m?0>g$_8BsFVh*gYX6tEJ-hxNTVigU9%~hxT-B88duZiUb|$@WK}H?jBaUe}wKZ zYReku;pRYgW+k;NU8^zD1$MpQUVmwqk-xfG*Qxu4!APZZ?D&&{buL=IuZbt-)>lc7 zDAcL9AsM@GYw7FL18;W^73$sDb@RoOH#e5hoDmc0b6N{e`RJac;No)!kl#8!36m2{ z=={0dKf0tBy+1xEjj2g2yQJ1sfNd&;{^;p}U$QvBzr}?LKE@`ss^! z_#d7)!8Y1OYgOMD*v>^t+1_yA-6JFR65j11SzawAsgqyzqml6HLELI!sBNn6sRNa!VZI%!Eld{v|9Et`;tjLvrh>srIm`Z?ci`3 na6?i8EUEKYJo1#x#q#Lcs_^KckZfdfF6r{CgPaM$wvqY|y!08- literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/charlie/keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/test/charlie/keyshare-held-by-alice.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..d7d2ebd1f8853fda06a9c3f9473f9ce4acc79936 GIT binary patch literal 2192 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 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/charlie/keyshare-held-by-dave.keyshare b/crates/testing-utils/keyshares/test/charlie/keyshare-held-by-dave.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..04df936feb244e4812cc94a5cc7343e445a3d165 GIT binary patch literal 2192 zcmbW1Yd8}M7{@c0qTy*njA~R8$=1+_m~A$bOdA`OI@4H%tJ)HyCc&A?GoZo zunRmB5aeosB2jVsE$j&xCr1K}5d#0?kefFE+U&ql0{v6tD-ZI#>OsB8(z&vCSZk@O z;Tr^@jG2LbkcF+)6S{8ol7X3F%$(Tf6dHx??hPm5Ee^ZV-Q4hg-WDVR2~V(aJnhAD zMPLH4E^yXqbGj?-SB`-H9Z_gB!N(yJ6Gh#Gf=ubEp{ z7V)|y>^88+l9mqoQUbe}CA)rspKq5vL*AJ9{cGZ$gf)Zf$_houk>^4ps^Ohotxqzy zO+A>$?FvXrmpDfs7&18yS@XQdgZfZ))sJ$;v`FRMT#RM%i#q?nB7#Q&W%gi{+59H%4<`w-cywQ@f$@7w$hSflS*{*2L`;rxTjaBit@dEU z>ED?p6`{H?Xs@2*V)qpGg1!^gLJdz7U;dk1M5`7WQV^5fiWLKnjZR%3e@2d&msyFqQl+aeJGZ7k-w(<#l5nJDZRfp+ z0};3>-K>_BpbbTzO$tX!4;Kh>(-1>QF7=p|LbG=E%yBjM@Rv1)tC zez6Wio#$ON9`yq|wciq8CzHgbJ1HvdFsQv$cO8VCy%_KG zUL;f!#doWi!uvyymuKqt;BeY~jM9FDT<=)hME{TR+Q1(h$a+%JGM3s2lAB@E0l zbRHxwQ%2{I4g#L$=X#Wuac8^EOjz9$v=UTAKe#I#{yMA(rxD#r;Ll2yq7n;aVi%&j zaGnZnqpKqI&QR%Zfyk+1oh9r%qPs~RKn)Ce&MnrEU2j50bI<~4J4@e?>d z0M}zTzQyQPf@;4vBo2+L=YA45cU9jI7(69j)2K-xx1`^-8*}JzTy9onm_>0rYF5qv zjbCOGwh+|o&|rBkHuapf+-ttdpK`EEA9)jy%@w(vqz7?@%fhE_+hc+s4pU;)9Lh)xQwZ1JHw`dEK5pwvRI@ zaQ28nb|Y4+H&Io7v{6CMfv+rKJ7h_{ee+X_g&jGTR1=ocDLrdUrd0ihyOLD{NPOj} z-`RtIg0%-)v-z)1ioX@C6R)Rdd0=%SiZ`vA@9US`em^wPfWsm%_QuP|Fsn$7l_RDE zG6^2Aix2VQ2JGo{eh&mJwA+qvv2pPFkzYhG7|Sy%fLZ%1iU(%Ty4_ZT7TdE!TO=Xj f#3LN|)3l-dCyiOoR%I!Z5z3IP*&jdsg_ZI@l93i` literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/dave-keyshare-0.keyshare b/crates/testing-utils/keyshares/test/dave-keyshare-0.keyshare deleted file mode 100644 index 852a008e5253356815c648f98144981a2ec92a82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 zcmbVMYd8~n93B&j6dm_2B&SGa*jRE7W~^b@%`GOox!-TgTCqwBMaLy_X(4tPqSk3B zmpI5RxwVRkqr@JP%RJT2`MN&naem+455M>Qz5n-p{>ETC8yE~pb;CoV5#gRVM+(*f z9vDg@*(Z=e5ERmb8hj4nWr~JD-C(wu0B3}>&g;hVxgb|1MwWtn+j)3s6PHhh&=u(^ zEz7S4T|8J&pfT7E>>Lkq_jix?q<}C8C<;f$;}M}0C$TwuY((z3U-NAq^b&Sf6mCuQwsjX=4Sfg}+?( z7=E8l0r8|%xn&mp*L)djlKoh2%z$LJ@65PV*`uHA?lU@J@nv$&Rq1%-ejM?)ufvTw z@isOsqV0*YdQt}rip*K9>XQ39{aSX_yPD8u=qT9D=f2*HTJ0$2;o=Kt`vE@t(DqSi|e7M2&ol_yap--7T#CqOC z0dRl$h_G;Otp~K~Z!6d8bmd4?st?Wl2F2XR7OD8stKV3vdm!`qiJ+QGm=$_Vt7FRfy4TrTl_eN!hu(v(vmhM(Gxptk+pu`?K4;KtGEB|sdNqf z;0@!(J!o}+>-aRxk8!&;;HwLbFH$^8>r&fV5zS0wU1^JyI$@liul!|peRt3-6Dvpv zV#;;+%kaA@h(}L)vupXw(8EpP-sq#R(ET%#fhBLjek9R zvj6F7`#28#y?rCUc-7@%@T8i8(Rei_;FHu3k`i#sE!CC2k)V`?*T<|_DwfBA$E$mYX)vUldo{wh_~^46pw z64zuO$X`5WJ>fOXSQ)#Xl+;}+(h=PrsW)@D8F>eLqIW2CIs1`GRxzzR)wNCkdx6^?7p?TVx8-KeRiPo-(ykM8_>qt8ipnpiA}GP4! z_R+Uy{2x(xOA=4`BY0y@(c~ooX8sv^GC5ZjQ9dlokNG-xabJ6$sbfh>x@Ug!z;O#+ zt*;SBb+MyYL=Z5w9Qh=%wScYOgAr=P9c&#kITzLeSeM}rQJ=GfvAG4fd%1&7)6ltj zfL~cIvqSwSk#6x5*Od;dF&2D#p<=2ihl}5{@t{F1?4W7bn&r0e1F<|`FO;nSV7(Ci zJ98cF-fK|<%a1i#02TWeCcKY}(_pov6(nEK;sosaoY=-uE#5xkfgimb0cDEq2^tEo z8RpH3S_`ORnbXs1`*Mb9$pF1a3ENLmtWa1TO3D#LGb1Gc{SZ`zZs!-m9$T zFquKs?$IQxiawqpuxC<-MVR&KwCbZ7drs@IRmSZc%I-O>9NJWW$y0lmvlZY);6N_b7e%IeI$huLuaefE&Y{y<+P4s}u%_lo4<6Q)+u)J%_0N~YN q{u)zDp-!8W)VMm@39v+>iqD8tO0Q>g1)jL}y!7<0>>pbsf&T^9*d}-Y diff --git a/crates/testing-utils/keyshares/test/dave-keyshare-1.keyshare b/crates/testing-utils/keyshares/test/dave-keyshare-1.keyshare deleted file mode 100644 index c8d74bab5957fd8cad7cf3391dd8937a3fb3caae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 zcmbW1dpHwn9LL9$k`$F(>O?pd!sgae&%qjN*_K_56j+*PIk_}`a_TN{`dXk{eGYC`}zG|Gs_c}$S^B{Cn3y@4#L7A zC_K%@1@1?OU=dh20&&B zc{tG=1BEz4?Xg}+_^%x0%q$%+4na;FYN#c{8sbcI4Pe8VmMnO&?aw6);Sn^XX_epY z|HE?l)nQ;HV+_(pW;Jcl{!u=nt}pIT9gm7IE>HyX^3nO3?v*~}ts}ky;dDYfrCjht z4E!y(SCT&UtsS)JX|LGeboF3xj628rHr?9Y9-;h(*kva7vOA&K)Vuf!b|E4;2Q1+7 z{qdXZ!6o9A3V8&XEdY9UA29e*Pv#p+y5F|SudcaTRh_^+ur=tsclN5w;=LE``KSFR z&p<0f%NiVEI_?!S{grLYu*J{Sudcb~l*TkRz-zgP(wus^-K2qtG}W&YOWVCCxHxgR zH&?O6Q$f_0M=?5jrl3SL4>?d1a0X-a7SlDpI`Ah2*+V&`LjKFeSa^E=7M@@vq4`n6 z^o1(b4|J*Z2CBT3V+j1(G339PYYPmRmT+2i?b+b_o5(5*j7VHRI23$T&7W+QH+2 zPrB~!8sRTRv(?u`>TF2(E!JJLh^lGNm>HZKA?C%(BJTp&(yz{EJ~SpUGqaL{WfG)b zp1!S`dFipX4F)Sb=N)LRxYGBz7RW+B-(>mILsKrjpPH0a-;4y(eWWH2IZHO3K|%*s z(zxeSx?pbA6aFmTS<^KIQGoG}!m8n^!ob{~jUx6xQk z%-=QJ(jg^@xmu@0RGF=~V0SxKq7k~kK?pwY-vU@ts1!1qvn3%ZJp99y*G^-QsTlzI zQ3|(Z_b-sH^Ap#V_b)aR|9GWluB?a;+p%0$q3*xm-2a=+hJbw`0uLg}UJS7P%=&}7 zgdubsDTbznfIovWJk!HRLqj#P>u>U+FKO|;wtczK$lsN*dEC{d@6SL8SLQ&{*fJPt zU8}718I_@Ma!h^i-5yRfK<{bz=3{il%CW;vx)r3MBCC9;U1Sh=O{76ippBxNB_p+U zv}Ye09Xuo*7ksrdZ{#Wvn?BK@+Zj1`N!Y@=`_$R+%IvJ6H%!iR^^FCDV}}5Hu4m8t zE4<$IvM=g*UZ=ni*gmY2O`0IK9`EFsxsB-+s12NOeDu(1L4VEsIXCTXNOdTRA9)QT zOXR3pDgu{d3gac|tvFny&5D82>+IX<%NLax=UVm%ido%i@l{*t18t<^{;4@R%) diff --git a/crates/testing-utils/keyshares/test/dave-keyshare-2.keyshare b/crates/testing-utils/keyshares/test/dave-keyshare-2.keyshare deleted file mode 100644 index 35b76af5f50760626b393c491ac67df3d8bae616..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 zcmbW2dpHwn9LL9$5{imkI#D?lU2I~Fdcuq~Htd2Clg;LSoy(#XJCUTKTyl?b*kOoT zwUGOfT<4OenCy^PNrWeM&cFIYkMsWb{p0<9pU?aK{hn9f&=O-AY(po98&V-qdrzl8 z8r<736cOp~ghA19Fpw_+7es|S2U*#hA+TU9Tv{u(e?e2E|8&Hdpt&9XgCb+QMq^K< zq!wke(pRLOf}?=?h8BjX2qQ-i#|Q!ighfEncuxlhgg*s}MPd<1sI@nVhBvSXh1-K@ z-bS8y4=upPNBTcUGZ+j>wRbQIMFbM?))br-+}oc_wv6-y8KIF*RNu=8X9EljY7aBV zdZ7@%a+K2FEcdS*ft$zH1`;rHoDUE4v*vBh6cdD!S~ROlDY=fFLWSMiB{x_dwrOr{ zV3t?Xfpo8Wc3Dq$xfZsPqz=#xBp!3i0WFd$c$ZMin+DegR-%oRnMPr{Fhw;TUXrv#51}1Xa@9r(H*G1az%%os-_NT1_UMM)m_nGnVLew6YR>E}= z{+}+#UY`Ims1wk3_t54o8mragDu;!gN}`zP<7`=QR;g`izAM+ax^3K#$N!YvL8|6G z76N}O9u((HfA0V-dYH>L+Qc0VNpPh@?oc4E=1BQI=WczeS3Susr+g~@z%E3mvcNnh zCjh_A99$_}tC2>!(|ACSo+CP68{9d%;-3CC>GhcF)pHA6uBlGfgNtzvix2+pD7EvS za)EKfA2nLRwOngv-f-Jj;ES^_UdKDJsuG$S5p_&t6{|r?l{g%osq}4fX_wC=6DN%H zVam38$Ozg?NP5OD>`K8r^hj->3r4RW(=A#b_>+Qal8!05|K)I;Z#RD%@2DsC^e0Cg z<}1F))h0K%hnbyTR<*rK;%wU^n8Dxvb2yy+^k?Z8g4-RBsYm$YDF(^O6VrO8X=;f z$KBa`$2m)}G?fi2wbyn0Ezwo2oUCR}oq0Pq?p%^6VWa_Q%iru>-Zv$C=Rdp`A`znw zl^ixzHmEw=zC~v(%YL`5dQ#Q9;?t-yf4@{|yU}Tf!H>=IN`2!&6yN2Oh4dwpu3)}p z=sl6g6AEu`-4p&SMj#Y5UJO9=5C8etbXidGz*Yh6$Mm)R%^3#P`SD4F%-EijXLyxv z$2ohyw015Ng-ms80a;=yWUF>y#rwh!HuAxj16lz~GF(2jr9d2(o`o+=@3onLPR{_` zi_)2`s=ugolb@HibU=l^aP_safxIj}V)x3U8kK;91_9qqwgessU zJ)gdBvUC%7M)_&v-z=7KZvIGt?V_^Mh}g3FZ1R^#Zo$LRK5zOYv&R6MHwxwh zWP10$8j3kr(#6vSc8qBi5GS46&UMlC2@{9d%EJ~`MTIsChd0chBWUbIsld=2Mm$uK zLRT`B1+FBN-4*Aw;cyI-H66L$f;%}YSLCRdS~YnUp*_lXpDR#?+ll7_GH%WTfH!;v p-UDV7lCb?~M8D{PsA&fZW64EC`?zg!t z;_$TTy; zIddEx4gHNx>LU*4sm-p-m% zH2YsU0{(T}8uzapfm_Fh0%LhnMbOmmu`ymmC=1798pvjOT~l)X{3e4lD{1#0v}JB6 zz@pnCchqNUKLo^|WAl&TB)VcM6Wiv~Wvbsi$a9A|Z5bR2P+M;BO6rRq>f|wFx{;N5 zaO7%L^zsnqAzLvov2-$f%a*`_JixSJ&9fcju+aLSb20%}Q`%(&TynIw(ddx>wrnQO zt!rYp*f5=2bIekysS6;#aXx-0H6PAs)>^T%%`2Lb2yVBnhJhM8{7cTOW~jxMMUd1q zFUXxP5wU54FLULY?6GyJjrSGC?s|Il5S0$+upJZQUyGqcDk=G`wqxmJA}1ud^mYFK z>GGMxoLMq~d0ij>-M;WL!I&4HpEu3lB3TWf!*KKxZ6 z#5{b#q5szNh!35>pfthPiH}V^AA1QsoTDAG#vR9Lf zI}B6>J5@<8HDZhau8B>eo37UnOT8k!*S2=O-U+g&G%I{M-p&kNuW2H@=Ptz@x}|IT zb#LU<(@BZl#h2A=SYw`?b7w=wjioc&`)+KSzx7=L2CrN|@K0uREFM~LVlL?_iJmh0 zewLVsN~w`6?e{gj=N>|-}s_lpeyrb-Nc_(HBNR%5vgsi`J zh)2L%2HpP#Y%Fo3GAM{U!BB3>^^hKzu&Lk$){93pnzi-&c3-*U8QCkcTkYnhGoB>G zOTXm|rX}&SR6=7H=WCCFaoidG76)k(A+UPo82#CS(LEuaOXKqsG5&TG=BvL2Eb5xKV)d_ABI8a0Rw? znXFl$3u+4LcV(~~5a3QnW_#@Bl^XGM7C*`OtigwMR?vku@lV1fvPukwQD1&KuMm)s zY`dCYRl2oL916HAb3#_inNeW?=CtOkUmDQ4nIqFIDd&r8Q|nqNiGan5Y)qRcj$S%= zpd9pq%DFWf+j?bZ*pu#ql$X_=kJpd;tNZFB70{+l=Lj$S1Ne1w%M5}$7Q=xE!Nt&) zeTkSf!J-P%9;-EkuGt0YCeFaK!TM`W7LF8vyu=qPDffNkO`p_msZ1kusAK=*aB#y} zana}L?RA&77eK`#8D4RZLRh=P9U9Qg_!NMR-VIR4HETkYJU`VKL?0+6=l^&LmLGlB zKsthzb5y2)`O7BXNciciu4}>_f3%{v-vboF;XcqjsZI0CkKO$Apz^kZWB@(>x~XE2 zW?{=*uL*rzI8088sJMq{i=9(NR7AVrNXc-SWa?~jc${2%oX&P*1u diff --git a/crates/testing-utils/keyshares/test/dave-keyshare-held-by-bob.keyshare b/crates/testing-utils/keyshares/test/dave-keyshare-held-by-bob.keyshare deleted file mode 100644 index f1e36e8c1ff16f3104651d28fc99651dc5c511ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 zcmbVMYd8~n9M(o{(kh`kN!Cp+r^hmvm2GxoW>Yi6*xYR{yO_B|DKaCXMJ3%6x!;#^ zlteDYTq~6nx=2MXnIq9TU!4znoZq+i!|#26@Be+Dzp*LaloDa)?Cl)EV8ducggxEQ z$%)8gBWNTVk%X`d@Cl`x;6(%~EHuE(kM0f7HPn)KZW6x;K5)-9uY`34`yaha^VC;5nW9j za0n_6OY^4?f5!-1zHKNlMWkK;&G?a$9AXFM5JYUO_KlDedO;swUFD6ddc6fL+cy;8 z-07S%6gH{_0ZAtOC0ht9JCZBXS|_h)R=v7&i*M|=Y~xUX(M(-P`qQNTb`d+d6H!3~ zC(KnQ&Gh5$`ftCLR{S+<*;jHp^tqdY3qWGMbs2@HI-c9{xj)6nEE0>MRoC!Me^lb` z_VylB?z@z$#6y_G1<|3}i~BLG>^=apy%dcg{Ho+iXnG5RojI85lh!eMhN-i2aLRex zImS)4Dh@Uz7sejKFhE-t@9VC|3_nSgUT9%v!$O?B6-f6Js6vZqC!4P4YIEwV3Mc>nxwjYte;x&K z5>NT`UU(A!t{oViS^8zxiZT>r^)m4;YH}Z)4Ps4HXZ`i1(4IlI{w_< zHdE+YbfOx)Otm)WE>h>G!FmH%^Y?GkbJ|>&)Nj9IbsdqZ0Uhf@2J#j6jV9M+&7CWh zV+~7J8670H_~pgg{; zPZ(|ax^hjSrxA-Y9L(FlFXof2#mSv! z2Xne83eTkcd$&bm$@@FN1mQPKlaB_O6je35gYkId(At<_#ivR8tvV>TCm%g2t$STP zdxQF}+A4%g>Z1k^AYq4}@M~11H>3emv{f}i?tQ)Dif)||dYj|b(|NeihGD2tDB!y0E^YMyW;qtjYtDtazqCA?t=Xum6HaI~>X<5uH%_TxIW&%Jb>FnH z4Ae#AT^LGfKC(LQQRgP=v#R!o3p)?P!Z8S4v_r#wQrF=~N$tc8lf=j4cn}%55ZbgM z4VPIuZGiB`oA;xu)gYaA-{4tb%zT5hFBPzD-MSC zd>m7*byv=VDkU&OQt!oZ)Wkk@Xtwk`fMsXyu!Ld^kJ|dP{vt{jwcrKisLf=%X6Rke+nd9&MK2 zG|^+v_#_*kq{o-vG;K|wonU$$cTseKR3X0Lr=vN_WA!B#f>CT^=2ngh&`q=bj7z&H l$x8jxz8?kiso4^}J;s8|+XEp5^?^j=52d1`i#z-u^bh8m5(EGM diff --git a/crates/testing-utils/keyshares/test/dave-keyshare-held-by-charlie.keyshare b/crates/testing-utils/keyshares/test/dave-keyshare-held-by-charlie.keyshare deleted file mode 100644 index b9cdbc7a2b6cf6a95c33dd2ea1a4eee2c5d6d8a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 zcmbVMYdq5n7_N<&G!dy^TBanIIxa(t88)oHOJ;^K<+crDGjrEHMjUdf(65M0ZgX81 zO>(DPLZU(lMdhAJMdy5VKIrGX-<}We^ZcIodEZx47XvtBv2;DUl`W2BNk?Mv;Y`4k z?aK-#B25TR7WznY0BdatczB0vxm!6I1YF zr|QmH`t*Y}H_NHGW#ihasf*RM4%Kt?a113;wFo$*4UyvDfb*v!2><~HAT517gNQm< zwi#Y4$VZPt^!O7a=wC(?3uqHNFd3frG^S ztc+V8!aVj?%1hyW&DnI`^sNb!ja<07O|EZYYFwc0ccsz!105;=1~E}QINn3)t9!y3 z%W@pTf2SthS{VNb+rNH4mL+R>!_~sXZa-&%t-QJc{f%mYSW_ziTCp{+@9XO==Gilj zHkzasiwTucAv%dN((C&b_qNJ&!xcxPJ0B!R7EqW{?_kQ4b|h7$Ch;7+cMGXB_~k49 z>mA8yv3yze*mFTO!TM`vbI@m3#uz24^IO;3T#xuS>S=7JD_@Nb6$|FfeuFsWeykgx zPW{AAF;Bd%%s8~`h%vqvx4S4hidg5zHym(SxVaiqj6Sxce8IlSR=n27Dm4n`?RVH> z5nY3hl_Zu))Nmi8V87I))tvRm-=}ihoj26)d}MqVnIQ|G89@0mgikdVcIN!NQPg3o zUbp6$BFsyH^p^kF9 zt%YuJ1=SCX7XR)sD3zQd-=Tz#fWE39*DoGfOgl5mM0AuKE$hULf-PaAx);}mJ(F}1 z%>#_@p!FfHN2d9S%4F3BE>rgHlxsOV;+bf4y?tAMNLS?TfS6YT_n%$tJLJaXB-ug# zfs9m6w%VnHrG=*lA!e*ulV(p@DFy|)aq)aTzmD*zIj<6iZr zNH_Py;h?*6$_g?*(F+ecu>eyWu1*z2*6?~i# zsW~l@58o0)4os}RNRy26tVL6kZh~BmuZeeDb^&4!aMDhSliu>I@BeCr9Qg3Q)@mOX z=B0{a~R(^vUoXIs!B_do>*L@+#0W<&k5gV!e>RowEF2qz_7wNpB$SI|8F z%7!$_AF)o2F2ASS7DKp9cE8{x>=u`RdO>=pxgs<5CC8c5rcD|9X`)~kxz1##PIjEJ j%%t{@!qvoFj>-{D=4~ZkXkooCPIID^eRlm0{|Eg82$~#V diff --git a/crates/testing-utils/keyshares/test/dave/keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/test/dave/keyshare-held-by-alice.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..1432a01522aa968d113857728a0b7cc44a1ff3af GIT binary patch literal 2192 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 literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/dave/keyshare-held-by-charlie.keyshare b/crates/testing-utils/keyshares/test/dave/keyshare-held-by-charlie.keyshare new file mode 100644 index 0000000000000000000000000000000000000000..090e697fac72f6c3ee257fd44aba4d41d9f88059 GIT binary patch literal 2192 zcmbW1YdjNb9LF=)PO@5r#5O5Kim}aD^>LXEA#F1f?QCW)4cU&_luIkJaiR-K6DdTw zRJ1Or9JxkRWbWHkiZh&wb)s|Lt{3&u^X~iN`TaiM&;R*9)^NA|Zb$ZVLgL_bB+8fO zAI-vq!KHytt%7b zYr_gh(1;YsiXR`9{}Y{DTs-K$eh4NmI)LaIO2A^m86hEV@iZHRw}(GHl8ZZFyWa)n z>*9mMsniw7z=aq)1-7#h2~v zyfJKqs4-=aHY>rTQ=3F`hm+&BJqK~lq>x42 zq9~^U%4@P2B(14SLK?Ny>p5ts{5}N3{qbz!s3C;8hgM%|YQf>tpUNHQ)MnN$$!)ok zDZq!jx<+-a&7jOhpQ326X4ZP;`;fxwC!bjZBdaRu9^Fo{e@)YVYx{y3_C)jP#NGJX}E#x?Azo$Tb2yLNqT27T~zU?fC= zaV0E38DG+aFmu9Q7XUSoae5E7O_nrTe6+)q*x`<4B}?a$HTn44dcbpGbGBz!l#=;m zH!WU@qhHZxMY{dM=u{k_x*yNfxV$%55VN(-whExEsZ2rMFTqg972h7ukm7Gc!sTAN z*_!KuXo=nSJOmpeDraqd3pwLZZE${;h))?cuXH@r#hfl9Wx$rwGSU+fb+atPV01Fm6a8n8=1yDLu zaUq59;OsF0M+PApSJMAl)pT(~VR%PPstgJP;d@L%yWJF%(sQ0>!J+0z>4j-we-34y zeE>!Mv-{=tVIwtXa^4LO?f_RcKueM}^A3wQttN+u(*`%+g z3Vm1Ci#4k!j^^bTPB5C^?}KsFi)z#@CvK)#m8Rz2+5qFHCfHWp`Bz^S&-|oUUC<}= z)Nc>rrg47nlqa4ytq=0*x>7w7gnoR}NWVCL4gQj$T`b22vx9{;H)$rKIiSo@wepUP zuN61jCxfz7lqHm@FztvOS1a2*oZU8aBDG_IdH=BJBLiT+eu6AHYZysAaoT<_%peuH zI?X4Bu|_lKVi*^^26zHoCIFA9U;GzPk<V# z=S>AjCqsYO|I8c_NCFNW&W0UpU)8>~wJK)pLJR*Xmg~}}9o{4R2cTDr7^glHNh8*Y zFO3wqznES#C442FIlfq6w8MP2L8qMZ%x)$5gaz;pR3$c}oqMD;D)ZPC5pczknXp7H$%`^C?8rZjRnaxMc6#LkeBv5kByiWsT ztc*pi|8kIyMg-0kmJ+MHVx>8oc~(`y2E8JUQwLk$EY;{rcB6l|rR7IugY3KQ^V{B= z$<($P+I5eC2S^pwcsS;9ZCX8blbXqbH?e%Bh}#NX)#zsW$Wj|8da~&da%!V{l3?MR z-|SoZ+_l47b*?|($>a4;ntp zGwb7r@vFOVtkcA4O3UKV5Pg3!RclsFR=L9_SNwElt@|7GrFU%|-%7RX#2Sk{BJqu` q@$usE8^uyhgL_=qaGcTX3pW~yNfI@JD~oEPOC0`2fB0^Q%J?6+KOc_( literal 0 HcmV?d00001 diff --git a/crates/testing-utils/keyshares/test/eve-keyshare-0.keyshare b/crates/testing-utils/keyshares/test/eve-keyshare-0.keyshare deleted file mode 100644 index 3d92ff4a3b0f575df1ab20d5a19140c1645c24a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 zcmXpob#Zid_DT;7Gb{GUj|}xr3vqYN%uPvgt4K98^Ye;G&#v-_G7fUK40Lu1&hYhM zQaGmgzh#H)Z-=+7vfAI?9Blhu|J%bLrcPyJzl75EnuY4j2Bt2izU5}&N#W&@X@NeT@30Ta+f(p*W%L`DNsw;;Dd zpURXn({yvoz|@HR64y-AVvma4h#=p}5NE^e$dH0`*Qf&bKu3>YqhMD;CNh)mZAIqn zt1>&X@3U=T|E#Iy^6}b!{Zx)Ad(CG>MFq;=aeh5jm}Gw|GHu8#uYM9ewN!QUhlxAH z#QuHm_!6`Kjl-w?XRat*Jd~75vd0yf)75jN$f7R@>FN4R6kKE!LQE|4XX=gW{*#LMCivec;X|Bv<_Q7MsplN!M3a zPnbW=ohdl2ZKY@7L7}e-UjILTtdgE5J}c|abEcEE5=R(Oy@|@(Rk|=dRM_0Dd;6|E zch7m8&A&W9U$Q>jVE?IaTYp>qyeb^<|JUiS3N{uk?E8(T{$lZ)JE^rb|8&5d8+fd^|5H z>+$}>ri)ZG1s1uz2@9KLvopn+E8pfxb>!D;qKBk{OeS54W_;S1+qh}!dLCohg17!< ze{P{u+@s*k3H>QS^*f47nx~<97>!4ADph2* zIFTB_ZYgr@+t=Fv3|p7Z?v_vNFxjdYvv_x2|DjG1#kmuIRmDFqd^0UQe3nQDn|~rl z-WG?18?Tf;2`x8Oy7YQ}q92dJ5}&N(e~$>;ggq{Lql^IB}! z)}B2(NpSOjqdBY$b(@ccv@?Bt<-rihDY)^9T%gA%S4~6K&9N?Gc>PaCS*F^o^60>c ztL2)B39}N#eUIH*c)zn}^I@g{25sg|2d5`&-7TJMZyF-(Jz?$k{fSrX1sWE*eEM59 zRoPX|Q?=LXnzCPEKyQTeXZxSAkLxyDnw{qm>1=O0TB*9w!oo_fTI`K!>kh;2zuO13tdA@43+G|PE0!Qj;^UD>tyNx7RRv%S2Sl4X-) zRFwR)>%7#8WtTTJY8d-|(~)Re&~n9Ved*=)CGL;C@dl~Z{WrT9KTq4dJiaw=d2i1P z`KnVv7h68=ZduK+9avJOJ;?dM@PzeUM%PMr-YpuO(>2vgtC_D?PBh7Xexm5$?uw5t qr_RroQB^wjAUgW>Jh`VbtM@xNoQ^K~&)D@x+0o_F2^A^4{s#ax_Y@ca diff --git a/crates/testing-utils/keyshares/test/eve-keyshare-1.keyshare b/crates/testing-utils/keyshares/test/eve-keyshare-1.keyshare deleted file mode 100644 index c42a6bd227809efe1a9b93c9b22b2177e3e9c025..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 zcmXpobuslVHw#Y+FON(!4EC_}3r!6R^Tvkw?d!F zlrqzFbIZWgi2M@QOw(eIirk1G-^vhY!|ceAf^^rY0{1{ik6@!<)r%$f zKNodHksRO2mqI08D=0&Mz@t&6ybtMQ<;BZ9RL|+FY&uwcgLKKin?K3M%>?Td-MX z)A{8!K7IX@+oe$TD>z)~N}sF4eIklQ`uoQlr~Y^;`M%@a^zNah!c(K7=hjQeiOb@b z2W|Ipi-d=K(){BU^E^j%q4|9)#jehCwjzrPW!8ojvP_%4@k;Qlo6=`HH!dl%+j>}M zO515s2Wi!F1{JKft8*LPoab7sG2{N1RQ(6VPq&3k*vR_8ol8ir`0Xt=owJgzudJRh zf0{c}a9Z0+&%%R3UlqLmfBsk{Jx_dA)}7}}Cu=2+Frs=BmA9*OVR)#pxm)-4U3>1H z^EjJ-d49fReYnB?Q{T4!w)%NhIN<-U(_a;AELzz28%_Pi;x~6vYis`LfH^n#c7E8( z8ttO`rIVv#&a3>ATY+n4Obp(=dqbqe-wiinCT@RY#A)B8FM{9x!VfDBKic?sUQ*WM z{fA8#sb~r;a(fdNHp^ybiZfTf&6DcLuh&EmNd=iqx)RO!v@y4F)714m#&FTDkM3`HF}dQe&keap!I=~KQ-bPu6qhtlL-jBkkMz96Y;htr zfZbB$+PAN@{~5L}o!u>;*kQ6&F=p}Zy#7O-B8qb-{;G<9UifBOdiX4n4mSTpj=U`n z2{&FTeG*!3s&wh~{6s$@4z6IaVM z6BA}7iu)eBweWst&*sBS0SwyAn+{G-*t%Oh+1@ln*n7g-?fVn2*b6i)bounRY^t)W znx|^7)iq_m!hqfg=g;;(V;|RTwlq7>A=262bhJ{R?E}XJgSmoXUlJo)gqap6z1``N zU8df|c4fo;FT&OA5Bw(G-(3H4$C0BpOsIi~%4>)c=XmsT@hubgO-|NKPJ!QB-fT~3{! nEu*S*>_K$&>v?idWmfNZa5x=Z^q;ZokFul7r4uSrc>NCm9wZgk diff --git a/crates/testing-utils/keyshares/test/eve-keyshare-2.keyshare b/crates/testing-utils/keyshares/test/eve-keyshare-2.keyshare deleted file mode 100644 index 1eda2078556bf4707f9fbf084e2a262ebfe7192c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 zcmbW1c{~$*9LG0fj?@z-$~i|;vXLoFj@iuEY&LU0wV9S2Gxt@F$dR5`69QvN0JgrrAjOYy+lrw2K?O#OpgJX2A@f!2mDD z-e*ZW+<4RPEe?Vs>=5`UQ#ZO>l*b7pGS-aX>PMwwgHD){abzsc%+cRB-1U%M7@A}h z?r-YnO4kHz{=|Mb+MrN4CW&eqhGluUI-a1|qy2*z3{142ktqS^&J2jfdLD8?nUPSo zbELbMQ?>A7V~3(?4(W?ADSqBq|bd-8XsN-TEcSKi4yY4qtmYN$*& z;!8h$GK=Pa5_oXMu@pSuU8K5kKDvQlaN(i*gNi_M=bv^cNEy)D!4*-pwCsBBL`lyb zbw%#%=bRixN<@k}v@Pl2S8>S3|C*6iYkd|THnMkmgQoUg6Ic6V>dPZ2Kmenbdjz&P z#?JkpUWQFHTRzzaaih%Zf5Ul?1uB*u7MVjcGhSIjuCrCEsBCdgevN=!_*SJWqoyMC zXkClJ<#U~i)+)NM;L#G6l|hNq-7@9-3Pg*3u%WQg2bAm@i6MI#dG)ZFL9jvBZuF%2 z2xz|eiX7+MZ3lL<{E{YaePJ$Er9`Rl)cY~9m#39mfg3S5s>X;iH&=zjnDY-CAANX* z?PB$pvUVr9!TBA_bzjX_UMmpSS38$9kw;P_`Nnyx;)LSd)Kpd{v1njN!)%>|m!0ln zhE#OXBrAN7bhjXf+|c;`HvHkP(ZhCw#3&z`;2^08*Pgnnw6--5WVqrdYy zW|~SZL^d!`GA!gsoX3(-@!1|1lU#upa5O0>>3&|d>>;&~8Ry7vZ#!a`+l8`mnB)pI ziMedpM-g}YQuLbBfci(WfA&R&OG15E_*u?I;GfjicL{W)-H#|~1`#eVon8mj{dx7g z1})vB4(eUr6nybn1_WB1vl@GBj6Ka^x)nmw!Ok?P;9BeB1Cv_w@;4D$eN&}0f-HQv zOz5OS`{!H_XXv7faT?I!?%<5fcc*_*IwhvHkAqi_!VRi)0}}XZ4OiNJV?@P0C9o|q zQQR`e(ylJsf=yd`gHTNb59S$&G~O6m$Z^8suW6fb1CRaQ?88J5Ln=OSU(Do(2!)u8 z;I(OD{QBGh&3npJ9HEUXztfQoEMcr$kRi9;?yc!}NRI5YQ5=XIOE+{jS+ro!#^H6M zIeK6JPX8&yjgs>&3)*rJ=>wOJZ)^3PhxN-}(b0Ryt91Xp!+<;wBajf*4zXL!#kX<~DeSO7^{u126v!p@`hjU;$J zcDpv^-}2#sf^^U7e0Oc+ARgiNK0;ufq`eGdf>%! z)J2+mih@`;rCtphu;Ho3~(<q0LRvb9Now mS5O_ivRs#fx?tvkI!*MXVev~BGA+I9A9%Ksleh!vOs diff --git a/crates/testing-utils/keyshares/test/eve-keyshare-held-by-alice.keyshare b/crates/testing-utils/keyshares/test/eve-keyshare-held-by-alice.keyshare deleted file mode 100644 index 4281330bc501088e8710623eb15741294abf0859..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 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 diff --git a/crates/testing-utils/keyshares/test/eve-keyshare-held-by-charlie.keyshare b/crates/testing-utils/keyshares/test/eve-keyshare-held-by-charlie.keyshare deleted file mode 100644 index c5537a9d5d4a5d3c2ffc2fd998d048bd9135a584..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 zcmbW1c{~$*9LIBYjfav4HEVO`$|PfMh8i&S9i6_{w86uIP=1c~7Gyi58O6ul-8{@g9frjaJZYCuP8zld zxDCPt=VgWZl_THYV?%gl!Q`YHbmVxPvgpDPuDS2zIS#+LT$SEo?bt(hPo;6YybH^zJ}s%^Yegnt9BcfUv3b8rY>WCkFZ83pyUxgaZZ4T*MZ zvQ|lnn6$E@(3P7fbq;jzx$i+0D$B}$ZhG4~>gLb|#z)^%Al>)*#29m7T$OeC#;v1l ze2TpD)QwN=Wd_Mw?tj#a?7WXn9Ex@oCh%P^e_o%io8OrYyU;S26dd+tt8(t=m#^Nv zp}y=&&3974Pt`);!13$Fk~{aok!d-`osqWumlb-6HEAb~d{J`ABGW!4dTrC&*w!<} zztg3hxt&uO8dS~d>XNGP-SVKqy(JrgpHi1efH>HLDuXq^8)tBgK))t;9zXEzXHcuS zERnsHqirmzBR-Iz6YnW#SkVx3i6CSbKlM^qRx$MfX4#^HFw+Kz9~2|?HLA9|^y)*Xul^Fkysz+lwHRh>#1&ey*MK%7lv zxGCym$)jY>T8b4Yl)vIx4>WMz_jK9IQIButk-PH8U3z0JXNj+toT}2<6<9>fd1Og+ zoq+MsIZ>pdceZ9PGMU~kB;HwYJ8*vzD@Pdun1-Z-wseSZ$?GQ+v~#=!gH%_SEaxP2 ztEgl3kbji=qtEdC$jMx*vTH}evV~Smdt0ANo#|F=`l~i}?6{j#HM+y5 zfqPc!B+=>4$q+^KDzX1F)KJTF@mX3*u#j`*yL2-f9_eeUp-95#x{gud(EEVu!pTv! z>_)q{j_YkgInFW2rlJbyHk+^Jm7d|b7>7;%b!w6r!*ho08)Kvk+$4e4E)$visnSYJ*NcWJRGl_`|7 zPK^ajOh>NgZuGTkm32CtE82=^pFhlvY0FFRI)CLxpOmJG^y*5N|`I6&TLwaNHrL(mWQV zVg8a|Rl2uN9Kr`uXB_T-p{AV$?r(HEOvx|IE>0L^prrJh9l1^#r4;t+^R~RHBd^Pq z($gie3y$4fIa^&d26WJ*qlJ6$m`owQ_J^v1?^;5Gw$8{gVICQGAEml)z|ED?M~0_R z2vl@qFf$4FQ0m_4PE`qM@~yJmd%+^MtBUp>Mlp-Spt0fNTn0{%W?Q2cJ(ZL-%yGd0--Bq|Lo+oBf9}d3A#CxD2a4(bGsU#?J$5MD zWWQm~Qo17{h{|y`c}64Ciht{)JbU9I%EA09@yV^|LP=#-kXti1yeJoqQIrx mBr%~XT_2tZ>P0mcfD<{LlkF0)&3EOR-+BmNh1P+)^8W?e;uZ%0 diff --git a/crates/testing-utils/src/create_test_keyshares.rs b/crates/testing-utils/src/create_test_keyshares.rs index 7b80de562..0d95a5c84 100644 --- a/crates/testing-utils/src/create_test_keyshares.rs +++ b/crates/testing-utils/src/create_test_keyshares.rs @@ -30,36 +30,32 @@ use std::collections::BTreeSet; /// threshold keyshares with auxiliary info pub async fn create_test_keyshares( distributed_secret_key_bytes: [u8; 32], - alice: sr25519::Pair, - bob: sr25519::Pair, - charlie: sr25519::Pair, + signers: [sr25519::Pair; 3], ) -> Vec<(ThresholdKeyShare, AuxInfo)> where Params: SchemeParams, { let signing_key = SigningKey::from_bytes(&(distributed_secret_key_bytes).into()).unwrap(); - let signers = vec![alice.clone(), bob.clone(), charlie.clone()]; let session_id = SessionId::from_seed(b"12345".as_slice()); let all_parties = signers.iter().map(|pair| PartyId::from(pair.public())).collect::>(); let mut old_holders = all_parties.clone(); - old_holders.remove(&PartyId::from(charlie.clone().public())); + // Remove one member as we initially create 2 of 2 keyshares, then reshare to 2 of 3 + old_holders.remove(&PartyId::from(signers[2].public())); let keyshares = KeyShare::::new_centralized(&mut OsRng, &old_holders, Some(&signing_key)); let aux_infos = AuxInfo::::new_centralized(&mut OsRng, &all_parties); - let alice_id = PartyId::from(bob.public()); let new_holder = NewHolder { - verifying_key: keyshares[&alice_id].verifying_key(), + verifying_key: keyshares.values().next().unwrap().verifying_key(), old_threshold: 2, old_holders, }; - let mut sessions = signers + let mut sessions = signers[..2] .iter() - .filter(|&pair| pair.public() != charlie.public()) .map(|pair| { let inputs = KeyResharingInputs { old_holder: Some(OldHolder { @@ -82,7 +78,7 @@ where }) .collect::>(); - let charlie_session = { + let new_holder_session = { let inputs = KeyResharingInputs { old_holder: None, new_holder: Some(new_holder.clone()), @@ -92,14 +88,14 @@ where make_key_resharing_session( &mut OsRng, session_id, - PairWrapper(charlie), + PairWrapper(signers[2].clone()), &all_parties, inputs, ) .unwrap() }; - sessions.push(charlie_session); + sessions.push(new_holder_session); let new_t_key_shares = run_nodes(sessions).await; diff --git a/crates/threshold-signature-server/src/helpers/launch.rs b/crates/threshold-signature-server/src/helpers/launch.rs index a90331b97..102c44d66 100644 --- a/crates/threshold-signature-server/src/helpers/launch.rs +++ b/crates/threshold-signature-server/src/helpers/launch.rs @@ -74,6 +74,12 @@ pub enum ValidatorName { Eve, } +impl std::fmt::Display for ValidatorName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", format!("{:?}", self).to_lowercase()) + } +} + /// Output for --setup-only flag #[derive(Deserialize, Debug, Clone)] pub struct SetupOnlyOutput { diff --git a/crates/threshold-signature-server/src/helpers/tests.rs b/crates/threshold-signature-server/src/helpers/tests.rs index 71a72e099..4e85966fd 100644 --- a/crates/threshold-signature-server/src/helpers/tests.rs +++ b/crates/threshold-signature-server/src/helpers/tests.rs @@ -216,23 +216,14 @@ pub async fn spawn_testing_validators( } /// Add the pre-generated test keyshares to a kvdb -async fn put_keyshares_in_db(_index: usize, validator_name: ValidatorName) { - // Eve's keyshares are used as the network parent key - let user_name = "eve"; - - let string_validator_name = match validator_name { - ValidatorName::Alice => "alice", - ValidatorName::Bob => "bob", - ValidatorName::Charlie => "charlie", - ValidatorName::Dave => "dave", - ValidatorName::Eve => "eve", - }; +async fn put_keyshares_in_db(non_signer_name: ValidatorName, validator_name: ValidatorName) { let keyshare_bytes = { let project_root = project_root::get_project_root().expect("Error obtaining project root."); let file_path = project_root.join(format!( - "crates/testing-utils/keyshares/production/{}-keyshare-held-by-{}.keyshare", - user_name, string_validator_name + "crates/testing-utils/keyshares/production/{}/keyshare-held-by-{}.keyshare", + non_signer_name, validator_name )); + println!("File path {:?}", file_path); std::fs::read(file_path).unwrap() }; @@ -299,8 +290,7 @@ pub async fn jump_start_network_with_signer( let validators_names = vec![ValidatorName::Alice, ValidatorName::Bob, ValidatorName::Charlie, ValidatorName::Dave]; let mut non_signer = None; - let mut keyshare_index = 0; - for validator_name in validators_names { + for validator_name in validators_names.clone() { let mnemonic = development_mnemonic(&Some(validator_name)); let (tss_signer, _static_secret) = get_signer_and_x25519_secret_from_mnemonic(&mnemonic.to_string()).unwrap(); @@ -310,14 +300,21 @@ pub async fn jump_start_network_with_signer( // Ignore the error as one confirmation will fail if submit_transaction(api, rpc, &tss_signer, &jump_start_confirm_request, None) .await - .is_ok() + .is_err() { - put_keyshares_in_db(keyshare_index, validator_name).await; - keyshare_index += 1; - } else { non_signer = Some(validator_name); } } + if let Some(non_signer) = non_signer { + for validator_name in validators_names { + if non_signer != validator_name { + put_keyshares_in_db(non_signer, validator_name).await; + } + } + } else { + tracing::error!("Missing non-signer - not storing pre-generated keyshares"); + } + non_signer } diff --git a/scripts/create-test-keyshares/Cargo.toml b/scripts/create-test-keyshares/Cargo.toml index 63180cc38..fae22e389 100644 --- a/scripts/create-test-keyshares/Cargo.toml +++ b/scripts/create-test-keyshares/Cargo.toml @@ -7,12 +7,14 @@ homepage ='https://entropy.xyz/' license ='AGPL-3.0-or-later' repository ='https://github.com/entropyxyz/entropy-core' edition ='2021' +publish =false [dependencies] entropy-testing-utils={ version="0.2.0-rc.1", path="../../crates/testing-utils" } tokio ={ version="1.40", features=["macros", "fs", "rt-multi-thread", "io-util", "process"] } entropy-shared ={ version="0.2.0-rc.1", path="../../crates/shared" } entropy-kvdb ={ version="0.2.0-rc.1", path="../../crates/kvdb", default-features=false } +sp-core ="31.0.0" # Unreleased version of Synedrion with support for child key derivations. synedrion={ git="https://github.com/entropyxyz/synedrion", rev="1d210d149dfeb0dca1dd41d7fac4d0bf03c686fa" } diff --git a/scripts/create-test-keyshares/README.md b/scripts/create-test-keyshares/README.md new file mode 100644 index 000000000..ecefbdceb --- /dev/null +++ b/scripts/create-test-keyshares/README.md @@ -0,0 +1,17 @@ +# `entropy-create-test-keyshares` + +This is used to create sets of pre-generated keyshares. These are used in some of the `entropy-tss` +tests to speed up the test by not needing to run a distributed key generation during the test. + +Since keyshares are linked to the identities of the holders, and the initial signer set is selected +randomly during the test, there is one keyshare set generated per possible combination of initial +signers. + +Since we have 4 nodes, and 3 signers, we refer to each set by the name of the node who is **not** in +the signer set (which is the one who will act as the relayer node). + +So set 'alice' consists of ['bob', 'charlie', 'dave'] and set 'bob' consists of ['alice', 'charlie', +dave'], etc. + +There are also different keyshare sets for 'test' or 'production' parameters used by Synedrion. Test +parameters are less secure but mean that the protocols run much faster. diff --git a/scripts/create-test-keyshares/src/main.rs b/scripts/create-test-keyshares/src/main.rs index 5c386ce43..0dbd2bbca 100644 --- a/scripts/create-test-keyshares/src/main.rs +++ b/scripts/create-test-keyshares/src/main.rs @@ -17,60 +17,76 @@ //! The base path for where to store keyshares is given as a single command line argument //! If it is not given, the current working directory is used use entropy_kvdb::kv_manager::helpers::serialize; -use entropy_shared::{DETERMINISTIC_KEY_SHARE_DAVE, DETERMINISTIC_KEY_SHARE_EVE}; +use entropy_shared::DETERMINISTIC_KEY_SHARE_EVE; use entropy_testing_utils::create_test_keyshares::create_test_keyshares; use entropy_tss::helpers::{ - launch::{DEFAULT_ALICE_MNEMONIC, DEFAULT_BOB_MNEMONIC, DEFAULT_DAVE_MNEMONIC}, + launch::{ + ValidatorName, DEFAULT_ALICE_MNEMONIC, DEFAULT_BOB_MNEMONIC, DEFAULT_CHARLIE_MNEMONIC, + DEFAULT_DAVE_MNEMONIC, + }, validator::get_signer_and_x25519_secret_from_mnemonic, }; -use std::{env::args, path::PathBuf}; +use sp_core::sr25519; +use std::{env::args, iter::zip, path::PathBuf}; use synedrion::{ProductionParams, TestParams}; #[tokio::main] async fn main() { let base_path = PathBuf::from(args().nth(1).unwrap_or_else(|| ".".to_string())); - let (alice_pair, _) = - get_signer_and_x25519_secret_from_mnemonic(DEFAULT_ALICE_MNEMONIC).unwrap(); - let (bob_pair, _) = get_signer_and_x25519_secret_from_mnemonic(DEFAULT_BOB_MNEMONIC).unwrap(); - let (charlie_pair, _) = - get_signer_and_x25519_secret_from_mnemonic(DEFAULT_DAVE_MNEMONIC).unwrap(); + let keypairs_and_names: Vec<_> = [ + (DEFAULT_ALICE_MNEMONIC, ValidatorName::Alice), + (DEFAULT_BOB_MNEMONIC, ValidatorName::Bob), + (DEFAULT_CHARLIE_MNEMONIC, ValidatorName::Charlie), + (DEFAULT_DAVE_MNEMONIC, ValidatorName::Dave), + ] + .into_iter() + .map(|(mnemonic, name)| { + let (pair, _) = get_signer_and_x25519_secret_from_mnemonic(mnemonic).unwrap(); + (pair.signer().clone(), name) + }) + .collect(); - let names_and_secret_keys = - [("dave", *DETERMINISTIC_KEY_SHARE_DAVE), ("eve", *DETERMINISTIC_KEY_SHARE_EVE)]; + let secret_key = *DETERMINISTIC_KEY_SHARE_EVE; - for (name, secret_key) in names_and_secret_keys { - let test_keyshares = create_test_keyshares::( - secret_key, - alice_pair.signer().clone(), - bob_pair.signer().clone(), - charlie_pair.signer().clone(), - ) - .await; - let test_keyshres_serialized = + for (_keypair, name) in keypairs_and_names.iter() { + let (keypairs_this_time, names_this_time): (Vec, Vec) = + keypairs_and_names.iter().filter(|(_, n)| n != name).cloned().unzip(); + + let keypairs_this_time: [sr25519::Pair; 3] = keypairs_this_time + .try_into() + .map_err(|_| "Cannot convert keypair vector to array") + .unwrap(); + + // Create and write test keyshares + let test_keyshares = + create_test_keyshares::(secret_key, keypairs_this_time.clone()).await; + let test_keyshares_serialized: Vec<_> = test_keyshares.iter().map(|k| serialize(k).unwrap()).collect(); - write_keyshares(base_path.join("test"), name, test_keyshres_serialized).await; + let keyshares_and_names = zip(test_keyshares_serialized, names_this_time.clone()).collect(); + write_keyshares(base_path.join("test"), name, keyshares_and_names).await; - let production_keyshares = create_test_keyshares::( - secret_key, - alice_pair.signer().clone(), - bob_pair.signer().clone(), - charlie_pair.signer().clone(), - ) - .await; - let production_keyshres_serialized = + // Create and write production keyshares + let production_keyshares = + create_test_keyshares::(secret_key, keypairs_this_time.clone()).await; + let production_keyshres_serialized: Vec<_> = production_keyshares.iter().map(|k| serialize(k).unwrap()).collect(); - write_keyshares(base_path.join("production"), name, production_keyshres_serialized).await; + let keyshares_and_names = zip(production_keyshres_serialized, names_this_time).collect(); + write_keyshares(base_path.join("production"), name, keyshares_and_names).await; } } -async fn write_keyshares(base_path: PathBuf, name: &str, keyshares_bytes: Vec>) { - let holder_names = ["alice", "bob", "dave"]; - for (i, bytes) in keyshares_bytes.iter().enumerate() { - let filename = format!("{}-keyshare-held-by-{}.keyshare", name, holder_names[i]); +async fn write_keyshares( + base_path: PathBuf, + name_of_excluded: &ValidatorName, + keyshares_and_names: Vec<(Vec, ValidatorName)>, +) { + for (keyshare, name) in keyshares_and_names { let mut filepath = base_path.clone(); + filepath.push(name_of_excluded.to_string()); + let filename = format!("keyshare-held-by-{}.keyshare", name); filepath.push(filename); println!("Writing keyshare file: {:?}", filepath); - std::fs::write(filepath, bytes).unwrap(); + std::fs::write(filepath, keyshare).unwrap(); } } From f8cd3a27211fe2341847f0f0578d3bd95f1ed7bd Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 1 Oct 2024 23:26:44 +0200 Subject: [PATCH 14/17] Small fixes to `test-cli` (#1084) Small fixes to test-cli --- crates/test-cli/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/test-cli/src/lib.rs b/crates/test-cli/src/lib.rs index 8713c9774..9bc063167 100644 --- a/crates/test-cli/src/lib.rs +++ b/crates/test-cli/src/lib.rs @@ -76,6 +76,7 @@ enum CliCommand { /// interface. programs: Vec, /// Option of version numbers to go with the programs, will default to 0 if None + #[arg(short, long)] program_version_numbers: Option>, /// A name or mnemonic from which to derive a program modification keypair. /// This is used to send the register extrinsic so it must be funded @@ -311,7 +312,7 @@ pub async fn run_command( program_version_number, ) .await?; - Ok(format!("Program stored {hash}")) + Ok(format!("Program stored: {}", hex::encode(hash))) }, CliCommand::RemoveProgram { mnemonic_option, hash } => { let mnemonic = if let Some(mnemonic_option) = mnemonic_option { @@ -409,7 +410,7 @@ pub async fn run_command( if !programs.is_empty() { println!( - "{:<11} {:<48} {:<11} {:<14} {} {}", + "{:<64} {:<48} {:<11} {:<14} {} {}", "Hash".blue(), "Stored by:".green(), "Times used:".purple(), @@ -420,7 +421,7 @@ pub async fn run_command( for (hash, program_info) in programs { println!( "{} {} {:>11} {:>14} {:<13} {}", - hash, + hex::encode(hash), program_info.deployer, program_info.ref_counter, program_info.bytecode.len(), From 121714f63a10e902fdffe3188a12f9e7ee80abf9 Mon Sep 17 00:00:00 2001 From: JesseAbram <33698952+JesseAbram@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:52:16 -0400 Subject: [PATCH 15/17] Fix master build (#1088) * Fix master build * fix * Fix race condition * increase TEST_RESHARE_BLOCK * add logger to sign eth * fix do jump start * fmt --- crates/shared/src/constants.rs | 2 +- .../src/helpers/tests.rs | 29 ++++++++++--------- .../src/validator/tests.rs | 3 +- .../tests/sign_eth_tx.rs | 3 +- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/crates/shared/src/constants.rs b/crates/shared/src/constants.rs index c2bc4d689..e592a9889 100644 --- a/crates/shared/src/constants.rs +++ b/crates/shared/src/constants.rs @@ -75,7 +75,7 @@ pub const MAX_SIGNERS: u8 = 15; pub const SIGNER_THRESHOLD: u8 = 2; /// For testing to line up chain mock data and reshare_test -pub const TEST_RESHARE_BLOCK_NUMBER: u32 = 7; +pub const TEST_RESHARE_BLOCK_NUMBER: u32 = 9; /// Program version number, must be incremented if version number changes pub const PROGRAM_VERSION_NUMBER: u8 = 0; diff --git a/crates/threshold-signature-server/src/helpers/tests.rs b/crates/threshold-signature-server/src/helpers/tests.rs index 4e85966fd..ef3b37c7e 100644 --- a/crates/threshold-signature-server/src/helpers/tests.rs +++ b/crates/threshold-signature-server/src/helpers/tests.rs @@ -365,6 +365,7 @@ pub async fn do_jump_start( rpc: &LegacyRpcMethods, pair: sr25519::Pair, ) { + run_to_block(rpc, 2).await; let block_number = rpc.chain_get_header(None).await.unwrap().unwrap().number + 1; put_jumpstart_request_on_chain(api, rpc, pair).await; @@ -374,21 +375,23 @@ pub async fn do_jump_start( let validators_info = query_chain(api, rpc, selected_validators_query, None).await.unwrap().unwrap(); let validators_info: Vec<_> = validators_info.into_iter().map(|v| v.0).collect(); - let onchain_user_request = OcwMessageDkg { block_number, validators_info }; + let onchain_user_request = + OcwMessageDkg { block_number, validators_info: validators_info.clone() }; let client = reqwest::Client::new(); - let response_results = join_all( - [3002, 3003, 3004] - .iter() - .map(|port| { - client - .post(format!("http://127.0.0.1:{}/generate_network_key", port)) - .body(onchain_user_request.clone().encode()) - .send() - }) - .collect::>(), - ) - .await; + + let mut results = vec![]; + for validator_info in validators_info { + let url = format!( + "http://{}/generate_network_key", + std::str::from_utf8(&validator_info.ip_address.clone()).unwrap() + ); + if url != *"http://127.0.0.1:3001/generate_network_key" { + results.push(client.post(url).body(onchain_user_request.clone().encode()).send()) + } + } + + let response_results = join_all(results).await; let jump_start_status_query = entropy::storage().staking_extension().jump_start_progress(); let mut jump_start_status = query_chain(api, rpc, jump_start_status_query.clone(), None) diff --git a/crates/threshold-signature-server/src/validator/tests.rs b/crates/threshold-signature-server/src/validator/tests.rs index a82e0aa58..3bdefba2e 100644 --- a/crates/threshold-signature-server/src/validator/tests.rs +++ b/crates/threshold-signature-server/src/validator/tests.rs @@ -220,8 +220,9 @@ async fn test_reshare() { ); } + let current_block_number = rpc.chain_get_header(None).await.unwrap().unwrap().number; // Check that rotating the network key wont work again later - run_to_block(&rpc, block_number + 9).await; + run_to_block(&rpc, current_block_number + 3).await; let response_stale = client.post("http://127.0.0.1:3001/validator/rotate_network_key").send().await.unwrap(); diff --git a/crates/threshold-signature-server/tests/sign_eth_tx.rs b/crates/threshold-signature-server/tests/sign_eth_tx.rs index 16f946baf..e8564065f 100644 --- a/crates/threshold-signature-server/tests/sign_eth_tx.rs +++ b/crates/threshold-signature-server/tests/sign_eth_tx.rs @@ -26,7 +26,7 @@ use entropy_testing_utils::{ constants::{AUXILARY_DATA_SHOULD_SUCCEED, TEST_PROGRAM_WASM_BYTECODE}, spawn_testing_validators, test_node_process_testing_state, ChainSpecType, }; -use entropy_tss::helpers::tests::do_jump_start; +use entropy_tss::helpers::tests::{do_jump_start, initialize_test_logger}; use ethers_core::{ abi::ethabi::ethereum_types::{H160, H256}, types::{RecoveryMessage, Transaction, TransactionRequest, U256}, @@ -46,6 +46,7 @@ const GOERLI_CHAIN_ID: u64 = 5; #[tokio::test] #[serial] async fn integration_test_sign_eth_tx() { + initialize_test_logger().await; clean_tests(); let (_validator_ips, _validator_ids) = From 4af5c9e04b14a0c823eb2f63d3d30f116994bf11 Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 1 Oct 2024 23:53:38 +0200 Subject: [PATCH 16/17] Avoid panic by checking that we have a non-signing validator before selecting one (#1083) Check that we have a non-signing validator before selecting one --- crates/client/src/client.rs | 3 +++ crates/client/src/errors.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/client/src/client.rs b/crates/client/src/client.rs index 89c49514b..bf2a36ebb 100644 --- a/crates/client/src/client.rs +++ b/crates/client/src/client.rs @@ -116,6 +116,9 @@ pub async fn sign( let message_hash = Hasher::keccak(&message); let validators_info = get_validators_not_signer_for_relay(api, rpc).await?; + if validators_info.is_empty() { + return Err(ClientError::NoNonSigningValidators); + } tracing::debug!("Validators info {:?}", validators_info); let block_number = rpc.chain_get_header(None).await?.ok_or(ClientError::BlockNumber)?.number; diff --git a/crates/client/src/errors.rs b/crates/client/src/errors.rs index 163059b11..24705ae55 100644 --- a/crates/client/src/errors.rs +++ b/crates/client/src/errors.rs @@ -96,8 +96,6 @@ pub enum ClientError { TryFromSlice(#[from] std::array::TryFromSliceError), #[error("User is not registered on-chain")] NotRegistered, - #[error("No synced validators")] - NoSyncedValidators, #[error("Cannot confirm program was created")] CannotConfirmProgramCreated, #[error("Cannot confirm program was removed")] @@ -108,4 +106,6 @@ pub enum ClientError { CannotQuerySynced, #[error("Verifying key has incorrect length")] BadVerifyingKeyLength, + #[error("There are no validators which can act as a relay node for signature requests")] + NoNonSigningValidators, } From db02efe5287f85be7f1f42f6b77f23469a8d0327 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Oct 2024 08:12:10 +0000 Subject: [PATCH 17/17] Bump clap from 4.5.18 to 4.5.19 in the patch-dependencies group (#1091) Bumps the patch-dependencies group with 1 update: [clap](https://github.com/clap-rs/clap). Updates `clap` from 4.5.18 to 4.5.19 - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.18...clap_complete-v4.5.19) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch dependency-group: patch-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 14 +++++++------- crates/test-cli/Cargo.toml | 2 +- crates/threshold-signature-server/Cargo.toml | 2 +- node/cli/Cargo.toml | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8070e6e3e..7b9815faa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1307,9 +1307,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" dependencies = [ "clap_builder", "clap_derive", @@ -1317,9 +1317,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" dependencies = [ "anstream", "anstyle", @@ -14173,12 +14173,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" dependencies = [ "rustix 0.38.37", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/crates/test-cli/Cargo.toml b/crates/test-cli/Cargo.toml index 1c3599c8c..be65c76cb 100644 --- a/crates/test-cli/Cargo.toml +++ b/crates/test-cli/Cargo.toml @@ -10,7 +10,7 @@ edition ='2021' [dependencies] entropy-client={ version="0.2.0", path="../client" } -clap ={ version="4.5.18", features=["derive"] } +clap ={ version="4.5.19", features=["derive"] } colored ="2.0.4" subxt ="0.35.3" sp-core ="31.0.0" diff --git a/crates/threshold-signature-server/Cargo.toml b/crates/threshold-signature-server/Cargo.toml index bd49ebd0d..186749bf7 100644 --- a/crates/threshold-signature-server/Cargo.toml +++ b/crates/threshold-signature-server/Cargo.toml @@ -63,7 +63,7 @@ bip32={ version="0.5.2" } bip39={ version="2.0.0", features=["zeroize"] } bytes={ version="1.7", default-features=false, features=["serde"] } base64="0.22.1" -clap={ version="4.5.18", features=["derive"] } +clap={ version="4.5.19", features=["derive"] } num="0.4.3" snow="0.9.6" sha3="0.10.8" diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index e1305e632..7a7510111 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -19,7 +19,7 @@ name='entropy' [dependencies] # Third-party dependencies -clap ={ version="4.5.18", features=["derive"], optional=true } +clap ={ version="4.5.19", features=["derive"], optional=true } codec ={ package="parity-scale-codec", version="3.0.0" } futures ="0.3.30" hex-literal ="0.4.1" @@ -99,7 +99,7 @@ pallet-staking-extension={ version="0.2.0", path="../../pallets/staking" } project-root="0.2.2" [build-dependencies] -clap={ version="4.5.18", optional=true } +clap={ version="4.5.19", optional=true } pallet-balances ={ version="29.0.0" } substrate-build-script-utils={ version="11.0.0" }