From 519440e6e7c08c7281bb37bb058f6fc005270d9b Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 30 Aug 2024 10:30:53 +0200 Subject: [PATCH 1/4] Check build-time measurement (MRTD) values when verifying TDX quotes (#1024) * Check MRTD value * Comment * Add accepted MRTD values parameter to parameters pallet * Use parameter from parameters pallet * Rm constant from entropy-shared * Add accepted MRTD values parameters to chainspec * Clippy * Use vec from sp_std * Rm unused dependency * Import vec, update staking pallet mock * Update mock for registry pallet * Update mock for attestation pallet * Add accepted MRTD values parameters to testnet chainspec * Import BoundedVec * Update weights and rename benchmark to match extrinsic * Suggestion from review * Update weights * Update weights --- node/cli/src/chain_spec/dev.rs | 4 + node/cli/src/chain_spec/integration_tests.rs | 4 + node/cli/src/chain_spec/testnet.rs | 6 +- pallets/attestation/Cargo.toml | 3 +- pallets/attestation/src/lib.rs | 9 +- pallets/attestation/src/mock.rs | 13 +- pallets/parameters/src/benchmarking.rs | 12 ++ pallets/parameters/src/lib.rs | 31 ++- pallets/parameters/src/mock.rs | 1 + pallets/parameters/src/weights.rs | 200 ++++++++++--------- pallets/registry/src/mock.rs | 4 +- pallets/staking/src/mock.rs | 4 +- runtime/src/weights/pallet_parameters.rs | 74 ++++--- 13 files changed, 238 insertions(+), 127 deletions(-) diff --git a/node/cli/src/chain_spec/dev.rs b/node/cli/src/chain_spec/dev.rs index 6a8fa3cd6..4d8b2fd68 100644 --- a/node/cli/src/chain_spec/dev.rs +++ b/node/cli/src/chain_spec/dev.rs @@ -308,6 +308,10 @@ pub fn development_genesis_config( max_instructions_per_programs: INITIAL_MAX_INSTRUCTIONS_PER_PROGRAM, total_signers: TOTAL_SIGNERS, threshold: SIGNER_THRESHOLD, + accepted_mrtd_values: vec![ + BoundedVec::try_from([0; 48].to_vec()).unwrap(), + BoundedVec::try_from([1; 48].to_vec()).unwrap(), + ], ..Default::default() }, "programs": ProgramsConfig { diff --git a/node/cli/src/chain_spec/integration_tests.rs b/node/cli/src/chain_spec/integration_tests.rs index c5dd75816..1c8c833bf 100644 --- a/node/cli/src/chain_spec/integration_tests.rs +++ b/node/cli/src/chain_spec/integration_tests.rs @@ -247,6 +247,10 @@ pub fn integration_tests_genesis_config( max_instructions_per_programs: INITIAL_MAX_INSTRUCTIONS_PER_PROGRAM, total_signers: TOTAL_SIGNERS, threshold: SIGNER_THRESHOLD, + accepted_mrtd_values: vec![ + BoundedVec::try_from([0; 48].to_vec()).unwrap(), + BoundedVec::try_from([1; 48].to_vec()).unwrap(), + ], ..Default::default() }, "programs": ProgramsConfig { diff --git a/node/cli/src/chain_spec/testnet.rs b/node/cli/src/chain_spec/testnet.rs index a3ec871ac..fb5848420 100644 --- a/node/cli/src/chain_spec/testnet.rs +++ b/node/cli/src/chain_spec/testnet.rs @@ -37,7 +37,7 @@ use sc_telemetry::TelemetryEndpoints; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_core::{crypto::UncheckedInto, sr25519}; -use sp_runtime::Perbill; +use sp_runtime::{BoundedVec, Perbill}; /// The AccountID of a Threshold Signature server. This is to meant to be registered on-chain. type TssAccountId = sp_runtime::AccountId32; @@ -446,6 +446,10 @@ pub fn testnet_genesis_config( max_instructions_per_programs: INITIAL_MAX_INSTRUCTIONS_PER_PROGRAM, total_signers: TOTAL_SIGNERS, threshold: SIGNER_THRESHOLD, + accepted_mrtd_values: vec![ + BoundedVec::try_from([0; 48].to_vec()).unwrap(), + BoundedVec::try_from([1; 48].to_vec()).unwrap(), + ], ..Default::default() }, "programs": ProgramsConfig { diff --git a/pallets/attestation/Cargo.toml b/pallets/attestation/Cargo.toml index 0b3b25065..6149b527c 100644 --- a/pallets/attestation/Cargo.toml +++ b/pallets/attestation/Cargo.toml @@ -22,6 +22,7 @@ frame-benchmarking={ version="29.0.0", default-features=false, optional=true } sp-std ={ version="14.0.0", default-features=false } pallet-session ={ version="29.0.0", default-features=false, optional=true } +pallet-parameters={ version="0.2.0", path="../parameters", default-features=false } entropy-shared={ version="0.2.0", path="../../crates/shared", features=[ "wasm-no-std", ], default-features=false } @@ -37,7 +38,6 @@ 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" } -pallet-parameters ={ version="0.2.0", path="../parameters", default-features=false } tdx-quote ={ git="https://github.com/entropyxyz/tdx-quote", features=["mock"] } rand_core ="0.6.4" @@ -51,6 +51,7 @@ std=[ 'log/std', 'pallet-staking-extension/std', 'pallet-balances/std', + 'pallet-parameters/std', 'sp-io/std', "sp-runtime/std", ] diff --git a/pallets/attestation/src/lib.rs b/pallets/attestation/src/lib.rs index e98d315ff..ebab0a19e 100644 --- a/pallets/attestation/src/lib.rs +++ b/pallets/attestation/src/lib.rs @@ -121,6 +121,8 @@ pub mod pallet { NoStashAccount, /// Cannot lookup associated TS server info NoServerInfo, + /// Unacceptable VM image running + BadMrtdValue, } #[pallet::call] @@ -167,8 +169,11 @@ pub mod pallet { Error::::IncorrectInputData ); - // TODO #982 Check measurements match current release of entropy-tss - let _mrtd = quote.mrtd(); + // Check build-time measurement matches a current-supported release of entropy-tss + let mrtd_value = BoundedVec::try_from(quote.mrtd().to_vec()) + .map_err(|_| Error::::BadMrtdValue)?; + 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; diff --git a/pallets/attestation/src/mock.rs b/pallets/attestation/src/mock.rs index fea3719bc..086153d1f 100644 --- a/pallets/attestation/src/mock.rs +++ b/pallets/attestation/src/mock.rs @@ -29,7 +29,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; @@ -352,5 +352,16 @@ pub fn new_test_ext() -> sp_io::TestExternalities { }; pallet_staking_extension.assimilate_storage(&mut t).unwrap(); + let pallet_parameters = pallet_parameters::GenesisConfig:: { + request_limit: 5u32, + max_instructions_per_programs: 5u64, + total_signers: 3u8, + threshold: 2u8, + accepted_mrtd_values: vec![BoundedVec::try_from([0; 48].to_vec()).unwrap()], + _config: Default::default(), + }; + + pallet_parameters.assimilate_storage(&mut t).unwrap(); + t.into() } diff --git a/pallets/parameters/src/benchmarking.rs b/pallets/parameters/src/benchmarking.rs index 0d24fa885..a0ff82bc1 100644 --- a/pallets/parameters/src/benchmarking.rs +++ b/pallets/parameters/src/benchmarking.rs @@ -16,6 +16,7 @@ use frame_benchmarking::benchmarks; use frame_support::assert_ok; use frame_system::EventRecord; +use sp_std::vec; use super::*; #[allow(unused)] @@ -65,6 +66,17 @@ benchmarks! { assert_last_event::(Event::SignerInfoChanged{ signer_info }.into()); } + change_accepted_mrtd_values { + let origin = T::UpdateOrigin::try_successful_origin().unwrap(); + let accepted_mrtd_values = vec![BoundedVec::try_from([0; 48].to_vec()).unwrap()]; + }: { + assert_ok!( + >::change_accepted_mrtd_values(origin, accepted_mrtd_values.clone()) + ); + } + verify { + assert_last_event::(Event::AcceptedMrtdValuesChanged{ accepted_mrtd_values }.into()); + } impl_benchmark_test_suite!(Parameters, crate::mock::new_test_ext(), crate::mock::Runtime); } diff --git a/pallets/parameters/src/lib.rs b/pallets/parameters/src/lib.rs index cad018b12..4be3c7614 100644 --- a/pallets/parameters/src/lib.rs +++ b/pallets/parameters/src/lib.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 . -//! # Programs Parameters +//! # Parameters Pallet //! //! ## Overview //! @@ -37,6 +37,7 @@ use entropy_shared::MAX_SIGNERS; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; use sp_runtime::DispatchResult; +use sp_std::vec::Vec; #[cfg(test)] mod mock; @@ -67,6 +68,8 @@ pub mod module { type WeightInfo: WeightInfo; } + pub type MrtdValues = Vec>>; + #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { @@ -74,6 +77,7 @@ pub mod module { pub max_instructions_per_programs: u64, pub threshold: u8, pub total_signers: u8, + pub accepted_mrtd_values: MrtdValues, #[serde(skip)] pub _config: sp_std::marker::PhantomData, } @@ -83,6 +87,10 @@ pub mod module { fn build(&self) { assert!(self.threshold > 0, "Threhsold too low"); assert!(self.total_signers >= self.threshold, "Threshold is larger then signer"); + assert!( + !self.accepted_mrtd_values.is_empty(), + "At least one accepted MRTD value is required" + ); RequestLimit::::put(self.request_limit); MaxInstructionsPerPrograms::::put(self.max_instructions_per_programs); let signer_info = SignersSize { @@ -91,6 +99,7 @@ pub mod module { last_session_change: 0, }; SignersInfo::::put(signer_info); + AcceptedMrtdValues::::put(self.accepted_mrtd_values.clone()); } } @@ -128,6 +137,8 @@ pub mod module { MaxInstructionsPerProgramsChanged { max_instructions_per_programs: u64 }, /// Signer Info changed SignerInfoChanged { signer_info: SignersSize }, + /// Accepted MRTD values changed + AcceptedMrtdValuesChanged { accepted_mrtd_values: MrtdValues }, } /// The request limit a user can ask to a specific set of TSS in a block @@ -145,6 +156,12 @@ pub mod module { #[pallet::getter(fn signers_info)] pub type SignersInfo = StorageValue<_, SignersSize, ValueQuery>; + /// Accepted values of the TDX build-time measurement register - from the currently-supported + /// releases of entropy-tss + #[pallet::storage] + #[pallet::getter(fn accepted_mrtd_values)] + pub type AcceptedMrtdValues = StorageValue<_, MrtdValues, ValueQuery>; + #[pallet::pallet] #[pallet::without_storage_info] pub struct Pallet(_); @@ -205,5 +222,17 @@ pub mod module { Self::deposit_event(Event::SignerInfoChanged { signer_info }); Ok(()) } + + #[pallet::call_index(3)] + #[pallet::weight( ::WeightInfo::change_accepted_mrtd_values())] + pub fn change_accepted_mrtd_values( + origin: OriginFor, + accepted_mrtd_values: MrtdValues, + ) -> DispatchResult { + T::UpdateOrigin::ensure_origin(origin)?; + AcceptedMrtdValues::::put(&accepted_mrtd_values); + Self::deposit_event(Event::AcceptedMrtdValuesChanged { accepted_mrtd_values }); + Ok(()) + } } } diff --git a/pallets/parameters/src/mock.rs b/pallets/parameters/src/mock.rs index 726bbe025..812da2b27 100644 --- a/pallets/parameters/src/mock.rs +++ b/pallets/parameters/src/mock.rs @@ -138,6 +138,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { max_instructions_per_programs: 5u64, total_signers: 5u8, threshold: 3u8, + accepted_mrtd_values: vec![BoundedVec::try_from([0; 48].to_vec()).unwrap()], _config: Default::default(), }; pallet_parameters.assimilate_storage(&mut t).unwrap(); diff --git a/pallets/parameters/src/weights.rs b/pallets/parameters/src/weights.rs index 1cef038d8..b78620c33 100644 --- a/pallets/parameters/src/weights.rs +++ b/pallets/parameters/src/weights.rs @@ -13,13 +13,13 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -//! Autogenerated weights for pallet_transaction_pause +//! Autogenerated weights for `pallet_parameters` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 33.0.0 +//! DATE: 2024-08-30, STEPS: `5`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `hcastano`, CPU: `` -//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! HOSTNAME: `turnip`, CPU: `Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 // Executed Command: // ./target/release/entropy @@ -27,106 +27,128 @@ // pallet // --chain // dev -// --wasm-execution=compiled -// --pallet -// pallet_transaction_pause -// --extrinsic -// * -// --steps -// 50 -// --repeat -// 20 -// --template -// .maintain/frame-weight-template.hbs -// --output -// pallets/transaction-pause/src/weights.rs +// --pallet=pallet_parameters +// --extrinsic=change_mrtd_values +// --steps=5 +// --repeat=2 +// --header=.maintain/AGPL-3.0-header.txt +// --output=./runtime/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use frame_support::{traits::Get, weights::{constants::RocksDbWeight, Weight}}; use core::marker::PhantomData; /// Weight functions needed for pallet_transaction_pause. pub trait WeightInfo { - fn change_request_limit() -> Weight; - fn max_instructions_per_programs() -> Weight; - fn change_signers_info() -> Weight; + fn change_request_limit() -> Weight; + fn max_instructions_per_programs() -> Weight; + fn change_signers_info() -> Weight; + fn change_accepted_mrtd_values() -> Weight; } -/// Weights for pallet_transaction_pause using the Substrate node and recommended hardware. +/// Weight functions for `pallet_parameters`. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `Parameters::RequestLimit` (r:0 w:1) - /// Proof: `Parameters::RequestLimit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn change_request_limit() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_000_000 picoseconds. - Weight::from_parts(6_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Parameters::MaxInstructionsPerPrograms` (r:0 w:1) - /// Proof: `Parameters::MaxInstructionsPerPrograms` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn max_instructions_per_programs() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(4_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Parameters::SignersInfo` (r:0 w:1) - /// Proof: `Parameters::SignersInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn change_signers_info() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_000_000 picoseconds. - Weight::from_parts(4_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } + /// Storage: `Parameters::RequestLimit` (r:0 w:1) + /// Proof: `Parameters::RequestLimit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn change_request_limit() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + + /// Storage: `Parameters::MaxInstructionsPerPrograms` (r:0 w:1) + /// Proof: `Parameters::MaxInstructionsPerPrograms` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn max_instructions_per_programs() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + + /// Storage: `Parameters::SignersInfo` (r:0 w:1) + /// Proof: `Parameters::SignersInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn change_signers_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + + /// Storage: `Parameters::AcceptedMrtdValues` (r:0 w:1) + /// Proof: `Parameters::AcceptedMrtdValues` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn change_accepted_mrtd_values() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 14_134_000 picoseconds. + Weight::from_parts(22_719_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } } // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `Parameters::RequestLimit` (r:0 w:1) - /// Proof: `Parameters::RequestLimit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn change_request_limit() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_000_000 picoseconds. - Weight::from_parts(6_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - /// Storage: `Parameters::MaxInstructionsPerPrograms` (r:0 w:1) - /// Proof: `Parameters::MaxInstructionsPerPrograms` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn max_instructions_per_programs() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(4_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(RocksDbWeight::get().writes(1)) - } - /// Storage: `Parameters::SignersInfo` (r:0 w:1) - /// Proof: `Parameters::SignersInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn change_signers_info() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_000_000 picoseconds. - Weight::from_parts(4_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(RocksDbWeight::get().writes(1)) - } + /// Storage: `Parameters::RequestLimit` (r:0 w:1) + /// Proof: `Parameters::RequestLimit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn change_request_limit() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + /// Storage: `Parameters::MaxInstructionsPerPrograms` (r:0 w:1) + /// Proof: `Parameters::MaxInstructionsPerPrograms` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn max_instructions_per_programs() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + /// Storage: `Parameters::SignersInfo` (r:0 w:1) + /// Proof: `Parameters::SignersInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn change_signers_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(RocksDbWeight::get().writes(1)) + } + + /// Storage: `Parameters::AcceptedMrtdValues` (r:0 w:1) + /// Proof: `Parameters::AcceptedMrtdValues` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn change_accepted_mrtd_values() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 14_134_000 picoseconds. + Weight::from_parts(22_719_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(RocksDbWeight::get().writes(1)) + } } diff --git a/pallets/registry/src/mock.rs b/pallets/registry/src/mock.rs index dc5b75608..3d2c10f19 100644 --- a/pallets/registry/src/mock.rs +++ b/pallets/registry/src/mock.rs @@ -29,9 +29,10 @@ use sp_runtime::{ curve::PiecewiseLinear, testing::{TestXt, UintAuthorityId}, traits::{BlakeTwo256, ConvertInto, IdentityLookup}, - BuildStorage, Perbill, + BoundedVec, BuildStorage, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; +use sp_std::vec; use std::cell::RefCell; use crate as pallet_registry; @@ -387,6 +388,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { max_instructions_per_programs: 5u64, total_signers: 3u8, threshold: 2u8, + accepted_mrtd_values: vec![BoundedVec::try_from([0; 48].to_vec()).unwrap()], _config: Default::default(), } .assimilate_storage(&mut t) diff --git a/pallets/staking/src/mock.rs b/pallets/staking/src/mock.rs index 372866da4..0d1fe7159 100644 --- a/pallets/staking/src/mock.rs +++ b/pallets/staking/src/mock.rs @@ -31,9 +31,10 @@ use sp_runtime::{ curve::PiecewiseLinear, testing::{TestXt, UintAuthorityId}, traits::{BlakeTwo256, ConvertInto, IdentityLookup, OpaqueKeys, Zero}, - BuildStorage, KeyTypeId, Perbill, + BoundedVec, BuildStorage, KeyTypeId, Perbill, }; use sp_staking::{EraIndex, SessionIndex}; +use sp_std::vec; use crate as pallet_staking_extension; @@ -411,6 +412,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { max_instructions_per_programs: 5u64, total_signers: 3u8, threshold: 2u8, + accepted_mrtd_values: vec![BoundedVec::try_from([0; 48].to_vec()).unwrap()], _config: Default::default(), } .assimilate_storage(&mut t) diff --git a/runtime/src/weights/pallet_parameters.rs b/runtime/src/weights/pallet_parameters.rs index 20c750acb..24ae04b49 100644 --- a/runtime/src/weights/pallet_parameters.rs +++ b/runtime/src/weights/pallet_parameters.rs @@ -16,9 +16,9 @@ //! Autogenerated weights for `pallet_parameters` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 33.0.0 -//! DATE: 2024-07-16, STEPS: `5`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-30, STEPS: `5`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Jesses-MacBook-Pro.local`, CPU: `` +//! HOSTNAME: `turnip`, CPU: `Intel(R) Core(TM) i7-4710MQ CPU @ 2.50GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: 1024 // Executed Command: @@ -28,7 +28,7 @@ // --chain // dev // --pallet=pallet_parameters -// --extrinsic=* +// --extrinsic=change_accepted_mrtd_values // --steps=5 // --repeat=2 // --header=.maintain/AGPL-3.0-header.txt @@ -45,36 +45,50 @@ use core::marker::PhantomData; /// Weight functions for `pallet_parameters`. pub struct WeightInfo(PhantomData); impl pallet_parameters::WeightInfo for WeightInfo { - /// Storage: `Parameters::RequestLimit` (r:0 w:1) - /// Proof: `Parameters::RequestLimit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn change_request_limit() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 4_000_000 picoseconds. - Weight::from_parts(4_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Parameters::MaxInstructionsPerPrograms` (r:0 w:1) - /// Proof: `Parameters::MaxInstructionsPerPrograms` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn max_instructions_per_programs() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 3_000_000 picoseconds. - Weight::from_parts(4_000_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `Parameters::SignersInfo` (r:0 w:1) - /// Proof: `Parameters::SignersInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - fn change_signers_info() -> Weight { + /// Storage: `Parameters::RequestLimit` (r:0 w:1) + /// Proof: `Parameters::RequestLimit` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn change_request_limit() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_000_000 picoseconds. + Weight::from_parts(6_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + + /// Storage: `Parameters::MaxInstructionsPerPrograms` (r:0 w:1) + /// Proof: `Parameters::MaxInstructionsPerPrograms` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn max_instructions_per_programs() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + + /// Storage: `Parameters::SignersInfo` (r:0 w:1) + /// Proof: `Parameters::SignersInfo` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn change_signers_info() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 4_000_000 picoseconds. + Weight::from_parts(4_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + + /// Storage: `Parameters::AcceptedMrtdValues` (r:0 w:1) + /// Proof: `Parameters::AcceptedMrtdValues` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn change_accepted_mrtd_values() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_000_000 picoseconds. - Weight::from_parts(4_000_000, 0) + // Minimum execution time: 14_134_000 picoseconds. + Weight::from_parts(22_719_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } From 624b37d3bad1acdee74f724c7a2cf2a3e2ab0159 Mon Sep 17 00:00:00 2001 From: Hernando Castano Date: Fri, 30 Aug 2024 11:10:35 -0400 Subject: [PATCH 2/4] Fix `change_signers_info` benchmark (#1035) In https://github.com/entropyxyz/entropy-core/pull/978/ a couple of extra checks were added to ensure that parameters related to signing could only change so quickly. This ended up breaking one of the benchmarks since the benchmark setup used a difference that was larger than the allowed amount. I've fixed that by reading the current values from storage (set at Genesis) and updating those by the allowed amount. --- pallets/parameters/src/benchmarking.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pallets/parameters/src/benchmarking.rs b/pallets/parameters/src/benchmarking.rs index a0ff82bc1..6359bc1ce 100644 --- a/pallets/parameters/src/benchmarking.rs +++ b/pallets/parameters/src/benchmarking.rs @@ -56,7 +56,18 @@ benchmarks! { change_signers_info { let origin = T::UpdateOrigin::try_successful_origin().unwrap(); pallet_session::CurrentIndex::::put(1); - let signer_info = SignersSize { total_signers: 5, threshold: 3, last_session_change: 1 }; + + let SignersSize { + threshold: old_threshold, + total_signers: old_total_signers, + last_session_change: old_last_session_change, + } = SignersInfo::::get(); + + let signer_info = SignersSize { + total_signers: old_total_signers + 1, + threshold: old_threshold + 1, + last_session_change: old_last_session_change + 1, + }; }: { assert_ok!( >::change_signers_info(origin, signer_info.total_signers, signer_info.threshold) From 38b73d5a37321953e53c666586ad5150aa7a5120 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 07:46:41 +0000 Subject: [PATCH 3/4] Bump async-trait from 0.1.81 to 0.1.82 in the patch-dependencies group (#1037) Bumps the patch-dependencies group with 1 update: [async-trait](https://github.com/dtolnay/async-trait). Updates `async-trait` from 0.1.81 to 0.1.82 - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](https://github.com/dtolnay/async-trait/compare/0.1.81...0.1.82) --- 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 b72d4b9d4..f833f4494 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -594,9 +594,9 @@ checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", diff --git a/crates/protocol/Cargo.toml b/crates/protocol/Cargo.toml index da14af1c2..b54ebb3d9 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.81" +async-trait ="0.1.82" 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 4c997062aadd7a94a4796d15c966415787410900 Mon Sep 17 00:00:00 2001 From: peg Date: Mon, 2 Sep 2024 19:35:56 +0200 Subject: [PATCH 4/4] Add test environment with four TS servers (#1029) * Add 4 node setup to integration test chainspec * Add helper to create 4 node test setup * Reshare test spawns 4 TS servers * Add daves constants * Fix initial chain state for mock reshare * Fix reshare test * Specify chainspec type when spawning TSS nodes * Rm debug logging * Typo * Fix proactive reshare test * Rm comment * Add test helper fn * Doccomments * Refer to client fns as test_client:: in test * Update test following merge * Update test following merge * Fix test --- crates/testing-utils/src/constants.rs | 9 ++ crates/testing-utils/src/helpers.rs | 54 ++++++++ crates/testing-utils/src/lib.rs | 3 +- .../src/attestation/tests.rs | 6 +- .../src/helpers/tests.rs | 46 ++++++- .../src/signing_client/tests.rs | 11 +- .../src/user/tests.rs | 35 +++-- .../src/validator/tests.rs | 123 ++++++++++++++---- .../tests/register_and_sign.rs | 5 +- .../tests/sign_eth_tx.rs | 5 +- node/cli/src/chain_spec/integration_tests.rs | 5 +- pallets/staking/src/lib.rs | 12 +- 12 files changed, 251 insertions(+), 63 deletions(-) create mode 100644 crates/testing-utils/src/helpers.rs diff --git a/crates/testing-utils/src/constants.rs b/crates/testing-utils/src/constants.rs index 8a377e462..ada142829 100644 --- a/crates/testing-utils/src/constants.rs +++ b/crates/testing-utils/src/constants.rs @@ -32,6 +32,8 @@ lazy_static! { hex!["2cbc68e8bf0fbc1c28c282d1263fc9d29267dc12a1044fb730e8b65abc37524c"].into(), // Charlie - from DEFAULT_CHARLIE_MNEMONIC in entropy_tss::helpers::launch hex!["946140d3d5ddb980c74ffa1bb64353b5523d2d77cdf3dc617fd63de9d3b66338"].into(), + // Dave - from DEFAULT_DAVE_MNEMONIC in entropy_tss::helpers::launch + hex!["0a9054ef6b6b8ad0dd2c89895b2515583f2fbf1edced68e7328ae456d86b9402"].into(), ]; // See entropy_tss::helpers::validator::get_signer_and_x25519_secret for how these are derived @@ -57,6 +59,13 @@ lazy_static! { ] .try_into() .unwrap(), + // Dave - from DEFAULT_DAVE_MNEMONIC in entropy_tss::helpers::launch + vec![ + 165, 202, 97, 104, 222, 190, 168, 183, 231, 63, 209, 233, 19, 185, 187, 200, 10, 29, 102, + 240, 39, 50, 140, 15, 124, 112, 94, 121, 44, 182, 40, 71 + ] + .try_into() + .unwrap() ]; } diff --git a/crates/testing-utils/src/helpers.rs b/crates/testing-utils/src/helpers.rs new file mode 100644 index 000000000..60194a153 --- /dev/null +++ b/crates/testing-utils/src/helpers.rs @@ -0,0 +1,54 @@ +// Copyright (C) 2023 Entropy Cryptography Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +use crate::{ + chain_api::{get_api, get_rpc, EntropyConfig}, + spawn_testing_validators, + substrate_context::{test_context_stationary, test_node_process_testing_state}, + ChainSpecType, +}; +use entropy_protocol::PartyId; +use subxt::{backend::legacy::LegacyRpcMethods, OnlineClient}; + +/// 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 (api, rpc) = match chain_spec_type { + ChainSpecType::Development => { + let substrate_context = test_context_stationary().await; + ( + get_api(&substrate_context.node_proc.ws_url).await.unwrap(), + get_rpc(&substrate_context.node_proc.ws_url).await.unwrap(), + ) + }, + ChainSpecType::Integration => { + // 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; + ( + get_api(&substrate_context.ws_url).await.unwrap(), + get_rpc(&substrate_context.ws_url).await.unwrap(), + ) + }, + }; + (api, rpc, validator_ips, validator_ids) +} diff --git a/crates/testing-utils/src/lib.rs b/crates/testing-utils/src/lib.rs index 8da2a5cda..22329cb1c 100644 --- a/crates/testing-utils/src/lib.rs +++ b/crates/testing-utils/src/lib.rs @@ -19,10 +19,11 @@ extern crate lazy_static; pub use entropy_tss::chain_api; pub mod constants; pub mod create_test_keyshares; +pub mod helpers; mod node_proc; pub mod substrate_context; pub use entropy_tss::helpers::tests::{ - jump_start_network_with_signer as jump_start_network, spawn_testing_validators, + jump_start_network_with_signer as jump_start_network, spawn_testing_validators, ChainSpecType, }; pub use node_proc::TestNodeProcess; pub use substrate_context::*; diff --git a/crates/threshold-signature-server/src/attestation/tests.rs b/crates/threshold-signature-server/src/attestation/tests.rs index fb31117b9..6dc8a495c 100644 --- a/crates/threshold-signature-server/src/attestation/tests.rs +++ b/crates/threshold-signature-server/src/attestation/tests.rs @@ -16,7 +16,7 @@ use crate::{ chain_api::{entropy, get_api, get_rpc}, helpers::{ substrate::query_chain, - tests::{initialize_test_logger, run_to_block, spawn_testing_validators}, + tests::{initialize_test_logger, run_to_block, spawn_testing_validators, ChainSpecType}, }, }; use entropy_kvdb::clean_tests; @@ -32,7 +32,9 @@ async fn test_attest() { clean_tests(); let cxt = test_node_process_stationary().await; - let (_validator_ips, _validator_ids) = spawn_testing_validators(false).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(false, 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/tests.rs b/crates/threshold-signature-server/src/helpers/tests.rs index e684e491d..e754a8f88 100644 --- a/crates/threshold-signature-server/src/helpers/tests.rs +++ b/crates/threshold-signature-server/src/helpers/tests.rs @@ -42,7 +42,6 @@ use entropy_kvdb::{encrypted_sled::PasswordMethod, get_db_path, kv_manager::KvMa use entropy_protocol::PartyId; use entropy_shared::{DAVE_VERIFYING_KEY, EVE_VERIFYING_KEY, NETWORK_PARENT_KEY}; use std::time::Duration; - use subxt::{ backend::legacy::LegacyRpcMethods, ext::sp_core::sr25519, tx::PairSigner, utils::AccountId32 as SubxtAccountId32, Config, OnlineClient, @@ -119,10 +118,29 @@ pub async fn create_clients( (app, kv_store) } -/// Spawn 3 TSS nodes with pre-stored keyshares -pub async fn spawn_testing_validators(add_parent_key: bool) -> (Vec, Vec) { +/// A way to specify which chainspec to use in testing +#[derive(Clone, PartialEq)] +pub enum ChainSpecType { + /// The development chainspec, which has 3 TSS nodes + Development, + /// The integration test chainspec, which has 4 TSS nodes + Integration, +} + +/// 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; + // spawn threshold servers - let ports = [3001i64, 3002, 3003]; + let mut ports = vec![3001i64, 3002, 3003]; + + if add_fourth_server { + ports.push(3004); + } let (alice_axum, alice_kv) = create_clients("validator1".to_string(), vec![], vec![], &Some(ValidatorName::Alice)).await; @@ -143,11 +161,12 @@ pub async fn spawn_testing_validators(add_parent_key: bool) -> (Vec, Vec *get_signer(&charlie_kv).await.unwrap().account_id().clone().as_ref(), )); - let ids = vec![alice_id, bob_id, charlie_id]; + 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 @@ -170,6 +189,23 @@ pub async fn spawn_testing_validators(add_parent_key: bool) -> (Vec, Vec axum::serve(listener_charlie, charlie_axum).await.unwrap(); }); + if add_fourth_server { + let (dave_axum, dave_kv) = + create_clients("validator4".to_string(), vec![], vec![], &Some(ValidatorName::Dave)) + .await; + + let listener_dave = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", ports[3])) + .await + .expect("Unable to bind to given server address."); + tokio::spawn(async move { + axum::serve(listener_dave, dave_axum).await.unwrap(); + }); + let dave_id = PartyId::new(SubxtAccountId32( + *get_signer(&dave_kv).await.unwrap().account_id().clone().as_ref(), + )); + ids.push(dave_id); + } + tokio::time::sleep(Duration::from_secs(1)).await; let ips = ports.iter().map(|port| format!("127.0.0.1:{port}")).collect(); diff --git a/crates/threshold-signature-server/src/signing_client/tests.rs b/crates/threshold-signature-server/src/signing_client/tests.rs index b4a9ee4ff..63cc8f6b3 100644 --- a/crates/threshold-signature-server/src/signing_client/tests.rs +++ b/crates/threshold-signature-server/src/signing_client/tests.rs @@ -20,7 +20,7 @@ use crate::{ launch::LATEST_BLOCK_NUMBER_PROACTIVE_REFRESH, tests::{ initialize_test_logger, run_to_block, setup_client, spawn_testing_validators, - unsafe_get, + unsafe_get, ChainSpecType, }, }, }; @@ -45,7 +45,8 @@ async fn test_proactive_refresh() { clean_tests(); let _cxt = test_node_process_testing_state(false).await; - let (validator_ips, _ids) = spawn_testing_validators(false).await; + let (validator_ips, _ids) = spawn_testing_validators(false, ChainSpecType::Integration).await; + let signing_committee_ips = &validator_ips[..3].to_vec(); let client = reqwest::Client::new(); @@ -78,14 +79,14 @@ async fn test_proactive_refresh() { }; let test_fail_incorrect_data = - submit_transaction_requests(validator_ips.clone(), ocw_message.clone()).await; + submit_transaction_requests(signing_committee_ips.clone(), ocw_message.clone()).await; for res in test_fail_incorrect_data { assert_eq!(res.unwrap().text().await.unwrap(), "Proactive Refresh data incorrect"); } ocw_message.validators_info[0].x25519_public_key = X25519_PUBLIC_KEYS[0]; let test_user_res = - submit_transaction_requests(validator_ips.clone(), ocw_message.clone()).await; + submit_transaction_requests(signing_committee_ips.clone(), ocw_message.clone()).await; for res in test_user_res { assert_eq!(res.unwrap().text().await.unwrap(), ""); @@ -104,7 +105,7 @@ async fn test_proactive_refresh() { ocw_message.validators_info[2].tss_account = alice.public().encode(); let test_user_res_not_in_group = - submit_transaction_requests(validator_ips.clone(), ocw_message.clone()).await; + submit_transaction_requests(signing_committee_ips.clone(), ocw_message.clone()).await; for res in test_user_res_not_in_group { assert_eq!( res.unwrap().text().await.unwrap(), diff --git a/crates/threshold-signature-server/src/user/tests.rs b/crates/threshold-signature-server/src/user/tests.rs index 59d41f3d8..7ae0cd3b6 100644 --- a/crates/threshold-signature-server/src/user/tests.rs +++ b/crates/threshold-signature-server/src/user/tests.rs @@ -122,7 +122,7 @@ use crate::{ substrate::{get_oracle_data, 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, unsafe_get, + run_to_block, setup_client, spawn_testing_validators, unsafe_get, ChainSpecType, }, user::compute_hash, validator::get_signer_and_x25519_secret_from_mnemonic, @@ -169,7 +169,8 @@ async fn test_signature_requests_fail_on_different_conditions() { let two = AccountKeyring::Two; let add_parent_key_to_kvdb = true; - let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key_to_kvdb).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key_to_kvdb, 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. @@ -326,7 +327,8 @@ async fn signature_request_with_derived_account_works() { let charlie = AccountKeyring::Charlie; let add_parent_key_to_kvdb = true; - let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key_to_kvdb).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key_to_kvdb, 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. @@ -396,7 +398,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).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -470,7 +473,8 @@ async fn test_request_limit_are_updated_during_signing() { let two = AccountKeyring::Two; let add_parent_key = true; - let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -592,7 +596,8 @@ async fn test_fails_to_sign_if_non_signing_group_participants_are_used() { let two = AccountKeyring::Two; let add_parent_key = true; - let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -703,7 +708,8 @@ async fn test_program_with_config() { let two = AccountKeyring::Two; let add_parent_key = true; - let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -790,7 +796,8 @@ async fn test_jumpstart_network() { let alice = AccountKeyring::Alice; let cxt = test_context_stationary().await; - let (_validator_ips, _validator_ids) = spawn_testing_validators(false).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(false, ChainSpecType::Development).await; let api = get_api(&cxt.node_proc.ws_url).await.unwrap(); let rpc = get_rpc(&cxt.node_proc.ws_url).await.unwrap(); @@ -1002,7 +1009,8 @@ async fn test_fail_infinite_program() { let two = AccountKeyring::Two; let add_parent_key = true; - let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key, ChainSpecType::Integration).await; let force_authoring = true; let substrate_context = test_node_process_testing_state(force_authoring).await; @@ -1085,7 +1093,8 @@ async fn test_device_key_proxy() { let two = AccountKeyring::Two; let add_parent_key_to_kvdb = true; - let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key_to_kvdb).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key_to_kvdb, 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. @@ -1223,7 +1232,8 @@ async fn test_faucet() { let two = AccountKeyring::Eve; let alice = AccountKeyring::Alice; - let (validator_ips, _validator_ids) = spawn_testing_validators(false).await; + let (validator_ips, _validator_ids) = + spawn_testing_validators(false, 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(); @@ -1395,7 +1405,8 @@ async fn test_new_registration_flow() { let charlie = AccountKeyring::Charlie; let add_parent_key_to_kvdb = true; - let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key_to_kvdb).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key_to_kvdb, 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 07854ac49..bb8057793 100644 --- a/crates/threshold-signature-server/src/validator/tests.rs +++ b/crates/threshold-signature-server/src/validator/tests.rs @@ -14,19 +14,27 @@ // along with this program. If not, see . use super::api::{check_balance_for_fees, check_forbidden_key}; use crate::{ - chain_api::{get_api, get_rpc}, helpers::{ launch::{FORBIDDEN_KEYS, LATEST_BLOCK_NUMBER_RESHARE}, tests::{ initialize_test_logger, run_to_block, setup_client, spawn_testing_validators, - unsafe_get, + unsafe_get, ChainSpecType, }, }, + user::tests::jump_start_network, validator::{ api::{is_signer_or_delete_parent_key, prune_old_holders, validate_new_reshare}, errors::ValidatorErr, }, }; +use entropy_client as test_client; +use entropy_client::{ + chain_api::{ + entropy::runtime_types::bounded_collections::bounded_vec::BoundedVec, + entropy::runtime_types::pallet_registry::pallet::ProgramInstance, get_api, get_rpc, + }, + Hasher, +}; use entropy_kvdb::{ clean_tests, kv_manager::helpers::{deserialize, serialize}, @@ -35,6 +43,9 @@ use entropy_protocol::KeyShareWithAuxInfo; use entropy_shared::{ OcwMessageReshare, MIN_BALANCE, NETWORK_PARENT_KEY, TEST_RESHARE_BLOCK_NUMBER, }; +use entropy_testing_utils::constants::{ + AUXILARY_DATA_SHOULD_SUCCEED, PREIMAGE_SHOULD_SUCCEED, TEST_PROGRAM_WASM_BYTECODE, +}; use entropy_testing_utils::{ constants::{ALICE_STASH_ADDRESS, RANDOM_ACCOUNT}, substrate_context::{test_node_process_testing_state, testing_context}, @@ -43,7 +54,10 @@ use entropy_testing_utils::{ use futures::future::join_all; use parity_scale_codec::Encode; use serial_test::serial; +use sp_core::Pair; use sp_keyring::AccountKeyring; +use subxt::utils::AccountId32; +use synedrion::k256::ecdsa::VerifyingKey; #[tokio::test] #[serial] @@ -51,33 +65,34 @@ async fn test_reshare() { initialize_test_logger().await; clean_tests(); - let alice = AccountKeyring::AliceStash; + 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).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key_to_kvdb, ChainSpecType::Integration).await; - let validator_ports = vec![3001, 3002, 3003]; + 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 { + for port in &validator_ports[..3] { key_shares_before.push(unsafe_get(&client, hex::encode(NETWORK_PARENT_KEY), *port).await); } - crate::user::tests::jump_start_network(&api, &rpc).await; + jump_start_network(&api, &rpc).await; let block_number = TEST_RESHARE_BLOCK_NUMBER; let onchain_reshare_request = - OcwMessageReshare { new_signer: alice.public().encode(), block_number }; + OcwMessageReshare { new_signer: dave.public().encode(), block_number }; run_to_block(&rpc, block_number + 1).await; let response_results = join_all( - validator_ports + validator_ports[1..] .iter() .map(|port| { client @@ -92,7 +107,7 @@ async fn test_reshare() { assert_eq!(response_result.unwrap().text().await.unwrap(), ""); } - for i in 0..validator_ports.len() { + for i in 0..3 { let (key_share_before, aux_info_before): KeyShareWithAuxInfo = deserialize(&key_shares_before[i]).unwrap(); @@ -105,7 +120,11 @@ async fn test_reshare() { assert_eq!(serialize(&key_share_before).unwrap(), serialize(&key_share_after).unwrap()); // Check aux info has not yet changed 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 _ = client .post(format!("http://127.0.0.1:{}/validator/rotate_network_key", validator_ports[i])) .send() @@ -117,16 +136,22 @@ async fn test_reshare() { let (key_share_after_rotate, aux_info_after_rotate): KeyShareWithAuxInfo = deserialize(&key_share_and_aux_data_after_rotate).unwrap(); - // Check key share has changed - assert_ne!( - serialize(&key_share_before).unwrap(), - serialize(&key_share_after_rotate).unwrap() - ); - // Check aux info has changed - assert_ne!( - serialize(&aux_info_before).unwrap(), - serialize(&aux_info_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 { + let (key_share_before, aux_info_before): KeyShareWithAuxInfo = + deserialize(&key_shares_before[i]).unwrap(); + // Check key share has changed + assert_ne!( + serialize(&key_share_before).unwrap(), + serialize(&key_share_after_rotate).unwrap() + ); + // Check aux info has changed + assert_ne!( + serialize(&aux_info_before).unwrap(), + serialize(&aux_info_after_rotate).unwrap() + ); + } // calling twice doesn't do anything let response = client @@ -153,6 +178,7 @@ async fn test_reshare() { ); } + // Check that rotating the network key wont work again later run_to_block(&rpc, block_number + 7).await; let response_stale = @@ -160,7 +186,57 @@ async fn test_reshare() { assert_eq!(response_stale.text().await.unwrap(), "Data is stale"); - // TODO #981 - test signing a message with the new keyshare set + // Now test signing a message with the new keyshare set + let account_owner = AccountKeyring::Ferdie.pair(); + let signature_request_author = AccountKeyring::One; + // Store a program + let program_pointer = test_client::store_program( + &api, + &rpc, + &account_owner, + TEST_PROGRAM_WASM_BYTECODE.to_owned(), + vec![], + vec![], + vec![], + ) + .await + .unwrap(); + + // Register, using that program + let (verifying_key, _registered_info) = test_client::register( + &api, + &rpc, + account_owner.clone(), + AccountId32(account_owner.public().0), + BoundedVec(vec![ProgramInstance { program_pointer, program_config: vec![] }]), + ) + .await + .unwrap(); + + // Sign a message + let recoverable_signature = test_client::sign( + &api, + &rpc, + signature_request_author.pair(), + verifying_key, + PREIMAGE_SHOULD_SUCCEED.to_vec(), + Some(AUXILARY_DATA_SHOULD_SUCCEED.to_vec()), + ) + .await + .unwrap(); + + // Check the signature + let message_should_succeed_hash = Hasher::keccak(PREIMAGE_SHOULD_SUCCEED); + let recovery_key_from_sig = VerifyingKey::recover_from_prehash( + &message_should_succeed_hash, + &recoverable_signature.signature, + recoverable_signature.recovery_id, + ) + .unwrap(); + assert_eq!( + verifying_key.to_vec(), + recovery_key_from_sig.to_encoded_point(true).to_bytes().to_vec() + ); clean_tests(); } @@ -173,9 +249,10 @@ 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).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key_to_kvdb, ChainSpecType::Integration).await; - let validator_ports = vec![3001, 3002, 3003]; + let validator_ports = vec![3001, 3002, 3003, 3004]; let client = reqwest::Client::new(); diff --git a/crates/threshold-signature-server/tests/register_and_sign.rs b/crates/threshold-signature-server/tests/register_and_sign.rs index 839bd41d9..d54c961b9 100644 --- a/crates/threshold-signature-server/tests/register_and_sign.rs +++ b/crates/threshold-signature-server/tests/register_and_sign.rs @@ -26,7 +26,7 @@ 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, + jump_start_network, spawn_testing_validators, test_node_process_testing_state, ChainSpecType, }; use serial_test::serial; use sp_core::{sr25519, Pair}; @@ -42,7 +42,8 @@ async fn integration_test_register_and_sign() { let signature_request_author = AccountKeyring::One; let add_parent_key = true; - let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key, 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 00279dad4..1aa9cd399 100644 --- a/crates/threshold-signature-server/tests/sign_eth_tx.rs +++ b/crates/threshold-signature-server/tests/sign_eth_tx.rs @@ -25,7 +25,7 @@ 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, + jump_start_network, spawn_testing_validators, test_node_process_testing_state, ChainSpecType, }; use ethers_core::{ abi::ethabi::ethereum_types::{H160, H256}, @@ -51,7 +51,8 @@ async fn integration_test_sign_eth_tx() { let signature_request_author = AccountKeyring::One; let add_parent_key = true; - let (_validator_ips, _validator_ids) = spawn_testing_validators(add_parent_key).await; + let (_validator_ips, _validator_ids) = + spawn_testing_validators(add_parent_key, 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 1c8c833bf..474751572 100644 --- a/node/cli/src/chain_spec/integration_tests.rs +++ b/node/cli/src/chain_spec/integration_tests.rs @@ -58,7 +58,6 @@ pub fn integration_tests_config() -> ChainSpec { vec![], get_account_id_from_seed::("Alice"), vec![ - get_account_id_from_seed::("Alice//stash"), get_account_id_from_seed::("Bob//stash"), get_account_id_from_seed::("Charlie//stash"), ], @@ -182,7 +181,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:3002".as_bytes().to_vec(), + "127.0.0.1:3004".as_bytes().to_vec(), ), ), ], @@ -215,7 +214,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::("Alice//stash")],), + mock_signer_rotate: (true, mock_signer_rotate_data, vec![get_account_id_from_seed::("Dave//stash")],), }, "elections": ElectionsConfig { members: endowed_accounts diff --git a/pallets/staking/src/lib.rs b/pallets/staking/src/lib.rs index fd4c79f50..f6ea6f16a 100644 --- a/pallets/staking/src/lib.rs +++ b/pallets/staking/src/lib.rs @@ -279,14 +279,10 @@ pub mod pallet { ProactiveRefresh::::put(refresh_info); // mocks a signer rotation for tss new_reshare tests if self.mock_signer_rotate.0 { - self.mock_signer_rotate - .clone() - .1 - .push(self.mock_signer_rotate.clone().2[0].clone()); - NextSigners::::put(NextSignerInfo { - next_signers: self.mock_signer_rotate.clone().1, - confirmations: vec![], - }); + let next_signers = &mut self.mock_signer_rotate.1.clone(); + next_signers.push(self.mock_signer_rotate.2[0].clone()); + let next_signers = next_signers.to_vec(); + NextSigners::::put(NextSignerInfo { next_signers, confirmations: vec![] }); ReshareData::::put(ReshareInfo { // To give enough time for test_reshare setup