diff --git a/pallets/attestation/src/default_weights.rs b/pallets/attestation/src/default_weights.rs index 271f0e2371..aead661720 100644 --- a/pallets/attestation/src/default_weights.rs +++ b/pallets/attestation/src/default_weights.rs @@ -19,24 +19,22 @@ //! Autogenerated weights for attestation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-07-21, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! DATE: 2021-08-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// target/release/kilt-parachain +// /home/willi/mashnet-node/target/release/kilt-parachain // benchmark // --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=attestation +// --extrinsic=* // --execution=wasm -// --wasm-execution=Compiled +// --wasm-execution=compiled // --heap-pages=4096 -// --extrinsic=* -// --pallet=attestation -// --steps=1 -// --repeat=20 -// --template -// .maintain/weight-template.hbs -// --output -// pallets/attestation/src/default_weights.rs +// --output=../../pallets/attestation/src/default_weights.rs +// --template=../../.maintain/weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -56,14 +54,14 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn add() -> Weight { - (38_091_000_u64) + (67_918_000_u64) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn revoke(d: u32, ) -> Weight { - (25_042_000_u64) - // Standard Error: 28_000 - .saturating_add((4_866_000_u64).saturating_mul(d as Weight)) + (46_093_000_u64) + // Standard Error: 202_000 + .saturating_add((8_252_000_u64).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(d as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -73,14 +71,14 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn add() -> Weight { - (38_091_000_u64) + (67_918_000_u64) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } fn revoke(d: u32, ) -> Weight { - (25_042_000_u64) - // Standard Error: 28_000 - .saturating_add((4_866_000_u64).saturating_mul(d as Weight)) + (46_093_000_u64) + // Standard Error: 202_000 + .saturating_add((8_252_000_u64).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(d as Weight))) .saturating_add(RocksDbWeight::get().writes(1_u64)) diff --git a/pallets/attestation/src/lib.rs b/pallets/attestation/src/lib.rs index 5df121d82e..c27fd9caf0 100644 --- a/pallets/attestation/src/lib.rs +++ b/pallets/attestation/src/lib.rs @@ -85,8 +85,6 @@ pub mod benchmarking; #[cfg(test)] mod tests; -use sp_std::vec::Vec; - pub use crate::{attestations::*, default_weights::WeightInfo, pallet::*}; use frame_support::traits::Get; @@ -94,7 +92,7 @@ use frame_support::traits::Get; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, BoundedVec}; use frame_system::pallet_prelude::*; /// Type of a claim hash. @@ -114,6 +112,11 @@ pub mod pallet { type EnsureOrigin: EnsureOrigin, ::Origin>; type Event: From> + IsType<::Event>; type WeightInfo: WeightInfo; + + /// The maximum number of delegated attestations which can be made by + /// the same delegation. + #[pallet::constant] + type MaxDelegatedAttestations: Get; } #[pallet::pallet] @@ -135,7 +138,12 @@ pub mod pallet { /// It maps from a delegation ID to a vector of claim hashes. #[pallet::storage] #[pallet::getter(fn delegated_attestations)] - pub type DelegatedAttestations = StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, Vec>>; + pub type DelegatedAttestations = StorageMap< + _, + Blake2_128Concat, + DelegationNodeIdOf, + BoundedVec, ::MaxDelegatedAttestations>, + >; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -178,6 +186,10 @@ pub mod pallet { /// is but it has been revoked. Only when the revoker is not the /// original attester. UnauthorizedRevocation, + /// The maximum number of delegated attestations has already been + /// reached for the corresponding delegation id such that another one + /// cannot be added. + MaxDelegatedAttestationsExceeded, } #[pallet::call] @@ -244,7 +256,9 @@ pub mod pallet { // If the attestation is based on a delegation, store separately let mut delegated_attestations = >::get(delegation_id).unwrap_or_default(); - delegated_attestations.push(claim_hash); + delegated_attestations + .try_push(claim_hash) + .map_err(|_| Error::::MaxDelegatedAttestationsExceeded)?; >::insert(delegation_id, delegated_attestations); } diff --git a/pallets/attestation/src/mock.rs b/pallets/attestation/src/mock.rs index 52eca90fd3..7505899792 100644 --- a/pallets/attestation/src/mock.rs +++ b/pallets/attestation/src/mock.rs @@ -23,7 +23,7 @@ use crate::*; use ctype::mock as ctype_mock; use codec::Decode; -use frame_support::{ensure, parameter_types, weights::constants::RocksDbWeight}; +use frame_support::{ensure, parameter_types, weights::constants::RocksDbWeight, BoundedVec}; use frame_system::EnsureSigned; use sp_core::{ed25519, sr25519, Pair}; use sp_keystore::{testing::KeyStore, KeystoreExt}; @@ -100,6 +100,8 @@ parameter_types! { pub const MaxSignatureByteLength: u16 = 64; pub const MaxParentChecks: u32 = 5; pub const MaxRevocations: u32 = 5; + #[derive(Clone)] + pub const MaxChildren: u32 = 1000; } impl delegation::Config for Test { @@ -111,13 +113,20 @@ impl delegation::Config for Test { type MaxSignatureByteLength = MaxSignatureByteLength; type MaxParentChecks = MaxParentChecks; type MaxRevocations = MaxRevocations; + type MaxChildren = MaxChildren; type WeightInfo = (); } +parameter_types! { + // TODO: Find reasonable number + pub const MaxDelegatedAttestations: u32 = 1000; +} + impl Config for Test { type EnsureOrigin = EnsureSigned; type Event = (); type WeightInfo = (); + type MaxDelegatedAttestations = MaxDelegatedAttestations; } impl delegation::VerifyDelegateSignature for Test { @@ -227,7 +236,10 @@ pub fn generate_base_attestation(attester: TestAttester) -> AttestationDetails)>, - delegated_attestations_stored: Vec<(TestDelegationNodeId, Vec)>, + delegated_attestations_stored: Vec<( + TestDelegationNodeId, + BoundedVec::MaxDelegatedAttestations>, + )>, } impl Default for ExtBuilder { @@ -247,7 +259,10 @@ impl ExtBuilder { pub fn with_delegated_attestations( mut self, - delegated_attestations: Vec<(TestDelegationNodeId, Vec)>, + delegated_attestations: Vec<( + TestDelegationNodeId, + BoundedVec::MaxDelegatedAttestations>, + )>, ) -> Self { self.delegated_attestations_stored = delegated_attestations; self diff --git a/pallets/delegation/src/benchmarking.rs b/pallets/delegation/src/benchmarking.rs index 62a00badd6..d03dcc180d 100644 --- a/pallets/delegation/src/benchmarking.rs +++ b/pallets/delegation/src/benchmarking.rs @@ -18,12 +18,12 @@ use codec::Encode; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite}; -use frame_support::dispatch::DispatchErrorWithPostInfo; +use frame_support::{dispatch::DispatchErrorWithPostInfo, storage::bounded_btree_set::BoundedBTreeSet}; use frame_system::RawOrigin; use sp_core::{offchain::KeyTypeId, sr25519}; use sp_io::crypto::sr25519_generate; use sp_runtime::MultiSignature; -use sp_std::{collections::btree_set::BTreeSet, num::NonZeroU32, vec::Vec}; +use sp_std::{num::NonZeroU32, vec::Vec}; use crate::*; @@ -223,7 +223,7 @@ benchmarks! { let c in 1 .. T::MaxParentChecks::get(); let (_, hierarchy_id, leaf_acc, leaf_id) = setup_delegations::(r, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; let root_node = DelegationNodes::::get(hierarchy_id).expect("Root hierarchy node should be present on chain."); - let children: BTreeSet = root_node.children; + let children: BoundedBTreeSet = root_node.children; let child_id: T::DelegationNodeId = *children.iter().next().ok_or("Root should have children")?; let child_delegation = DelegationNodes::::get(child_id).ok_or("Child of root should have delegation id")?; }: revoke_delegation(RawOrigin::Signed(child_delegation.details.owner.clone()), child_id, c, r) diff --git a/pallets/delegation/src/default_weights.rs b/pallets/delegation/src/default_weights.rs index 6bee212825..a3d286eda6 100644 --- a/pallets/delegation/src/default_weights.rs +++ b/pallets/delegation/src/default_weights.rs @@ -19,24 +19,22 @@ //! Autogenerated weights for delegation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-07-21, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! DATE: 2021-08-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// target/release/kilt-parachain +// /home/willi/mashnet-node/target/release/kilt-parachain // benchmark // --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=delegation +// --extrinsic=* // --execution=wasm -// --wasm-execution=Compiled +// --wasm-execution=compiled // --heap-pages=4096 -// --extrinsic=* -// --pallet=delegation -// --steps=1 -// --repeat=20 -// --template -// .maintain/weight-template.hbs -// --output -// pallets/delegation/src/default_weights.rs +// --output=../../pallets/delegation/src/default_weights.rs +// --template=../../.maintain/weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -58,29 +56,29 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn create_hierarchy() -> Weight { - (24_797_000_u64) + (49_402_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn add_delegation() -> Weight { - (80_841_000_u64) + (131_777_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn revoke_delegation_root_child(r: u32, _c: u32, ) -> Weight { - (17_804_000_u64) - // Standard Error: 94_000 - .saturating_add((17_445_000_u64).saturating_mul(r as Weight)) + (32_769_000_u64) + // Standard Error: 373_000 + .saturating_add((29_614_000_u64).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r as Weight))) } fn revoke_delegation_leaf(r: u32, c: u32, ) -> Weight { - (31_213_000_u64) - // Standard Error: 61_000 - .saturating_add((327_000_u64).saturating_mul(r as Weight)) - // Standard Error: 61_000 - .saturating_add((5_210_000_u64).saturating_mul(c as Weight)) + (54_214_000_u64) + // Standard Error: 196_000 + .saturating_add((484_000_u64).saturating_mul(r as Weight)) + // Standard Error: 196_000 + .saturating_add((8_692_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -90,29 +88,29 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn create_hierarchy() -> Weight { - (24_797_000_u64) + (49_402_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } fn add_delegation() -> Weight { - (80_841_000_u64) + (131_777_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } fn revoke_delegation_root_child(r: u32, _c: u32, ) -> Weight { - (17_804_000_u64) - // Standard Error: 94_000 - .saturating_add((17_445_000_u64).saturating_mul(r as Weight)) + (32_769_000_u64) + // Standard Error: 373_000 + .saturating_add((29_614_000_u64).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r as Weight))) } fn revoke_delegation_leaf(r: u32, c: u32, ) -> Weight { - (31_213_000_u64) - // Standard Error: 61_000 - .saturating_add((327_000_u64).saturating_mul(r as Weight)) - // Standard Error: 61_000 - .saturating_add((5_210_000_u64).saturating_mul(c as Weight)) + (54_214_000_u64) + // Standard Error: 196_000 + .saturating_add((484_000_u64).saturating_mul(r as Weight)) + // Standard Error: 196_000 + .saturating_add((8_692_000_u64).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(c as Weight))) .saturating_add(RocksDbWeight::get().writes(1_u64)) diff --git a/pallets/delegation/src/delegation_hierarchy.rs b/pallets/delegation/src/delegation_hierarchy.rs index 1f55ed5833..205aee115b 100644 --- a/pallets/delegation/src/delegation_hierarchy.rs +++ b/pallets/delegation/src/delegation_hierarchy.rs @@ -19,7 +19,7 @@ use bitflags::bitflags; use codec::{Decode, Encode}; use ctype::CtypeHashOf; -use sp_std::collections::btree_set::BTreeSet; +use frame_support::{dispatch::DispatchResult, storage::bounded_btree_set::BoundedBTreeSet}; use crate::*; @@ -59,14 +59,14 @@ impl Default for Permissions { /// For quicker lookups of the hierarchy details, all nodes maintain a direct /// link to the hierarchy root node. Furthermore, all nodes have a parent except /// the root nodes, which point to themselves for the hierarchy root node link. -#[derive(Clone, Debug, Encode, Decode, PartialEq)] +#[derive(Clone, Encode, Decode, PartialEq)] pub struct DelegationNode { /// The ID of the delegation hierarchy the node is part of. pub hierarchy_root_id: DelegationNodeIdOf, /// The ID of the parent. For all but root nodes this is not None. pub parent: Option>, /// The set of IDs of all the children nodes. - pub children: BTreeSet>, + pub children: BoundedBTreeSet, T::MaxChildren>, /// The additional information attached to the delegation node. pub details: DelegationDetails, } @@ -78,7 +78,7 @@ impl DelegationNode { Self { hierarchy_root_id: id, parent: None, - children: BTreeSet::new(), + children: BoundedBTreeSet::, T::MaxChildren>::new(), details, } } @@ -93,14 +93,17 @@ impl DelegationNode { Self { hierarchy_root_id, parent: Some(parent), - children: BTreeSet::new(), + children: BoundedBTreeSet::, T::MaxChildren>::new(), details, } } /// Adds a node by its ID to the current node's children. - pub fn add_child(&mut self, child_id: DelegationNodeIdOf) { - self.children.insert(child_id); + pub fn try_add_child(&mut self, child_id: DelegationNodeIdOf) -> DispatchResult { + self.children + .try_insert(child_id) + .map_err(|_| Error::::MaxChildrenExceeded)?; + Ok(()) } } diff --git a/pallets/delegation/src/lib.rs b/pallets/delegation/src/lib.rs index ce3229ac82..dcb28f7442 100644 --- a/pallets/delegation/src/lib.rs +++ b/pallets/delegation/src/lib.rs @@ -90,7 +90,7 @@ mod deprecated; pub use crate::{default_weights::WeightInfo, delegation_hierarchy::*, pallet::*}; -use frame_support::{ensure, pallet_prelude::Weight, traits::Get}; +use frame_support::{dispatch::DispatchResult, ensure, pallet_prelude::Weight, traits::Get}; use sp_runtime::{traits::Hash, DispatchError}; use sp_std::vec::Vec; @@ -132,10 +132,21 @@ pub mod pallet { type Event: From> + IsType<::Event>; #[pallet::constant] type MaxSignatureByteLength: Get; + + /// Maximum number of revocations. #[pallet::constant] type MaxRevocations: Get; + + /// Maximum number of upwards traversals of the delegation tree from a + /// node to the root and thus the depth of the delegation tree. #[pallet::constant] type MaxParentChecks: Get; + + /// Maximum number of all children for a delegation node. For a binary + /// tree, this should be twice the maximum depth of the tree, i.e. + /// `2 ^ MaxParentChecks`. + #[pallet::constant] + type MaxChildren: Get + Clone; type WeightInfo: WeightInfo; } @@ -244,6 +255,9 @@ pub mod pallet { MaxParentChecksTooLarge, /// An error that is not supposed to take place, yet it happened. InternalError, + /// The max number of all children has been reached for the + /// corresponding delegation node. + MaxChildrenExceeded, } #[pallet::call] @@ -378,7 +392,7 @@ pub mod pallet { ), parent_id, parent_node, - ); + )?; Self::deposit_event(Event::DelegationCreated( delegator, @@ -398,7 +412,7 @@ pub mod pallet { /// Revoking a delegation node results in the trust hierarchy starting /// from the given node being revoked. Nevertheless, revocation starts /// from the leave nodes upwards, so if the operation ends prematurely - /// because it runs out of gas, the delegation state would be consisent + /// because it runs out of gas, the delegation state would be consistent /// as no child would "survive" its parent. As a consequence, if the /// given node is revoked, the trust hierarchy with the node as root is /// to be considered revoked. @@ -505,11 +519,12 @@ impl Pallet { delegation_node: DelegationNode, parent_id: DelegationNodeIdOf, mut parent_node: DelegationNode, - ) { + ) -> DispatchResult { >::insert(delegation_id, delegation_node); // Add the new node as a child of that node - parent_node.add_child(delegation_id); + parent_node.try_add_child(delegation_id)?; >::insert(parent_id, parent_node); + Ok(()) } /// Check if an identity is the owner of the given delegation node or any diff --git a/pallets/delegation/src/migrations/v1.rs b/pallets/delegation/src/migrations/v1.rs index f69a115ec7..506bf27b00 100644 --- a/pallets/delegation/src/migrations/v1.rs +++ b/pallets/delegation/src/migrations/v1.rs @@ -18,9 +18,12 @@ use crate::*; -use frame_support::{IterableStorageMap, StorageMap, StoragePrefixedMap}; +use frame_support::{storage::bounded_btree_set::BoundedBTreeSet, IterableStorageMap, StorageMap, StoragePrefixedMap}; use sp_runtime::traits::Zero; -use sp_std::collections::btree_map::BTreeMap; +use sp_std::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + convert::TryFrom, +}; /// Checks whether the deployed storage version is v1. If not, it won't try /// migrate any data. @@ -97,7 +100,9 @@ fn migrate_roots(new_nodes: &mut BTreeMap, Dele // later, when we know we have seen all the children already. let mut new_root_node = DelegationNode::new_root_node(old_root_id, new_root_details); if let Some(root_children_ids) = deprecated::v1::storage::Children::::take(old_root_id) { - new_root_node.children = root_children_ids.iter().copied().collect(); + let children_set: BTreeSet> = root_children_ids.iter().copied().collect(); + new_root_node.children = + BoundedBTreeSet::try_from(children_set).expect("Should not exceed MaxChildren"); } // Add Children::take() weight total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); @@ -161,7 +166,8 @@ fn migrate_nodes( let new_node_parent_id = old_node.parent.unwrap_or(old_node.root_id); let mut new_node = DelegationNode::new_node(old_node.root_id, new_node_parent_id, new_node_details); if let Some(children_ids) = deprecated::v1::storage::Children::::take(old_node_id) { - new_node.children = children_ids.iter().copied().collect(); + let children_set: BTreeSet> = children_ids.iter().copied().collect(); + new_node.children = BoundedBTreeSet::try_from(children_set).expect("Should not exceed MaxChildren"); } // Add Children::take() weight total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); diff --git a/pallets/delegation/src/mock.rs b/pallets/delegation/src/mock.rs index 4c8b77baf9..bf0154b5ac 100644 --- a/pallets/delegation/src/mock.rs +++ b/pallets/delegation/src/mock.rs @@ -19,7 +19,7 @@ #![allow(clippy::from_over_into)] use codec::Decode; -use frame_support::{parameter_types, weights::constants::RocksDbWeight}; +use frame_support::{parameter_types, storage::bounded_btree_set::BoundedBTreeSet, weights::constants::RocksDbWeight}; use frame_system::EnsureSigned; use sp_core::{ed25519, sr25519, Pair}; use sp_keystore::{testing::KeyStore, KeystoreExt}; @@ -28,7 +28,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, MultiSignature, MultiSigner, }; -use sp_std::{collections::btree_set::BTreeSet, sync::Arc}; +use sp_std::sync::Arc; #[cfg(test)] use codec::Encode; @@ -101,6 +101,8 @@ parameter_types! { pub const MaxSignatureByteLength: u16 = 64; pub const MaxParentChecks: u32 = 5; pub const MaxRevocations: u32 = 5; + #[derive(Clone)] + pub const MaxChildren: u32 = 1000; } impl Config for Test { @@ -112,6 +114,7 @@ impl Config for Test { type MaxSignatureByteLength = MaxSignatureByteLength; type MaxParentChecks = MaxParentChecks; type MaxRevocations = MaxRevocations; + type MaxChildren = MaxChildren; type WeightInfo = (); } @@ -228,7 +231,7 @@ pub fn generate_base_delegation_node( ) -> DelegationNode { DelegationNode { details: generate_base_delegation_details(owner), - children: BTreeSet::new(), + children: BoundedBTreeSet::new(), hierarchy_root_id: hierarchy_id, parent, } @@ -390,7 +393,8 @@ impl ExtBuilder { del.1.clone(), parent_node_id, parent_node, - ); + ) + .expect("Should not exceed max children"); }) }); } diff --git a/pallets/did/src/benchmarking.rs b/pallets/did/src/benchmarking.rs index b5e8c1b79d..665c4324dc 100644 --- a/pallets/did/src/benchmarking.rs +++ b/pallets/did/src/benchmarking.rs @@ -18,22 +18,27 @@ use codec::Encode; use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite}; +use frame_support::assert_ok; use frame_system::RawOrigin; -use kilt_primitives::{AccountId, Hash}; +use kilt_primitives::AccountId; use sp_core::{crypto::KeyTypeId, ecdsa, ed25519, sr25519}; use sp_io::crypto::{ecdsa_generate, ecdsa_sign, ed25519_generate, ed25519_sign, sr25519_generate, sr25519_sign}; use sp_runtime::{traits::IdentifyAccount, MultiSigner, SaturatedConversion}; -use sp_std::{collections::btree_set::BTreeSet, convert::TryInto, vec}; -use crate::*; -use did_details::*; +use crate::{ + did_details::*, + mock_utils::{ + generate_base_did_creation_details, generate_base_did_details, generate_base_did_update_details, + get_key_agreement_keys, get_public_keys, get_service_endpoints, DEFAULT_URL_SCHEME, + }, + *, +}; const DEFAULT_ACCOUNT_ID: &str = "tx_submitter"; const DEFAULT_ACCOUNT_SEED: u32 = 0; const AUTHENTICATION_KEY_ID: KeyTypeId = KeyTypeId(*b"0000"); const ATTESTATION_KEY_ID: KeyTypeId = KeyTypeId(*b"0001"); const DELEGATION_KEY_ID: KeyTypeId = KeyTypeId(*b"0002"); -const DEFAULT_URL_SCHEME: [u8; 8] = *b"https://"; fn get_ed25519_public_authentication_key() -> ed25519::Public { ed25519_generate(AUTHENTICATION_KEY_ID, None) @@ -47,35 +52,6 @@ fn get_ecdsa_public_authentication_key() -> ecdsa::Public { ecdsa_generate(AUTHENTICATION_KEY_ID, None) } -fn get_key_agreement_keys(n_keys: u32) -> BTreeSet { - (1..=n_keys) - .map(|i| { - // Converts the loop index to a 32-byte array; - let mut seed_vec = i.to_be_bytes().to_vec(); - seed_vec.resize(32, 0u8); - let seed: [u8; 32] = seed_vec - .try_into() - .expect("Failed to create encryption key from raw seed."); - DidEncryptionKey::X25519(seed) - }) - .collect::>() -} - -fn get_public_keys(n_keys: u32) -> BTreeSet> { - (1..=n_keys) - .map(|i| { - // Converts the loop index to a 32-byte array; - let mut seed_vec = i.to_be_bytes().to_vec(); - seed_vec.resize(32, 0u8); - let seed: [u8; 32] = seed_vec - .try_into() - .expect("Failed to create encryption key from raw seed."); - let key = DidEncryptionKey::X25519(seed); - utils::calculate_key_id::(&key.into()) - }) - .collect::>>() -} - fn get_ed25519_public_attestation_key() -> ed25519::Public { ed25519_generate(ATTESTATION_KEY_ID, None) } @@ -100,48 +76,6 @@ fn get_ecdsa_public_delegation_key() -> ecdsa::Public { ecdsa_generate(DELEGATION_KEY_ID, None) } -// Assumes that the length of the URL is larger than 8 (length of the prefix https://) -fn get_service_endpoints(count: u32, length: u32) -> ServiceEndpoints { - let total_length = usize::try_from(length).expect("Failed to convert URL max length value to usize value."); - let total_count = usize::try_from(count).expect("Failed to convert max number of URLs value to usize value."); - let mut url_encoded_string = DEFAULT_URL_SCHEME.to_vec(); - url_encoded_string.resize(total_length, b'0'); - let url = Url::Http( - HttpUrl::try_from(url_encoded_string.as_ref()).expect("Failed to create default URL with provided length."), - ); - - ServiceEndpoints { - content_hash: Hash::default(), - urls: vec![url; total_count], - content_type: ContentType::ApplicationJson, - } -} - -fn get_did_base_details(auth_key: DidVerificationKey) -> DidDetails { - DidDetails::new(auth_key, BlockNumberOf::::default()) -} - -fn generate_base_did_creation_details(did: DidIdentifierOf) -> DidCreationDetails { - DidCreationDetails { - did, - new_key_agreement_keys: BTreeSet::new(), - new_attestation_key: None, - new_delegation_key: None, - new_service_endpoints: None, - } -} - -fn generate_base_did_update_details(_did: DidIdentifierOf) -> DidUpdateDetails { - DidUpdateDetails { - new_authentication_key: None, - new_key_agreement_keys: BTreeSet::new(), - attestation_key_update: DidFragmentUpdateAction::default(), - delegation_key_update: DidFragmentUpdateAction::default(), - service_endpoints_update: DidFragmentUpdateAction::default(), - public_keys_to_remove: BTreeSet::new(), - } -} - // Must always be dispatched with the DID authentication key fn generate_base_did_call_operation(did: DidIdentifierOf) -> DidAuthorizedCallOperation { let test_call = ::Call::get_call_for_did_call_benchmark(); @@ -171,10 +105,10 @@ benchmarks! { let did_public_auth_key = get_ed25519_public_authentication_key(); let did_subject: DidIdentifierOf = MultiSigner::from(did_public_auth_key).into_account().into(); - let did_key_agreement_keys = get_key_agreement_keys(n); + let did_key_agreement_keys = get_key_agreement_keys::(n); let did_public_att_key = get_ed25519_public_attestation_key(); let did_public_del_key = get_ed25519_public_delegation_key(); - let service_endpoints = get_service_endpoints(c, u); + let service_endpoints = get_service_endpoints::(c, u); let mut did_creation_details = generate_base_did_creation_details::(did_subject.clone()); did_creation_details.new_key_agreement_keys = did_key_agreement_keys; @@ -221,10 +155,10 @@ benchmarks! { let did_public_auth_key = get_sr25519_public_authentication_key(); let did_subject: DidIdentifierOf = MultiSigner::from(did_public_auth_key).into_account().into(); - let did_key_agreement_keys = get_key_agreement_keys(n); + let did_key_agreement_keys = get_key_agreement_keys::(n); let did_public_att_key = get_sr25519_public_attestation_key(); let did_public_del_key = get_sr25519_public_delegation_key(); - let service_endpoints = get_service_endpoints(c, u); + let service_endpoints = get_service_endpoints::(c, u); let mut did_creation_details = generate_base_did_creation_details::(did_subject.clone()); did_creation_details.new_key_agreement_keys = did_key_agreement_keys; @@ -271,10 +205,10 @@ benchmarks! { let did_public_auth_key = get_ecdsa_public_authentication_key(); let did_subject: DidIdentifierOf = MultiSigner::from(did_public_auth_key.clone()).into_account().into(); - let did_key_agreement_keys = get_key_agreement_keys(n); + let did_key_agreement_keys = get_key_agreement_keys::(n); let did_public_att_key = get_ecdsa_public_attestation_key(); let did_public_del_key = get_ecdsa_public_delegation_key(); - let service_endpoints = get_service_endpoints(c, u); + let service_endpoints = get_service_endpoints::(c, u); let mut did_creation_details = generate_base_did_creation_details::(did_subject.clone()); did_creation_details.new_key_agreement_keys = did_key_agreement_keys; @@ -320,22 +254,22 @@ benchmarks! { let did_public_auth_key = get_ed25519_public_authentication_key(); let did_subject: DidIdentifierOf = MultiSigner::from(did_public_auth_key).into_account().into(); - // To cover cases in which m > n without failing, we add m + n keys to the set of keys before the update operation - let did_key_agreement_keys = get_key_agreement_keys(m + n); + // To cover cases in which m > n without failing, we add max(n, m) keys to the set of keys before the update operation + let did_key_agreement_keys = get_key_agreement_keys::(n.max(m)); - let mut did_details = get_did_base_details(DidVerificationKey::from(did_public_auth_key)); - did_details.add_key_agreement_keys(did_key_agreement_keys, BlockNumberOf::::default()); + let mut did_details = generate_base_did_details::(DidVerificationKey::from(did_public_auth_key)); + assert_ok!(did_details.add_key_agreement_keys(did_key_agreement_keys, BlockNumberOf::::default())); Did::::insert(&did_subject, did_details); let new_did_public_auth_key = get_ed25519_public_authentication_key(); - let new_key_agreement_keys = get_key_agreement_keys(n); + let new_key_agreement_keys = get_key_agreement_keys::(n); let new_did_public_att_key = get_ed25519_public_attestation_key(); let new_did_public_del_key = get_ed25519_public_delegation_key(); // Public keys obtained are generated using the same logic as the key agreement keys, so that we are sure they do not generate KeyNotPresent errors let public_keys_to_remove = get_public_keys::(m); - let service_endpoints = get_service_endpoints(c, u); + let service_endpoints = get_service_endpoints::(c, u); - let mut did_update_details = generate_base_did_update_details::(did_subject.clone()); + let mut did_update_details = generate_base_did_update_details::(); did_update_details.new_authentication_key = Some(DidVerificationKey::from(new_did_public_auth_key)); did_update_details.new_key_agreement_keys = new_key_agreement_keys; did_update_details.attestation_key_update = DidFragmentUpdateAction::Change(DidVerificationKey::from(new_did_public_att_key)); @@ -382,22 +316,22 @@ benchmarks! { let did_public_auth_key = get_sr25519_public_authentication_key(); let did_subject: DidIdentifierOf = MultiSigner::from(did_public_auth_key).into_account().into(); - // To cover cases in which m > n without failing, we add m + n keys to the set of keys before the update operation - let did_key_agreement_keys = get_key_agreement_keys(m + n); + // To cover cases in which m > n without failing, we add max(n, m) keys to the set of keys before the update operation + let did_key_agreement_keys = get_key_agreement_keys::(n.max(m)); - let mut did_details = get_did_base_details(DidVerificationKey::from(did_public_auth_key)); - did_details.add_key_agreement_keys(did_key_agreement_keys, BlockNumberOf::::default()); + let mut did_details = generate_base_did_details::(DidVerificationKey::from(did_public_auth_key)); + assert_ok!(did_details.add_key_agreement_keys(did_key_agreement_keys, BlockNumberOf::::default())); Did::::insert(&did_subject, did_details); let new_did_public_auth_key = get_sr25519_public_authentication_key(); - let new_key_agreement_keys = get_key_agreement_keys(n); + let new_key_agreement_keys = get_key_agreement_keys::(n); let new_did_public_att_key = get_sr25519_public_attestation_key(); let new_did_public_del_key = get_sr25519_public_delegation_key(); // Public keys obtained are generated using the same logic as the key agreement keys, so that we are sure they do not generate KeyNotPresent errors let public_keys_to_remove = get_public_keys::(m); - let service_endpoints = get_service_endpoints(c, u); + let service_endpoints = get_service_endpoints::(c, u); - let mut did_update_details = generate_base_did_update_details::(did_subject.clone()); + let mut did_update_details = generate_base_did_update_details::(); did_update_details.new_authentication_key = Some(DidVerificationKey::from(new_did_public_auth_key)); did_update_details.new_key_agreement_keys = new_key_agreement_keys; did_update_details.attestation_key_update = DidFragmentUpdateAction::Change(DidVerificationKey::from(new_did_public_att_key)); @@ -444,22 +378,22 @@ benchmarks! { let did_public_auth_key = get_ecdsa_public_authentication_key(); let did_subject: DidIdentifierOf = MultiSigner::from(did_public_auth_key.clone()).into_account().into(); - // To cover cases in which m > n without failing, we add m + n keys to the set of keys before the update operation - let did_key_agreement_keys = get_key_agreement_keys(m + n); + // To cover cases in which m > n without failing, we add max(n, m) keys to the set of keys before the update operation + let did_key_agreement_keys = get_key_agreement_keys::(n.max(m)); - let mut did_details = get_did_base_details(DidVerificationKey::from(did_public_auth_key.clone())); - did_details.add_key_agreement_keys(did_key_agreement_keys, BlockNumberOf::::default()); + let mut did_details = generate_base_did_details::(DidVerificationKey::from(did_public_auth_key.clone())); + assert_ok!(did_details.add_key_agreement_keys(did_key_agreement_keys, BlockNumberOf::::default())); Did::::insert(&did_subject, did_details); let new_did_public_auth_key = get_ecdsa_public_authentication_key(); - let new_key_agreement_keys = get_key_agreement_keys(n); + let new_key_agreement_keys = get_key_agreement_keys::(n); let new_did_public_att_key = get_ecdsa_public_attestation_key(); let new_did_public_del_key = get_ecdsa_public_delegation_key(); // Public keys obtained are generated using the same logic as the key agreement keys, so that we are sure they do not generate KeyNotPresent errors let public_keys_to_remove = get_public_keys::(m); - let service_endpoints = get_service_endpoints(c, u); + let service_endpoints = get_service_endpoints::(c, u); - let mut did_update_details = generate_base_did_update_details::(did_subject.clone()); + let mut did_update_details = generate_base_did_update_details::(); did_update_details.new_authentication_key = Some(DidVerificationKey::from(new_did_public_auth_key.clone())); did_update_details.new_key_agreement_keys = new_key_agreement_keys; did_update_details.attestation_key_update = DidFragmentUpdateAction::Change(DidVerificationKey::from(new_did_public_att_key.clone())); @@ -500,13 +434,12 @@ benchmarks! { let did_public_auth_key = get_ed25519_public_authentication_key(); let did_subject: DidIdentifierOf = MultiSigner::from(did_public_auth_key).into_account().into(); - let did_details = get_did_base_details(DidVerificationKey::from(did_public_auth_key)); + let did_details = generate_base_did_details::(DidVerificationKey::from(did_public_auth_key)); Did::::insert(&did_subject, did_details); }: _(RawOrigin::Signed(did_subject.clone())) verify { - assert_eq!( - Did::::get(&did_subject), - None + assert!( + Did::::get(&did_subject).is_none() ); } @@ -516,7 +449,7 @@ benchmarks! { let did_public_auth_key = get_ed25519_public_authentication_key(); let did_subject: DidIdentifierOf = MultiSigner::from(did_public_auth_key).into_account().into(); - let did_details = get_did_base_details(DidVerificationKey::from(did_public_auth_key)); + let did_details = generate_base_did_details::(DidVerificationKey::from(did_public_auth_key)); Did::::insert(&did_subject, did_details); let did_call_op = generate_base_did_call_operation::(did_subject); @@ -530,7 +463,7 @@ benchmarks! { let did_public_auth_key = get_sr25519_public_authentication_key(); let did_subject: DidIdentifierOf = MultiSigner::from(did_public_auth_key).into_account().into(); - let did_details = get_did_base_details(DidVerificationKey::from(did_public_auth_key)); + let did_details = generate_base_did_details::(DidVerificationKey::from(did_public_auth_key)); Did::::insert(&did_subject, did_details); let did_call_op = generate_base_did_call_operation::(did_subject); @@ -544,7 +477,7 @@ benchmarks! { let did_public_auth_key = get_ecdsa_public_authentication_key(); let did_subject: DidIdentifierOf = MultiSigner::from(did_public_auth_key.clone()).into_account().into(); - let did_details = get_did_base_details(DidVerificationKey::from(did_public_auth_key.clone())); + let did_details = generate_base_did_details::(DidVerificationKey::from(did_public_auth_key.clone())); Did::::insert(&did_subject, did_details); let did_call_op = generate_base_did_call_operation::(did_subject); diff --git a/pallets/did/src/default_weights.rs b/pallets/did/src/default_weights.rs index 1a5def914a..b4621e3a3f 100644 --- a/pallets/did/src/default_weights.rs +++ b/pallets/did/src/default_weights.rs @@ -19,24 +19,22 @@ //! Autogenerated weights for did //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-08-05, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! DATE: 2021-08-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// target/release/kilt-parachain +// /home/willi/mashnet-node/target/release/kilt-parachain // benchmark // --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=did +// --extrinsic=* // --execution=wasm -// --wasm-execution=Compiled +// --wasm-execution=compiled // --heap-pages=4096 -// --extrinsic=* -// --pallet=did -// --steps=1 -// --repeat=20 -// --template -// .maintain/weight-template.hbs -// --output -// pallets/did/src/default_weights.rs +// --output=../../pallets/did/src/default_weights.rs +// --template=../../.maintain/weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -64,92 +62,90 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn create_ed25519_keys(n: u32, u: u32, c: u32, ) -> Weight { - (71_462_000_u64) - // Standard Error: 105_000 - .saturating_add((2_176_000_u64).saturating_mul(n as Weight)) - // Standard Error: 4_000 - .saturating_add((19_000_u64).saturating_mul(u as Weight)) - // Standard Error: 475_000 - .saturating_add((2_897_000_u64).saturating_mul(c as Weight)) + (117_551_000_u64) + // Standard Error: 127_000 + .saturating_add((2_529_000_u64).saturating_mul(n as Weight)) + // Standard Error: 3_000 + .saturating_add((10_000_u64).saturating_mul(u as Weight)) + // Standard Error: 864_000 + .saturating_add((4_008_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn create_sr25519_keys(n: u32, u: u32, c: u32, ) -> Weight { - (80_034_000_u64) - // Standard Error: 111_000 - .saturating_add((1_580_000_u64).saturating_mul(n as Weight)) - // Standard Error: 5_000 - .saturating_add((20_000_u64).saturating_mul(u as Weight)) - // Standard Error: 502_000 - .saturating_add((1_458_000_u64).saturating_mul(c as Weight)) + (125_047_000_u64) + // Standard Error: 113_000 + .saturating_add((2_679_000_u64).saturating_mul(n as Weight)) + // Standard Error: 3_000 + .saturating_add((16_000_u64).saturating_mul(u as Weight)) + // Standard Error: 768_000 + .saturating_add((1_611_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn create_ecdsa_keys(n: u32, u: u32, c: u32, ) -> Weight { - (163_338_000_u64) - // Standard Error: 70_000 - .saturating_add((2_028_000_u64).saturating_mul(n as Weight)) - // Standard Error: 3_000 - .saturating_add((22_000_u64).saturating_mul(u as Weight)) - // Standard Error: 315_000 - .saturating_add((3_977_000_u64).saturating_mul(c as Weight)) + (246_173_000_u64) + // Standard Error: 149_000 + .saturating_add((2_627_000_u64).saturating_mul(n as Weight)) + // Standard Error: 4_000 + .saturating_add((9_000_u64).saturating_mul(u as Weight)) + // Standard Error: 1_018_000 + .saturating_add((1_635_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - fn update_ed25519_keys(n: u32, m: u32, u: u32, c: u32, ) -> Weight { - (19_548_000_u64) - // Standard Error: 30_000 - .saturating_add((2_735_000_u64).saturating_mul(n as Weight)) - // Standard Error: 30_000 - .saturating_add((1_923_000_u64).saturating_mul(m as Weight)) - // Standard Error: 1_000 - .saturating_add((8_000_u64).saturating_mul(u as Weight)) - // Standard Error: 138_000 - .saturating_add((1_276_000_u64).saturating_mul(c as Weight)) + fn update_ed25519_keys(n: u32, m: u32, _u: u32, _c: u32, ) -> Weight { + (68_329_000_u64) + // Standard Error: 134_000 + .saturating_add((2_474_000_u64).saturating_mul(n as Weight)) + // Standard Error: 134_000 + .saturating_add((591_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - fn update_sr25519_keys(n: u32, m: u32, _u: u32, c: u32, ) -> Weight { - (22_526_000_u64) - // Standard Error: 73_000 - .saturating_add((3_146_000_u64).saturating_mul(n as Weight)) - // Standard Error: 73_000 - .saturating_add((2_083_000_u64).saturating_mul(m as Weight)) - // Standard Error: 331_000 - .saturating_add((1_177_000_u64).saturating_mul(c as Weight)) + fn update_sr25519_keys(n: u32, m: u32, u: u32, c: u32, ) -> Weight { + (58_837_000_u64) + // Standard Error: 63_000 + .saturating_add((2_426_000_u64).saturating_mul(n as Weight)) + // Standard Error: 63_000 + .saturating_add((789_000_u64).saturating_mul(m as Weight)) + // Standard Error: 1_000 + .saturating_add((10_000_u64).saturating_mul(u as Weight)) + // Standard Error: 434_000 + .saturating_add((1_470_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn update_ecdsa_keys(n: u32, m: u32, u: u32, c: u32, ) -> Weight { - (22_988_000_u64) - // Standard Error: 14_000 - .saturating_add((2_823_000_u64).saturating_mul(n as Weight)) - // Standard Error: 14_000 - .saturating_add((1_793_000_u64).saturating_mul(m as Weight)) - // Standard Error: 0 - .saturating_add((4_000_u64).saturating_mul(u as Weight)) - // Standard Error: 64_000 - .saturating_add((319_000_u64).saturating_mul(c as Weight)) + (60_018_000_u64) + // Standard Error: 59_000 + .saturating_add((2_580_000_u64).saturating_mul(n as Weight)) + // Standard Error: 59_000 + .saturating_add((822_000_u64).saturating_mul(m as Weight)) + // Standard Error: 1_000 + .saturating_add((12_000_u64).saturating_mul(u as Weight)) + // Standard Error: 407_000 + .saturating_add((436_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn delete() -> Weight { - (17_904_000_u64) + (36_719_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn submit_did_call_ed25519_key() -> Weight { - (67_156_000_u64) + (117_740_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn submit_did_call_sr25519_key() -> Weight { - (70_993_000_u64) + (116_287_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn submit_did_call_ecdsa_key() -> Weight { - (170_751_000_u64) + (236_162_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -158,92 +154,90 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn create_ed25519_keys(n: u32, u: u32, c: u32, ) -> Weight { - (71_462_000_u64) - // Standard Error: 105_000 - .saturating_add((2_176_000_u64).saturating_mul(n as Weight)) - // Standard Error: 4_000 - .saturating_add((19_000_u64).saturating_mul(u as Weight)) - // Standard Error: 475_000 - .saturating_add((2_897_000_u64).saturating_mul(c as Weight)) + (117_551_000_u64) + // Standard Error: 127_000 + .saturating_add((2_529_000_u64).saturating_mul(n as Weight)) + // Standard Error: 3_000 + .saturating_add((10_000_u64).saturating_mul(u as Weight)) + // Standard Error: 864_000 + .saturating_add((4_008_000_u64).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn create_sr25519_keys(n: u32, u: u32, c: u32, ) -> Weight { - (80_034_000_u64) - // Standard Error: 111_000 - .saturating_add((1_580_000_u64).saturating_mul(n as Weight)) - // Standard Error: 5_000 - .saturating_add((20_000_u64).saturating_mul(u as Weight)) - // Standard Error: 502_000 - .saturating_add((1_458_000_u64).saturating_mul(c as Weight)) + (125_047_000_u64) + // Standard Error: 113_000 + .saturating_add((2_679_000_u64).saturating_mul(n as Weight)) + // Standard Error: 3_000 + .saturating_add((16_000_u64).saturating_mul(u as Weight)) + // Standard Error: 768_000 + .saturating_add((1_611_000_u64).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn create_ecdsa_keys(n: u32, u: u32, c: u32, ) -> Weight { - (163_338_000_u64) - // Standard Error: 70_000 - .saturating_add((2_028_000_u64).saturating_mul(n as Weight)) - // Standard Error: 3_000 - .saturating_add((22_000_u64).saturating_mul(u as Weight)) - // Standard Error: 315_000 - .saturating_add((3_977_000_u64).saturating_mul(c as Weight)) + (246_173_000_u64) + // Standard Error: 149_000 + .saturating_add((2_627_000_u64).saturating_mul(n as Weight)) + // Standard Error: 4_000 + .saturating_add((9_000_u64).saturating_mul(u as Weight)) + // Standard Error: 1_018_000 + .saturating_add((1_635_000_u64).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - fn update_ed25519_keys(n: u32, m: u32, u: u32, c: u32, ) -> Weight { - (19_548_000_u64) - // Standard Error: 30_000 - .saturating_add((2_735_000_u64).saturating_mul(n as Weight)) - // Standard Error: 30_000 - .saturating_add((1_923_000_u64).saturating_mul(m as Weight)) - // Standard Error: 1_000 - .saturating_add((8_000_u64).saturating_mul(u as Weight)) - // Standard Error: 138_000 - .saturating_add((1_276_000_u64).saturating_mul(c as Weight)) + fn update_ed25519_keys(n: u32, m: u32, _u: u32, _c: u32, ) -> Weight { + (68_329_000_u64) + // Standard Error: 134_000 + .saturating_add((2_474_000_u64).saturating_mul(n as Weight)) + // Standard Error: 134_000 + .saturating_add((591_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - fn update_sr25519_keys(n: u32, m: u32, _u: u32, c: u32, ) -> Weight { - (22_526_000_u64) - // Standard Error: 73_000 - .saturating_add((3_146_000_u64).saturating_mul(n as Weight)) - // Standard Error: 73_000 - .saturating_add((2_083_000_u64).saturating_mul(m as Weight)) - // Standard Error: 331_000 - .saturating_add((1_177_000_u64).saturating_mul(c as Weight)) + fn update_sr25519_keys(n: u32, m: u32, u: u32, c: u32, ) -> Weight { + (58_837_000_u64) + // Standard Error: 63_000 + .saturating_add((2_426_000_u64).saturating_mul(n as Weight)) + // Standard Error: 63_000 + .saturating_add((789_000_u64).saturating_mul(m as Weight)) + // Standard Error: 1_000 + .saturating_add((10_000_u64).saturating_mul(u as Weight)) + // Standard Error: 434_000 + .saturating_add((1_470_000_u64).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn update_ecdsa_keys(n: u32, m: u32, u: u32, c: u32, ) -> Weight { - (22_988_000_u64) - // Standard Error: 14_000 - .saturating_add((2_823_000_u64).saturating_mul(n as Weight)) - // Standard Error: 14_000 - .saturating_add((1_793_000_u64).saturating_mul(m as Weight)) - // Standard Error: 0 - .saturating_add((4_000_u64).saturating_mul(u as Weight)) - // Standard Error: 64_000 - .saturating_add((319_000_u64).saturating_mul(c as Weight)) + (60_018_000_u64) + // Standard Error: 59_000 + .saturating_add((2_580_000_u64).saturating_mul(n as Weight)) + // Standard Error: 59_000 + .saturating_add((822_000_u64).saturating_mul(m as Weight)) + // Standard Error: 1_000 + .saturating_add((12_000_u64).saturating_mul(u as Weight)) + // Standard Error: 407_000 + .saturating_add((436_000_u64).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn delete() -> Weight { - (17_904_000_u64) + (36_719_000_u64) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn submit_did_call_ed25519_key() -> Weight { - (67_156_000_u64) + (117_740_000_u64) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn submit_did_call_sr25519_key() -> Weight { - (70_993_000_u64) + (116_287_000_u64) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn submit_did_call_ecdsa_key() -> Weight { - (170_751_000_u64) + (236_162_000_u64) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } diff --git a/pallets/did/src/deprecated.rs b/pallets/did/src/deprecated.rs index c5330c605e..b51d07fb3d 100644 --- a/pallets/did/src/deprecated.rs +++ b/pallets/did/src/deprecated.rs @@ -18,37 +18,38 @@ pub(crate) mod v1 { use codec::{Decode, Encode}; - use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; use crate::*; /// The details associated to a DID identity. - #[derive(Clone, Debug, Decode, Encode, PartialEq)] + #[derive(Clone, Decode, Encode, PartialEq)] pub struct DidDetails { pub(crate) authentication_key: KeyIdOf, - pub(crate) key_agreement_keys: BTreeSet>, + pub(crate) key_agreement_keys: DidKeyAgreementKeys, pub(crate) delegation_key: Option>, pub(crate) attestation_key: Option>, - pub(crate) public_keys: BTreeMap, DidPublicKeyDetails>, - pub(crate) endpoint_url: Option, + pub(crate) public_keys: DidPublicKeyMap, + pub(crate) endpoint_url: Option>, pub(crate) last_tx_counter: u64, } #[cfg(test)] impl DidDetails { pub(crate) fn new(authentication_key: DidVerificationKey, block_number: BlockNumberOf) -> Self { - let mut public_keys: BTreeMap, DidPublicKeyDetails> = BTreeMap::new(); + let mut public_keys = DidPublicKeyMap::::default(); let authentication_key_id = utils::calculate_key_id::(&authentication_key.clone().into()); - public_keys.insert( - authentication_key_id, - DidPublicKeyDetails { - key: authentication_key.into(), - block_number, - }, - ); + public_keys + .try_insert( + authentication_key_id, + DidPublicKeyDetails { + key: authentication_key.into(), + block_number, + }, + ) + .expect("Should not exceed BoundedBTreeMap bounds when setting public keys"); Self { authentication_key: authentication_key_id, - key_agreement_keys: BTreeSet::new(), + key_agreement_keys: DidKeyAgreementKeys::::default(), attestation_key: None, delegation_key: None, endpoint_url: None, diff --git a/pallets/did/src/did_details.rs b/pallets/did/src/did_details.rs index 127f670b2d..995ca0ad14 100644 --- a/pallets/did/src/did_details.rs +++ b/pallets/did/src/did_details.rs @@ -17,13 +17,14 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use codec::{Decode, Encode, WrapperTypeEncode}; +use frame_support::{ + storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet}, + BoundedVec, +}; use kilt_primitives::Hash; use sp_core::{ecdsa, ed25519, sr25519}; use sp_runtime::traits::Verify; -use sp_std::{ - collections::{btree_map::BTreeMap, btree_set::BTreeSet}, - convert::TryInto, -}; +use sp_std::{collections::btree_set::BTreeSet, convert::TryInto, fmt}; use crate::*; @@ -223,14 +224,14 @@ pub struct DidPublicKeyDetails { } /// The details associated to a DID identity. -#[derive(Clone, Debug, Decode, Encode, PartialEq)] +#[derive(Clone, Decode, Encode, PartialEq)] pub struct DidDetails { /// The ID of the authentication key, used to authenticate DID-related /// operations. pub(crate) authentication_key: KeyIdOf, /// The set of the key agreement key IDs, which can be used to encrypt /// data addressed to the DID subject. - pub(crate) key_agreement_keys: BTreeSet>, + pub(crate) key_agreement_keys: DidKeyAgreementKeys, /// \[OPTIONAL\] The ID of the delegation key, used to verify the /// signatures of the delegations created by the DID subject. pub(crate) delegation_key: Option>, @@ -246,10 +247,10 @@ pub struct DidDetails { /// the old attestation keys that have been rotated, i.e., they cannot /// be used to create new attestations but can still be used to verify /// previously issued attestations. - pub(crate) public_keys: BTreeMap, DidPublicKeyDetails>, + pub(crate) public_keys: DidPublicKeyMap, /// \[OPTIONAL\] The service endpoint details the DID /// subject publicly exposes. - pub service_endpoints: Option, + pub service_endpoints: Option>, /// The counter used to avoid replay attacks, which is checked and /// updated upon each DID operation involving with the subject as the /// creator. @@ -261,25 +262,27 @@ impl DidDetails { /// i.e., an authentication key and the block creation time. /// /// The tx counter is automatically set to 0. - pub fn new(authentication_key: DidVerificationKey, block_number: BlockNumberOf) -> Self { - let mut public_keys: BTreeMap, DidPublicKeyDetails> = BTreeMap::new(); + pub fn new(authentication_key: DidVerificationKey, block_number: BlockNumberOf) -> Result { + let mut public_keys = DidPublicKeyMap::::default(); let authentication_key_id = utils::calculate_key_id::(&authentication_key.clone().into()); - public_keys.insert( - authentication_key_id, - DidPublicKeyDetails { - key: authentication_key.into(), - block_number, - }, - ); - Self { + public_keys + .try_insert( + authentication_key_id, + DidPublicKeyDetails { + key: authentication_key.into(), + block_number, + }, + ) + .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; + Ok(Self { authentication_key: authentication_key_id, - key_agreement_keys: BTreeSet::new(), + key_agreement_keys: DidKeyAgreementKeys::::default(), attestation_key: None, delegation_key: None, service_endpoints: None, public_keys, last_tx_counter: 0u64, - } + }) } // Creates a new DID entry from some [DidCreationDetails] and a given @@ -287,7 +290,7 @@ impl DidDetails { pub fn from_creation_details( details: DidCreationDetails, new_auth_key: DidVerificationKey, - ) -> Result { + ) -> Result { ensure!( details.new_key_agreement_keys.len() <= <::MaxNewKeyAgreementKeys>::get().saturated_into::(), @@ -295,22 +298,22 @@ impl DidDetails { ); if let Some(ref service_endpoints) = details.new_service_endpoints { - service_endpoints.validate_against_config_limits::()?; + service_endpoints.validate_against_config_limits()?; } let current_block_number = >::block_number(); // Creates a new DID with the given authentication key. - let mut new_did_details = DidDetails::new(new_auth_key, current_block_number); + let mut new_did_details = DidDetails::new(new_auth_key, current_block_number)?; - new_did_details.add_key_agreement_keys(details.new_key_agreement_keys, current_block_number); + new_did_details.add_key_agreement_keys(details.new_key_agreement_keys, current_block_number)?; if let Some(attesation_key) = details.new_attestation_key { - new_did_details.update_attestation_key(attesation_key, current_block_number); + new_did_details.update_attestation_key(attesation_key, current_block_number)?; } if let Some(delegation_key) = details.new_delegation_key { - new_did_details.update_delegation_key(delegation_key, current_block_number); + new_did_details.update_delegation_key(delegation_key, current_block_number)?; } new_did_details.service_endpoints = details.new_service_endpoints; @@ -326,18 +329,18 @@ impl DidDetails { ensure!( update_details.new_key_agreement_keys.len() <= <::MaxNewKeyAgreementKeys>::get().saturated_into::(), - DidError::InputError(InputError::MaxKeyAgreementKeysLimitExceeded) + InputError::MaxKeyAgreementKeysLimitExceeded ); ensure!( update_details.public_keys_to_remove.len() <= <::MaxVerificationKeysToRevoke>::get().saturated_into::(), - DidError::InputError(InputError::MaxVerificationKeysToRemoveLimitExceeded) + InputError::MaxVerificationKeysToRemoveLimitExceeded ); if let DidFragmentUpdateAction::Change(ref service_endpoints) = update_details.service_endpoints_update { service_endpoints - .validate_against_config_limits::() + .validate_against_config_limits() .map_err(DidError::InputError)?; } @@ -349,11 +352,11 @@ impl DidDetails { // Update the authentication key, if needed. if let Some(new_authentication_key) = update_details.new_authentication_key { - self.update_authentication_key(new_authentication_key, current_block_number); + self.update_authentication_key(new_authentication_key, current_block_number)?; } // Add any new key agreement keys. - self.add_key_agreement_keys(update_details.new_key_agreement_keys, current_block_number); + self.add_key_agreement_keys(update_details.new_key_agreement_keys, current_block_number)?; // Update/remove the attestation key, if needed. match update_details.attestation_key_update { @@ -361,7 +364,7 @@ impl DidDetails { self.delete_attestation_key(); } DidFragmentUpdateAction::Change(new_attestation_key) => { - self.update_attestation_key(new_attestation_key, current_block_number); + self.update_attestation_key(new_attestation_key, current_block_number)?; } // Nothing happens. DidFragmentUpdateAction::Ignore => {} @@ -373,7 +376,7 @@ impl DidDetails { self.delete_delegation_key(); } DidFragmentUpdateAction::Change(new_delegation_key) => { - self.update_delegation_key(new_delegation_key, current_block_number); + self.update_delegation_key(new_delegation_key, current_block_number)?; } // Nothing happens. DidFragmentUpdateAction::Ignore => {} @@ -400,7 +403,7 @@ impl DidDetails { &mut self, new_authentication_key: DidVerificationKey, block_number: BlockNumberOf, - ) { + ) -> Result<(), StorageError> { let old_authentication_key_id = self.authentication_key; let new_authentication_key_id = utils::calculate_key_id::(&new_authentication_key.clone().into()); self.authentication_key = new_authentication_key_id; @@ -408,13 +411,16 @@ impl DidDetails { self.remove_key_if_unused(&old_authentication_key_id); // Add new key ID to public keys. If a key with the same ID is already present, // the result is simply that the block number is updated. - self.public_keys.insert( - new_authentication_key_id, - DidPublicKeyDetails { - key: new_authentication_key.into(), - block_number, - }, - ); + self.public_keys + .try_insert( + new_authentication_key_id, + DidPublicKeyDetails { + key: new_authentication_key.into(), + block_number, + }, + ) + .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; + Ok(()) } /// Add new key agreement keys to the DID. @@ -422,20 +428,25 @@ impl DidDetails { /// The new keys are added to the set of verification keys. pub fn add_key_agreement_keys( &mut self, - new_key_agreement_keys: BTreeSet, + new_key_agreement_keys: DidNewKeyAgreementKeys, block_number: BlockNumberOf, - ) { + ) -> Result<(), StorageError> { for new_key_agreement_key in new_key_agreement_keys { let new_key_agreement_id = utils::calculate_key_id::(&new_key_agreement_key.into()); - self.public_keys.insert( - new_key_agreement_id, - DidPublicKeyDetails { - key: new_key_agreement_key.into(), - block_number, - }, - ); - self.key_agreement_keys.insert(new_key_agreement_id); + self.public_keys + .try_insert( + new_key_agreement_id, + DidPublicKeyDetails { + key: new_key_agreement_key.into(), + block_number, + }, + ) + .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; + self.key_agreement_keys + .try_insert(new_key_agreement_id) + .map_err(|_| StorageError::MaxTotalKeyAgreementKeysExceeded)?; } + Ok(()) } /// Update the DID attestation key. @@ -443,16 +454,23 @@ impl DidDetails { /// The old key is not removed from the set of verification keys, hence /// it can still be used to verify past attestations. /// The new key is added to the set of verification keys. - pub fn update_attestation_key(&mut self, new_attestation_key: DidVerificationKey, block_number: BlockNumberOf) { + pub fn update_attestation_key( + &mut self, + new_attestation_key: DidVerificationKey, + block_number: BlockNumberOf, + ) -> Result<(), StorageError> { let new_attestation_key_id = utils::calculate_key_id::(&new_attestation_key.clone().into()); self.attestation_key = Some(new_attestation_key_id); - self.public_keys.insert( - new_attestation_key_id, - DidPublicKeyDetails { - key: new_attestation_key.into(), - block_number, - }, - ); + self.public_keys + .try_insert( + new_attestation_key_id, + DidPublicKeyDetails { + key: new_attestation_key.into(), + block_number, + }, + ) + .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; + Ok(()) } /// Delete the DID attestation key. @@ -469,20 +487,27 @@ impl DidDetails { /// The old key is deleted from the set of verification keys if it is /// not used in any other part of the DID. The new key is added to the /// set of verification keys. - pub fn update_delegation_key(&mut self, new_delegation_key: DidVerificationKey, block_number: BlockNumberOf) { + pub fn update_delegation_key( + &mut self, + new_delegation_key: DidVerificationKey, + block_number: BlockNumberOf, + ) -> Result<(), StorageError> { let old_delegation_key_id = self.delegation_key; let new_delegation_key_id = utils::calculate_key_id::(&new_delegation_key.clone().into()); self.delegation_key = Some(new_delegation_key_id); if let Some(old_delegation_key) = old_delegation_key_id { self.remove_key_if_unused(&old_delegation_key); } - self.public_keys.insert( - new_delegation_key_id, - DidPublicKeyDetails { - key: new_delegation_key.into(), - block_number, - }, - ); + self.public_keys + .try_insert( + new_delegation_key_id, + DidPublicKeyDetails { + key: new_delegation_key.into(), + block_number, + }, + ) + .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; + Ok(()) } /// Delete the DID delegation key. @@ -554,7 +579,7 @@ impl DidDetails { self.authentication_key } - pub fn get_key_agreement_keys_ids(&self) -> &BTreeSet> { + pub fn get_key_agreement_keys_ids(&self) -> &BoundedBTreeSet, T::MaxTotalKeyAgreementKeys> { &self.key_agreement_keys } @@ -566,7 +591,7 @@ impl DidDetails { &self.delegation_key } - pub fn get_public_keys(&self) -> &BTreeMap, DidPublicKeyDetails> { + pub fn get_public_keys(&self) -> &DidPublicKeyMap { &self.public_keys } @@ -612,28 +637,51 @@ impl DidDetails { } } +pub(crate) type DidNewKeyAgreementKeys = BoundedBTreeSet::MaxNewKeyAgreementKeys>; +pub(crate) type DidKeyAgreementKeys = BoundedBTreeSet, ::MaxTotalKeyAgreementKeys>; +pub(crate) type DidVerificationKeysToRevoke = + BoundedBTreeSet, ::MaxVerificationKeysToRevoke>; +pub(crate) type DidPublicKeyMap = + BoundedBTreeMap, DidPublicKeyDetails, ::MaxPublicKeysPerDid>; + /// The details of a new DID to create. -#[derive(Clone, Debug, Decode, Encode, PartialEq)] +#[derive(Clone, Decode, Encode, PartialEq)] pub struct DidCreationDetails { /// The DID identifier. It has to be unique. pub did: DidIdentifierOf, /// The new key agreement keys. - pub new_key_agreement_keys: BTreeSet, + pub new_key_agreement_keys: DidNewKeyAgreementKeys, /// \[OPTIONAL\] The new attestation key. pub new_attestation_key: Option, /// \[OPTIONAL\] The new delegation key. pub new_delegation_key: Option, /// \[OPTIONAL\] The service endpoints publicly exposed. - pub new_service_endpoints: Option, + pub new_service_endpoints: Option>, +} + +// required because BoundedTreeSet does not implement Debug outside of std +impl fmt::Debug for DidCreationDetails { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DidCreationDetails") + .field("did", &self.did) + .field( + "new_key_agreement_keys", + &self.new_key_agreement_keys.clone().into_inner(), + ) + .field("new_attestation_key", &self.new_attestation_key) + .field("new_delegation_key", &self.new_delegation_key) + .field("new_service_endpoints", &self.new_service_endpoints) + .finish() + } } /// The details to update a DID. -#[derive(Clone, Debug, Decode, Encode, PartialEq)] +#[derive(Clone, Decode, Encode, PartialEq)] pub struct DidUpdateDetails { /// \[OPTIONAL\] The new authentication key. pub new_authentication_key: Option, /// A new set of key agreement keys to add to the ones already stored. - pub new_key_agreement_keys: BTreeSet, + pub new_key_agreement_keys: DidNewKeyAgreementKeys, /// \[OPTIONAL\] The attestation key update action. pub attestation_key_update: DidFragmentUpdateAction, /// \[OPTIONAL\] The delegation key update action. @@ -642,20 +690,51 @@ pub struct DidUpdateDetails { /// If the operation also replaces the current attestation key, it will /// not be considered for removal in this operation, so it is not /// possible to specify it for removal in this set. - pub public_keys_to_remove: BTreeSet>, + pub public_keys_to_remove: DidVerificationKeysToRevoke, /// The update action on the service endpoints information. - pub service_endpoints_update: DidFragmentUpdateAction, + pub service_endpoints_update: DidFragmentUpdateAction>, } -#[derive(Clone, Debug, Decode, Encode, PartialEq, Eq)] -pub struct ServiceEndpoints { +// required because BoundedTreeSet does not implement Debug outside of std +impl fmt::Debug for DidUpdateDetails { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DidUpdateDetails") + .field("new_authentication_key", &self.new_authentication_key) + .field( + "new_key_agreement_keys", + &self.new_key_agreement_keys.clone().into_inner(), + ) + .field("attestation_key_update", &self.attestation_key_update) + .field("delegation_key_update", &self.delegation_key_update) + .field( + "public_keys_to_remove", + &self.public_keys_to_remove.clone().into_inner(), + ) + .field("service_endpoints_update", &self.service_endpoints_update) + .finish() + } +} + +#[derive(Clone, Decode, Encode, PartialEq)] +pub struct ServiceEndpoints { pub content_hash: Hash, - pub urls: Vec, + pub urls: BoundedVec, T::MaxEndpointUrlsCount>, pub content_type: ContentType, } -impl ServiceEndpoints { - pub(crate) fn validate_against_config_limits(&self) -> Result<(), InputError> { +// required because BoundedTreeSet does not implement Debug outside of std +impl fmt::Debug for ServiceEndpoints { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ServiceEndpoints") + .field("content_hash", &self.content_hash) + .field("urls", &self.urls.clone().into_inner()) + .field("content_type", &self.content_type) + .finish() + } +} + +impl ServiceEndpoints { + pub(crate) fn validate_against_config_limits(&self) -> Result<(), InputError> { ensure!( self.urls.len() <= T::MaxEndpointUrlsCount::get().saturated_into::(), InputError::MaxUrlsCountExceeded diff --git a/pallets/did/src/errors.rs b/pallets/did/src/errors.rs index a877190b6e..08afcd2b0c 100644 --- a/pallets/did/src/errors.rs +++ b/pallets/did/src/errors.rs @@ -33,6 +33,24 @@ pub enum DidError { InternalError, } +impl From for DidError { + fn from(err: StorageError) -> Self { + DidError::StorageError(err) + } +} + +impl From for DidError { + fn from(err: InputError) -> Self { + DidError::InputError(err) + } +} + +impl From for DidError { + fn from(err: UrlError) -> Self { + DidError::UrlError(err) + } +} + /// Error involving the pallet's storage. #[derive(Debug, Eq, PartialEq)] pub enum StorageError { @@ -52,6 +70,12 @@ pub enum StorageError { /// The maximum supported value for the DID tx counter has been reached. /// No more operations with the DID are allowed. MaxTxCounterValue, + /// The maximum number of public keys for this DID key identifier has + /// been reached. + MaxPublicKeysPerDidExceeded, + /// The maximum number of key agreements has been reached for the DID + /// subject. + MaxTotalKeyAgreementKeysExceeded, } /// Error generated when validating a DID operation. diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index 03b8db6576..1d9c319823 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -114,6 +114,8 @@ pub mod benchmarking; #[cfg(test)] mod mock; +#[cfg(any(feature = "runtime-benchmarks", test))] +mod mock_utils; #[cfg(test)] mod tests; @@ -134,7 +136,7 @@ use frame_system::ensure_signed; #[cfg(feature = "runtime-benchmarks")] use frame_system::RawOrigin; use sp_runtime::SaturatedConversion; -use sp_std::{boxed::Box, convert::TryFrom, fmt::Debug, prelude::Clone, vec, vec::Vec}; +use sp_std::{boxed::Box, fmt::Debug, prelude::Clone}; use migrations::*; @@ -174,30 +176,53 @@ pub mod pallet { + Dispatchable::Origin, PostInfo = PostDispatchInfo> + GetDispatchInfo + DeriveDidCallAuthorizationVerificationKeyRelationship; + /// Type for a DID subject identifier. type DidIdentifier: Parameter + Default + DidVerifiableIdentifier; + #[cfg(not(feature = "runtime-benchmarks"))] /// Origin type expected by the proxied dispatchable calls. type Origin: From>>; + #[cfg(feature = "runtime-benchmarks")] type Origin: From>>; type EnsureOrigin: EnsureOrigin, ::Origin>; /// Overarching event type. type Event: From> + IsType<::Event>; + + /// Maximum number of total public keys which can be stored per DID key + /// identifier. This includes the ones currently used for + /// authentication, key agreement, attestation, and delegation. It also + /// contains old attestation keys which cannot issue new attestations + /// but can still be used to verify previously issued attestations. + #[pallet::constant] + type MaxPublicKeysPerDid: Get; + /// Maximum number of key agreement keys that can be added in a creation /// or update operation. #[pallet::constant] type MaxNewKeyAgreementKeys: Get; + + /// Maximum number of total key agreement keys that can be stored for a + /// DID subject. + /// + /// Should be greater than `MaxNewKeyAgreementKeys`. + #[pallet::constant] + type MaxTotalKeyAgreementKeys: Get + Debug + Clone + PartialEq; + /// Maximum number of keys that can be removed in an update operation. #[pallet::constant] type MaxVerificationKeysToRevoke: Get; + /// Maximum length in ASCII characters of the endpoint URL specified in /// a creation or update operation. #[pallet::constant] - type MaxUrlLength: Get; + type MaxUrlLength: Get + Debug + Clone + PartialEq; + /// Maximum number of URLs that a service endpoint can contain. #[pallet::constant] - type MaxEndpointUrlsCount: Get; + type MaxEndpointUrlsCount: Get + Debug + Clone + PartialEq; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -294,6 +319,12 @@ pub mod pallet { MaxUrlsCountExceeded, /// An error that is not supposed to take place, yet it happened. InternalError, + /// The maximum number of public keys for this DID key identifier has + /// been reached. + MaxPublicKeysPerDidExceeded, + /// The maximum number of key agreements has been reached for the DID + /// subject. + MaxTotalKeyAgreementKeysExceeded, } impl From for Error { @@ -318,6 +349,8 @@ pub mod pallet { } StorageError::MaxTxCounterValue => Self::MaxTxCounterValue, StorageError::CurrentlyActiveKey => Self::CurrentlyActiveKey, + StorageError::MaxPublicKeysPerDidExceeded => Self::MaxPublicKeysPerDidExceeded, + StorageError::MaxTotalKeyAgreementKeysExceeded => Self::MaxTotalKeyAgreementKeysExceeded, } } } @@ -385,7 +418,7 @@ pub mod pallet { /// # #[pallet::weight({ let new_key_agreement_keys = details.new_key_agreement_keys.len().saturated_into::(); - let new_urls = details.new_service_endpoints.as_ref().map_or(vec![], |endpoint| endpoint.urls.clone()); + let new_urls = details.new_service_endpoints.as_ref().map_or(BoundedVec::default(), |endpoint| endpoint.urls.clone()); // Max 3, so we can iterate quite easily. let max_url_length = new_urls.iter().map(|url| url.len().saturated_into()).max().unwrap_or(0u32); @@ -496,7 +529,7 @@ pub mod pallet { let new_urls = if let DidFragmentUpdateAction::Change(ref new_service_endpoints) = details.service_endpoints_update { new_service_endpoints.urls.clone() } else { - vec![] + BoundedVec::default() }; // Again, max 3, so we can iterate quite easily. let max_url_length = new_urls.iter().map(|url| url.len().saturated_into()).max().unwrap_or(0u32); diff --git a/pallets/did/src/migrations/v1.rs b/pallets/did/src/migrations/v1.rs index 628d2d332f..9ad829fd05 100644 --- a/pallets/did/src/migrations/v1.rs +++ b/pallets/did/src/migrations/v1.rs @@ -87,10 +87,12 @@ mod tests { use super::*; use crate::mock::Test as TestRuntime; + use mock::{get_did_identifier_from_ed25519_key, get_ed25519_authentication_key, ExtBuilder}; + use sp_std::convert::TryFrom; #[test] fn fail_version_higher() { - let mut ext = mock::ExtBuilder::default() + let mut ext = ExtBuilder::default() .with_storage_version(DidStorageVersion::V2) .build(None); ext.execute_with(|| { @@ -104,7 +106,7 @@ mod tests { #[test] fn ok_no_dids() { - let mut ext = mock::ExtBuilder::default() + let mut ext = ExtBuilder::default() .with_storage_version(DidStorageVersion::V1) .build(None); ext.execute_with(|| { @@ -126,12 +128,12 @@ mod tests { #[test] fn ok_no_prior_endpoint() { - let mut ext = mock::ExtBuilder::default() + let mut ext = ExtBuilder::default() .with_storage_version(DidStorageVersion::V1) .build(None); ext.execute_with(|| { - let auth_key = mock::get_ed25519_authentication_key(true); - let alice_did = mock::get_did_identifier_from_ed25519_key(auth_key.public()); + let auth_key = get_ed25519_authentication_key(true); + let alice_did = get_did_identifier_from_ed25519_key(auth_key.public()); let alice_did_details = deprecated::v1::DidDetails::::new(DidVerificationKey::from(auth_key.public()), 0); @@ -159,15 +161,17 @@ mod tests { #[test] fn ok_prior_endpoint() { - let mut ext = mock::ExtBuilder::default() + let mut ext = ExtBuilder::default() .with_storage_version(DidStorageVersion::V1) .build(None); ext.execute_with(|| { - let auth_key = mock::get_ed25519_authentication_key(true); - let alice_did = mock::get_did_identifier_from_ed25519_key(auth_key.public()); + let auth_key = get_ed25519_authentication_key(true); + let alice_did = get_did_identifier_from_ed25519_key(auth_key.public()); let mut alice_did_details = deprecated::v1::DidDetails::::new(DidVerificationKey::from(auth_key.public()), 0); - alice_did_details.endpoint_url = Some(Url::Http(HttpUrl::try_from(b"https://kilt.io".as_ref()).unwrap())); + alice_did_details.endpoint_url = Some(Url::::Http( + HttpUrl::try_from(b"https://kilt.io".as_ref()).unwrap(), + )); deprecated::v1::storage::Did::insert(&alice_did, alice_did_details); diff --git a/pallets/did/src/mock.rs b/pallets/did/src/mock.rs index a9dfd2686f..887e330168 100644 --- a/pallets/did/src/mock.rs +++ b/pallets/did/src/mock.rs @@ -17,11 +17,10 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org #![allow(clippy::from_over_into)] -#![allow(unused_must_use)] +#![allow(dead_code)] use frame_support::{parameter_types, weights::constants::RocksDbWeight}; use frame_system::EnsureSigned; -use kilt_primitives::Hash; use sp_core::{ecdsa, ed25519, sr25519, Pair}; use sp_keystore::{testing::KeyStore, KeystoreExt}; use sp_runtime::{ @@ -29,7 +28,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, MultiSigner, }; -use sp_std::{collections::btree_set::BTreeSet, convert::TryInto, sync::Arc}; +use sp_std::sync::Arc; use crate as did; use crate::*; @@ -90,7 +89,13 @@ impl frame_system::Config for Test { parameter_types! { pub const MaxNewKeyAgreementKeys: u32 = 10u32; pub const MaxVerificationKeysToRevoke: u32 = 10u32; + #[derive(Debug, Clone, PartialEq)] pub const MaxUrlLength: u32 = 200u32; + #[derive(Debug, Clone)] + pub const MaxPublicKeysPerDid: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxTotalKeyAgreementKeys: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] pub const MaxEndpointUrlsCount: u32 = 3u32; } @@ -101,9 +106,11 @@ impl Config for Test { type EnsureOrigin = EnsureSigned; type Event = (); type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type MaxPublicKeysPerDid = MaxPublicKeysPerDid; + type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; type MaxEndpointUrlsCount = MaxEndpointUrlsCount; - type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type WeightInfo = (); } @@ -128,8 +135,6 @@ const DEFAULT_ATT_SEED: [u8; 32] = [6u8; 32]; const ALTERNATIVE_ATT_SEED: [u8; 32] = [60u8; 32]; const DEFAULT_DEL_SEED: [u8; 32] = [7u8; 32]; const ALTERNATIVE_DEL_SEED: [u8; 32] = [70u8; 32]; -const DEFAULT_URL_SCHEME: [u8; 8] = *b"https://"; -const DEFAULT_SERVICE_ENDPOINT_HASH_SEED: u64 = 200u64; pub fn get_did_identifier_from_ed25519_key(public_key: ed25519::Public) -> TestDidIdentifier { MultiSigner::from(public_key).into_account() @@ -223,77 +228,6 @@ pub fn get_ecdsa_delegation_key(default: bool) -> ecdsa::Pair { } } -pub fn get_key_agreement_keys(n_keys: u32) -> BTreeSet { - (1..=n_keys) - .map(|i| { - // Converts the loop index to a 32-byte array; - let mut seed_vec = i.to_be_bytes().to_vec(); - seed_vec.resize(32, 0u8); - let seed: [u8; 32] = seed_vec - .try_into() - .expect("Failed to create encryption key from raw seed."); - DidEncryptionKey::X25519(seed) - }) - .collect::>() -} - -pub fn get_public_keys_to_remove(n_keys: u32) -> BTreeSet { - (1..=n_keys) - .map(|i| { - // Converts the loop index to a 32-byte array; - let mut seed_vec = i.to_be_bytes().to_vec(); - seed_vec.resize(32, 0u8); - let seed: [u8; 32] = seed_vec - .try_into() - .expect("Failed to create encryption key from raw seed."); - let key = DidEncryptionKey::X25519(seed); - generate_key_id(&key.into()) - }) - .collect::>() -} - -// Assumes that the length of the URL is larger than 8 (length of the prefix https://) -pub fn get_service_endpoints(count: u32, length: u32) -> ServiceEndpoints { - let total_length = usize::try_from(length).expect("Failed to convert URL max length value to usize value."); - let total_count = usize::try_from(count).expect("Failed to convert number (count) of URLs to usize value."); - let mut url_encoded_string = DEFAULT_URL_SCHEME.to_vec(); - url_encoded_string.resize(total_length, b'0'); - let url = Url::Http( - HttpUrl::try_from(url_encoded_string.as_ref()).expect("Failed to create default URL with provided length."), - ); - - ServiceEndpoints { - content_hash: Hash::from_low_u64_be(DEFAULT_SERVICE_ENDPOINT_HASH_SEED), - urls: vec![url; total_count], - content_type: ContentType::ApplicationJson, - } -} - -pub fn generate_base_did_creation_details(did: TestDidIdentifier) -> did::DidCreationDetails { - DidCreationDetails { - did, - new_key_agreement_keys: BTreeSet::new(), - new_attestation_key: None, - new_delegation_key: None, - new_service_endpoints: None, - } -} - -pub fn generate_base_did_update_details() -> did::DidUpdateDetails { - DidUpdateDetails { - new_authentication_key: None, - new_key_agreement_keys: BTreeSet::new(), - attestation_key_update: DidFragmentUpdateAction::default(), - delegation_key_update: DidFragmentUpdateAction::default(), - service_endpoints_update: DidFragmentUpdateAction::default(), - public_keys_to_remove: BTreeSet::new(), - } -} - -pub fn generate_base_did_details(authentication_key: did::DidVerificationKey) -> did::DidDetails { - did::DidDetails::new(authentication_key, 0u64) -} - pub fn generate_key_id(key: &did::DidPublicKey) -> TestKeyId { utils::calculate_key_id::(key) } @@ -368,7 +302,7 @@ pub fn generate_test_did_call( } } -#[allow(dead_code)] +#[allow(unused_must_use)] pub fn initialize_logger() { env_logger::builder().is_test(true).try_init(); } diff --git a/pallets/did/src/mock_utils.rs b/pallets/did/src/mock_utils.rs new file mode 100644 index 0000000000..f681249b4b --- /dev/null +++ b/pallets/did/src/mock_utils.rs @@ -0,0 +1,112 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2021 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::*; +use did_details::*; +use frame_support::{storage::bounded_btree_set::BoundedBTreeSet, BoundedVec}; +use kilt_primitives::Hash; +use sp_std::{ + collections::btree_set::BTreeSet, + convert::{TryFrom, TryInto}, + vec, +}; + +pub(crate) const DEFAULT_URL_SCHEME: [u8; 8] = *b"https://"; +const DEFAULT_SERVICE_ENDPOINT_HASH_SEED: u64 = 200u64; + +pub fn get_key_agreement_keys(n_keys: u32) -> DidNewKeyAgreementKeys { + BoundedBTreeSet::try_from( + (1..=n_keys) + .map(|i| { + // Converts the loop index to a 32-byte array; + let mut seed_vec = i.to_be_bytes().to_vec(); + seed_vec.resize(32, 0u8); + let seed: [u8; 32] = seed_vec + .try_into() + .expect("Failed to create encryption key from raw seed."); + DidEncryptionKey::X25519(seed) + }) + .collect::>(), + ) + .expect("Failed to convert key_agreement_keys to BoundedBTreeSet") +} + +pub fn get_public_keys(n_keys: u32) -> DidVerificationKeysToRevoke { + BoundedBTreeSet::try_from( + (1..=n_keys) + .map(|i| { + // Converts the loop index to a 32-byte array; + let mut seed_vec = i.to_be_bytes().to_vec(); + seed_vec.resize(32, 0u8); + let seed: [u8; 32] = seed_vec + .try_into() + .expect("Failed to create encryption key from raw seed."); + let key = DidEncryptionKey::X25519(seed); + utils::calculate_key_id::(&key.into()) + }) + .collect::>>(), + ) + .expect("Failed to convert get_public_keys to BoundedBTreeSet") +} + +// Assumes that the length of the URL is larger than 8 (length of the prefix https://) +pub fn get_service_endpoints(count: u32, length: u32) -> ServiceEndpoints { + let total_length = usize::try_from(length).expect("Failed to convert URL max length value to usize value."); + let total_count = usize::try_from(count).expect("Failed to convert number (count) of URLs to usize value."); + let mut url_encoded_string = DEFAULT_URL_SCHEME.to_vec(); + url_encoded_string.resize(total_length, b'0'); + let url = Url::::Http( + HttpUrl::try_from(url_encoded_string.as_ref()).expect("Failed to create default URL with provided length."), + ); + + ServiceEndpoints:: { + #[cfg(not(feature = "std"))] + content_hash: Hash::default(), + #[cfg(feature = "std")] + content_hash: Hash::from_low_u64_be(DEFAULT_SERVICE_ENDPOINT_HASH_SEED), + urls: BoundedVec::, T::MaxEndpointUrlsCount>::try_from(vec![url; total_count]) + .expect("Exceeded max endpoint urls when creating service endpoints"), + content_type: ContentType::ApplicationJson, + } +} + +pub fn generate_base_did_creation_details(did: DidIdentifierOf) -> DidCreationDetails { + DidCreationDetails { + did, + new_key_agreement_keys: BoundedBTreeSet::new(), + new_attestation_key: None, + new_delegation_key: None, + new_service_endpoints: None, + } +} + +pub fn generate_base_did_update_details() -> DidUpdateDetails { + DidUpdateDetails { + new_authentication_key: None, + new_key_agreement_keys: BoundedBTreeSet::new(), + attestation_key_update: DidFragmentUpdateAction::default(), + delegation_key_update: DidFragmentUpdateAction::default(), + service_endpoints_update: DidFragmentUpdateAction::default(), + public_keys_to_remove: BoundedBTreeSet::new(), + } +} + +pub fn generate_base_did_details(authentication_key: DidVerificationKey) -> DidDetails { + DidDetails::new(authentication_key, BlockNumberOf::::default()) + .expect("Failed to generate new DidDetails from auth_key due to BoundedBTreeSet bound") +} diff --git a/pallets/did/src/tests.rs b/pallets/did/src/tests.rs index cd61296e8c..6c9dced4d6 100644 --- a/pallets/did/src/tests.rs +++ b/pallets/did/src/tests.rs @@ -20,7 +20,10 @@ use frame_support::{assert_err, assert_noop, assert_ok}; use sp_core::*; use sp_std::{collections::btree_set::BTreeSet, convert::TryFrom}; -use crate::{self as did, mock::*}; +use crate::{ + self as did, mock::*, mock_utils::*, DidError, DidNewKeyAgreementKeys, DidVerificationKeysToRevoke, FtpUrl, + HttpUrl, IpfsUrl, +}; use ctype::mock as ctype_mock; // create @@ -30,7 +33,7 @@ fn check_successful_simple_ed25519_creation() { let auth_key = get_ed25519_authentication_key(true); let alice_did = get_did_identifier_from_ed25519_key(auth_key.public()); let auth_did_key = did::DidVerificationKey::from(auth_key.public()); - let details = generate_base_did_creation_details(alice_did.clone()); + let details = generate_base_did_creation_details::(alice_did.clone()); let signature = auth_key.sign(details.encode().as_ref()); @@ -65,7 +68,7 @@ fn check_successful_simple_sr25519_creation() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); let auth_did_key = did::DidVerificationKey::from(auth_key.public()); - let details = generate_base_did_creation_details(alice_did.clone()); + let details = generate_base_did_creation_details::(alice_did.clone()); let signature = auth_key.sign(details.encode().as_ref()); @@ -100,7 +103,7 @@ fn check_successful_simple_ecdsa_creation() { let auth_key = get_ecdsa_authentication_key(true); let alice_did = get_did_identifier_from_ecdsa_key(auth_key.public()); let auth_did_key = did::DidVerificationKey::from(auth_key.public()); - let details = generate_base_did_creation_details(alice_did.clone()); + let details = generate_base_did_creation_details::(alice_did.clone()); let signature = auth_key.sign(details.encode().as_ref()); @@ -135,15 +138,17 @@ fn check_successful_complete_creation() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); let auth_did_key = did::DidVerificationKey::from(auth_key.public()); - let enc_keys: BTreeSet = + let enc_keys = DidNewKeyAgreementKeys::::try_from( vec![get_x25519_encryption_key(true), get_x25519_encryption_key(false)] .iter() .copied() - .collect(); + .collect::>(), + ) + .expect("Exceeded BoundedBTreeSet bounds when creating new key agreement keys"); let del_key = get_sr25519_delegation_key(true); let att_key = get_ecdsa_attestation_key(true); - let new_service_endpoints = get_service_endpoints(1, 10); - let mut details = generate_base_did_creation_details(alice_did.clone()); + let new_service_endpoints = get_service_endpoints::(1, 10); + let mut details = generate_base_did_creation_details::(alice_did.clone()); details.new_key_agreement_keys = enc_keys.clone(); details.new_attestation_key = Some(did::DidVerificationKey::from(att_key.public())); details.new_delegation_key = Some(did::DidVerificationKey::from(del_key.public())); @@ -212,8 +217,8 @@ fn check_duplicate_did_creation() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); let auth_did_key = did::DidVerificationKey::from(auth_key.public()); - let mock_did = generate_base_did_details(auth_did_key); - let details = generate_base_did_creation_details(alice_did.clone()); + let mock_did = generate_base_did_details::(auth_did_key); + let details = generate_base_did_creation_details::(alice_did.clone()); let signature = auth_key.sign(details.encode().as_ref()); @@ -238,7 +243,7 @@ fn check_invalid_signature_format_did_creation() { // Using an Ed25519 key where an Sr25519 is expected let invalid_key = get_ed25519_authentication_key(true); // DID creation contains auth_key, but signature is generated using invalid_key - let details = generate_base_did_creation_details(alice_did); + let details = generate_base_did_creation_details::(alice_did); let signature = invalid_key.sign(details.encode().as_ref()); @@ -261,7 +266,7 @@ fn check_invalid_signature_did_creation() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); let alternative_key = get_sr25519_authentication_key(false); - let details = generate_base_did_creation_details(alice_did); + let details = generate_base_did_creation_details::(alice_did); let signature = alternative_key.sign(details.encode().as_ref()); @@ -284,7 +289,7 @@ fn check_swapped_did_subject_did_creation() { let auth_key = get_sr25519_authentication_key(true); let swapped_key = get_sr25519_authentication_key(false); let swapped_did = get_did_identifier_from_sr25519_key(swapped_key.public()); - let details = generate_base_did_creation_details(swapped_did); + let details = generate_base_did_creation_details::(swapped_did); let signature = auth_key.sign(details.encode().as_ref()); @@ -303,12 +308,14 @@ fn check_swapped_did_subject_did_creation() { } #[test] +#[should_panic = "Failed to convert key_agreement_keys to BoundedBTreeSet"] fn check_max_limit_key_agreement_keys_did_creation() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); // Max keys allowed + 1 - let enc_keys = get_key_agreement_keys(::MaxNewKeyAgreementKeys::get().saturating_add(1)); - let mut details = generate_base_did_creation_details(alice_did); + let enc_keys = + get_key_agreement_keys::(::MaxNewKeyAgreementKeys::get().saturating_add(1)); + let mut details = generate_base_did_creation_details::(alice_did); details.new_key_agreement_keys = enc_keys; let signature = auth_key.sign(details.encode().as_ref()); @@ -328,13 +335,15 @@ fn check_max_limit_key_agreement_keys_did_creation() { } #[test] +#[should_panic = "Failed to create default URL with provided length"] fn check_url_too_long_did_creation() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); // Max URL length allowed + 1 - let service_endpoints = get_service_endpoints(1, ::MaxUrlLength::get().saturating_add(1)); + let service_endpoints = + get_service_endpoints::(1, ::MaxUrlLength::get().saturating_add(1)); - let mut details = generate_base_did_creation_details(alice_did); + let mut details = generate_base_did_creation_details::(alice_did); details.new_service_endpoints = Some(service_endpoints); let signature = auth_key.sign(details.encode().as_ref()); @@ -354,6 +363,7 @@ fn check_url_too_long_did_creation() { } #[test] +#[should_panic = "Exceeded max endpoint urls when creating service endpoints"] fn check_too_many_urls_did_creation() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); @@ -392,34 +402,43 @@ fn check_successful_complete_update() { let old_att_key = get_ed25519_attestation_key(true); let new_att_key = get_ed25519_attestation_key(false); let new_del_key = get_sr25519_delegation_key(true); - let new_service_endpoints = get_service_endpoints(1, 10); - - let mut old_did_details = generate_base_did_details(did::DidVerificationKey::from(old_auth_key.public())); - old_did_details.add_key_agreement_keys( - vec![old_enc_key] - .iter() - .copied() - .collect::>(), + let new_service_endpoints = get_service_endpoints::(1, 10); + + let mut old_did_details = generate_base_did_details::(did::DidVerificationKey::from(old_auth_key.public())); + assert_ok!(old_did_details.add_key_agreement_keys( + DidNewKeyAgreementKeys::::try_from( + vec![old_enc_key] + .iter() + .copied() + .collect::>(), + ) + .expect("Should not fail to create BoundedBTreeSet from a single element"), 0u64, - ); - old_did_details.update_attestation_key(did::DidVerificationKey::from(old_att_key.public()), 0u64); + )); + assert_ok!(old_did_details.update_attestation_key(did::DidVerificationKey::from(old_att_key.public()), 0u64)); // Update all keys, URL endpoint and tx counter. The old key agreement key is // removed. - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); details.new_authentication_key = Some(did::DidVerificationKey::from(new_auth_key.public())); - details.new_key_agreement_keys = vec![new_enc_key] - .iter() - .copied() - .collect::>(); + details.new_key_agreement_keys = DidNewKeyAgreementKeys::::try_from( + vec![new_enc_key] + .iter() + .copied() + .collect::>(), + ) + .expect("Should not fail to create BoundedBTreeSet from a single element"); details.attestation_key_update = did::DidFragmentUpdateAction::Change(did::DidVerificationKey::from(new_att_key.public())); details.delegation_key_update = did::DidFragmentUpdateAction::Change(did::DidVerificationKey::from(new_del_key.public())); - details.public_keys_to_remove = vec![generate_key_id(&old_enc_key.into())] - .iter() - .copied() - .collect::>(); + details.public_keys_to_remove = DidVerificationKeysToRevoke::::try_from( + vec![generate_key_id(&old_enc_key.into())] + .iter() + .copied() + .collect::>(), + ) + .expect("Should not fail to create BoundedBTreeSet from a single element"); details.service_endpoints_update = did::DidFragmentUpdateAction::Change(new_service_endpoints.clone()); let mut ext = ExtBuilder::default() @@ -497,12 +516,12 @@ fn check_successful_keys_deletion_update() { let att_key = get_ed25519_attestation_key(true); let del_key = get_sr25519_delegation_key(true); - let mut old_did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - old_did_details.update_attestation_key(did::DidVerificationKey::from(att_key.public()), 0u64); - old_did_details.update_delegation_key(did::DidVerificationKey::from(del_key.public()), 0u64); + let mut old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + assert_ok!(old_did_details.update_attestation_key(did::DidVerificationKey::from(att_key.public()), 0u64)); + assert_ok!(old_did_details.update_delegation_key(did::DidVerificationKey::from(del_key.public()), 0u64)); // Remove both attestation and delegation key - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); details.attestation_key_update = did::DidFragmentUpdateAction::Delete; details.delegation_key_update = did::DidFragmentUpdateAction::Delete; @@ -624,10 +643,10 @@ fn check_successful_keys_overwrite_update() { // Same as the authentication key -> leads to two keys having the same ID let new_att_key = auth_key.clone(); - let old_did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); // Remove both attestation and delegation key - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); details.attestation_key_update = did::DidFragmentUpdateAction::Change(did::DidVerificationKey::from(new_att_key.public())); @@ -678,11 +697,11 @@ fn check_successful_keys_multiuse_update() { // Same as the authentication key -> leads to two keys having the same ID let old_att_key = auth_key.clone(); - let mut old_did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - old_did_details.update_attestation_key(did::DidVerificationKey::from(old_att_key.public()), 0u64); + let mut old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + assert_ok!(old_did_details.update_attestation_key(did::DidVerificationKey::from(old_att_key.public()), 0u64)); // Remove attestation key - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); details.attestation_key_update = did::DidFragmentUpdateAction::Delete; let mut ext = ExtBuilder::default() @@ -719,8 +738,8 @@ fn check_did_not_present_update() { let alice_did = get_did_identifier_from_ed25519_key(auth_key.public()); let bob_auth_key = get_ed25519_authentication_key(false); let bob_did = get_did_identifier_from_ed25519_key(bob_auth_key.public()); - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - let details = generate_base_did_update_details(); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + let details = generate_base_did_update_details::(); let mut ext = ExtBuilder::default().with_dids(vec![(bob_did, mock_did)]).build(None); @@ -733,16 +752,18 @@ fn check_did_not_present_update() { } #[test] +#[should_panic = "Failed to convert key_agreement_keys to BoundedBTreeSet"] fn check_max_limit_key_agreement_keys_did_update() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); - let old_did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); // Max keys allowed + 1 - let new_enc_keys = get_key_agreement_keys(::MaxNewKeyAgreementKeys::get().saturating_add(1)); + let new_enc_keys = + get_key_agreement_keys::(::MaxNewKeyAgreementKeys::get().saturating_add(1)); - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); details.new_key_agreement_keys = new_enc_keys; let mut ext = ExtBuilder::default() @@ -761,17 +782,18 @@ fn check_max_limit_key_agreement_keys_did_update() { } #[test] +#[should_panic = "Failed to convert get_public_keys to BoundedBTreeSet"] fn check_max_limit_public_keys_to_remove_did_update() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); - let old_did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); // Max keys allowed + 1 let keys_ids_to_remove = - get_public_keys_to_remove(::MaxNewKeyAgreementKeys::get().saturating_add(1)); + get_public_keys::(::MaxNewKeyAgreementKeys::get().saturating_add(1)); - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); details.public_keys_to_remove = keys_ids_to_remove; let mut ext = ExtBuilder::default() @@ -790,16 +812,18 @@ fn check_max_limit_public_keys_to_remove_did_update() { } #[test] +#[should_panic = "Failed to create default URL with provided length"] fn check_url_too_long_did_update() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); - let old_did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); // Max URL length allowed + 1 - let new_service_endpoints = get_service_endpoints(1, ::MaxUrlLength::get().saturating_add(1)); + let new_service_endpoints = + get_service_endpoints::(1, ::MaxUrlLength::get().saturating_add(1)); - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); details.service_endpoints_update = did::DidFragmentUpdateAction::Change(new_service_endpoints); let mut ext = ExtBuilder::default() @@ -818,6 +842,7 @@ fn check_url_too_long_did_update() { } #[test] +#[should_panic = "Exceeded max endpoint urls when creating service endpoints"] fn check_too_many_urls_did_update() { let auth_key = get_sr25519_authentication_key(true); let alice_did = get_did_identifier_from_sr25519_key(auth_key.public()); @@ -851,17 +876,20 @@ fn check_currently_active_authentication_key_update() { let auth_key = get_ed25519_authentication_key(true); let alice_did = get_did_identifier_from_ed25519_key(auth_key.public()); - let old_did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); // Remove both attestation and delegation key - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); // Trying to remove the currently active authentication key - details.public_keys_to_remove = vec![generate_key_id( - &did::DidVerificationKey::from(auth_key.public()).into(), - )] - .iter() - .copied() - .collect::>(); + details.public_keys_to_remove = DidVerificationKeysToRevoke::::try_from( + vec![generate_key_id( + &did::DidVerificationKey::from(auth_key.public()).into(), + )] + .iter() + .copied() + .collect::>(), + ) + .expect("Should not fail to create BoundedBTreeSet from a single element"); let mut ext = ExtBuilder::default() .with_dids(vec![(alice_did.clone(), old_did_details)]) @@ -884,16 +912,19 @@ fn check_currently_active_delegation_key_update() { let alice_did = get_did_identifier_from_ed25519_key(auth_key.public()); let del_key = get_ecdsa_delegation_key(true); - let mut old_did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - old_did_details.update_delegation_key(did::DidVerificationKey::from(del_key.public()), 0u64); + let mut old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + assert_ok!(old_did_details.update_delegation_key(did::DidVerificationKey::from(del_key.public()), 0u64)); // Remove both attestation and delegation key - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); // Trying to remove the currently active delegation key - details.public_keys_to_remove = vec![generate_key_id(&did::DidVerificationKey::from(del_key.public()).into())] - .iter() - .copied() - .collect::>(); + details.public_keys_to_remove = DidVerificationKeysToRevoke::::try_from( + vec![generate_key_id(&did::DidVerificationKey::from(del_key.public()).into())] + .iter() + .copied() + .collect::>(), + ) + .expect("Should not fail to create BoundedBTreeSet from a single element"); let mut ext = ExtBuilder::default() .with_dids(vec![(alice_did.clone(), old_did_details)]) @@ -916,16 +947,19 @@ fn check_currently_active_attestation_key_update() { let alice_did = get_did_identifier_from_ed25519_key(auth_key.public()); let att_key = get_sr25519_attestation_key(true); - let mut old_did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - old_did_details.update_attestation_key(did::DidVerificationKey::from(att_key.public()), 0u64); + let mut old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + assert_ok!(old_did_details.update_attestation_key(did::DidVerificationKey::from(att_key.public()), 0u64)); // Remove both attestation and delegation key - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); // Trying to remove the currently active attestation key - details.public_keys_to_remove = vec![generate_key_id(&did::DidVerificationKey::from(att_key.public()).into())] - .iter() - .copied() - .collect::>(); + details.public_keys_to_remove = DidVerificationKeysToRevoke::::try_from( + vec![generate_key_id(&did::DidVerificationKey::from(att_key.public()).into())] + .iter() + .copied() + .collect::>(), + ) + .expect("Should not fail to create BoundedBTreeSet from a single element"); let mut ext = ExtBuilder::default() .with_dids(vec![(alice_did.clone(), old_did_details)]) @@ -948,17 +982,20 @@ fn check_verification_key_not_present_update() { let alice_did = get_did_identifier_from_ed25519_key(auth_key.public()); let key_to_delete = get_sr25519_authentication_key(true); - let old_did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); // Remove both attestation and delegation key - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); // Trying to remove the currently active authentication key - details.public_keys_to_remove = vec![generate_key_id( - &did::DidVerificationKey::from(key_to_delete.public()).into(), - )] - .iter() - .copied() - .collect::>(); + details.public_keys_to_remove = DidVerificationKeysToRevoke::::try_from( + vec![generate_key_id( + &did::DidVerificationKey::from(key_to_delete.public()).into(), + )] + .iter() + .copied() + .collect::>(), + ) + .expect("Should not fail to create BoundedBTreeSet from a single element"); let mut ext = ExtBuilder::default() .with_dids(vec![(alice_did.clone(), old_did_details)]) @@ -981,7 +1018,7 @@ fn check_verification_key_not_present_update() { fn check_successful_deletion() { let auth_key = get_ed25519_authentication_key(true); let alice_did = get_did_identifier_from_ed25519_key(auth_key.public()); - let did_details = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let mut ext = ExtBuilder::default() .with_dids(vec![(alice_did.clone(), did_details)]) @@ -991,10 +1028,10 @@ fn check_successful_deletion() { assert_ok!(Did::delete(Origin::signed(alice_did.clone()),)); }); - assert_eq!(ext.execute_with(|| Did::get_did(alice_did.clone())), None); + assert!(ext.execute_with(|| Did::get_did(alice_did.clone())).is_none()); // Re-adding the same DID identifier, which should not fail. - let details = generate_base_did_creation_details(alice_did.clone()); + let details = generate_base_did_creation_details::(alice_did.clone()); let signature = auth_key.sign(details.encode().as_ref()); @@ -1055,7 +1092,7 @@ fn check_max_counter_call_error() { let auth_key = get_sr25519_authentication_key(true); let did = get_did_identifier_from_sr25519_key(auth_key.public()); let caller = DEFAULT_ACCOUNT; - let mut mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mut mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); mock_did.last_tx_counter = u64::MAX; let mut ext = ExtBuilder::default() @@ -1082,7 +1119,7 @@ fn check_too_small_tx_counter_call_error() { let auth_key = get_sr25519_authentication_key(true); let did = get_did_identifier_from_sr25519_key(auth_key.public()); let caller = DEFAULT_ACCOUNT; - let mut mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mut mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); mock_did.last_tx_counter = 1u64; let mut ext = ExtBuilder::default() @@ -1110,7 +1147,7 @@ fn check_equal_tx_counter_call_error() { let auth_key = get_sr25519_authentication_key(true); let did = get_did_identifier_from_sr25519_key(auth_key.public()); let caller = DEFAULT_ACCOUNT; - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did.clone())]) @@ -1137,7 +1174,7 @@ fn check_too_large_tx_counter_call_error() { let auth_key = get_sr25519_authentication_key(true); let did = get_did_identifier_from_sr25519_key(auth_key.public()); let caller = DEFAULT_ACCOUNT; - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did.clone())]) @@ -1164,7 +1201,7 @@ fn check_verification_key_not_present_call_error() { let auth_key = get_sr25519_authentication_key(true); let did = get_did_identifier_from_sr25519_key(auth_key.public()); let caller = DEFAULT_ACCOUNT; - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did)]) @@ -1193,7 +1230,7 @@ fn check_invalid_signature_format_call_error() { let did = get_did_identifier_from_sr25519_key(auth_key.public()); let caller = DEFAULT_ACCOUNT; let alternative_auth_key = get_ed25519_authentication_key(true); - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did)]) @@ -1220,7 +1257,7 @@ fn check_invalid_signature_call_error() { let did = get_did_identifier_from_sr25519_key(auth_key.public()); let caller = DEFAULT_ACCOUNT; let alternative_auth_key = get_sr25519_authentication_key(false); - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did)]) @@ -1248,8 +1285,8 @@ fn check_call_attestation_key_successful() { let caller = DEFAULT_ACCOUNT; let attestation_key = get_ed25519_attestation_key(true); - let mut mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - mock_did.update_attestation_key(did::DidVerificationKey::from(attestation_key.public()), 0); + let mut mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + assert_ok!(mock_did.update_attestation_key(did::DidVerificationKey::from(attestation_key.public()), 0)); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did)]) @@ -1274,8 +1311,8 @@ fn check_call_attestation_key_error() { let caller = DEFAULT_ACCOUNT; let attestation_key = get_ed25519_attestation_key(true); - let mut mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - mock_did.update_attestation_key(did::DidVerificationKey::from(attestation_key.public()), 0); + let mut mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + assert_ok!(mock_did.update_attestation_key(did::DidVerificationKey::from(attestation_key.public()), 0)); let ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did)]) @@ -1307,8 +1344,8 @@ fn check_call_delegation_key_successful() { let caller = DEFAULT_ACCOUNT; let delegation_key = get_ed25519_delegation_key(true); - let mut mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - mock_did.update_delegation_key(did::DidVerificationKey::from(delegation_key.public()), 0); + let mut mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + assert_ok!(mock_did.update_delegation_key(did::DidVerificationKey::from(delegation_key.public()), 0)); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did)]) @@ -1333,8 +1370,8 @@ fn check_call_delegation_key_error() { let caller = DEFAULT_ACCOUNT; let delegation_key = get_ed25519_delegation_key(true); - let mut mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - mock_did.update_delegation_key(did::DidVerificationKey::from(delegation_key.public()), 0); + let mut mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + assert_ok!(mock_did.update_delegation_key(did::DidVerificationKey::from(delegation_key.public()), 0)); let ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did)]) @@ -1365,7 +1402,7 @@ fn check_call_authentication_key_successful() { let did = get_did_identifier_from_sr25519_key(auth_key.public()); let caller = DEFAULT_ACCOUNT; - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did)]) @@ -1389,7 +1426,7 @@ fn check_call_authentication_key_error() { let did = get_did_identifier_from_sr25519_key(auth_key.public()); let caller = DEFAULT_ACCOUNT; - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did)]) @@ -1446,7 +1483,7 @@ fn check_authentication_successful_operation_verification() { let auth_key = get_sr25519_authentication_key(true); let did = get_did_identifier_from_sr25519_key(auth_key.public()); - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did.clone())]) @@ -1477,8 +1514,8 @@ fn check_attestation_successful_operation_verification() { let did = get_did_identifier_from_sr25519_key(auth_key.public()); let attestation_key = get_ed25519_attestation_key(true); - let mut mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - mock_did.update_attestation_key(did::DidVerificationKey::from(attestation_key.public()), 0); + let mut mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + assert_ok!(mock_did.update_attestation_key(did::DidVerificationKey::from(attestation_key.public()), 0)); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did.clone())]) @@ -1509,8 +1546,8 @@ fn check_delegation_successful_operation_verification() { let did = get_did_identifier_from_sr25519_key(auth_key.public()); let delegation_key = get_ecdsa_delegation_key(true); - let mut mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); - mock_did.update_delegation_key(did::DidVerificationKey::from(delegation_key.public()), 0); + let mut mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); + assert_ok!(mock_did.update_delegation_key(did::DidVerificationKey::from(delegation_key.public()), 0)); let mut ext = ExtBuilder::default() .with_dids(vec![(did.clone(), mock_did.clone())]) @@ -1551,7 +1588,7 @@ fn check_did_not_present_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::StorageError(did::StorageError::DidNotPresent) + DidError::StorageError(did::StorageError::DidNotPresent) ); }); } @@ -1561,7 +1598,7 @@ fn check_max_tx_counter_operation_verification() { let auth_key = get_sr25519_authentication_key(true); let did = get_did_identifier_from_sr25519_key(auth_key.public()); - let mut mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mut mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); mock_did.set_tx_counter(u64::MAX); let mut ext = ExtBuilder::default() @@ -1578,7 +1615,7 @@ fn check_max_tx_counter_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::StorageError(did::StorageError::MaxTxCounterValue) + DidError::StorageError(did::StorageError::MaxTxCounterValue) ); }); } @@ -1588,7 +1625,7 @@ fn check_smaller_counter_operation_verification() { let auth_key = get_ed25519_authentication_key(true); let did = get_did_identifier_from_ed25519_key(auth_key.public()); - let mut mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mut mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); mock_did.last_tx_counter = 1; let mut call_operation = @@ -1604,7 +1641,7 @@ fn check_smaller_counter_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::SignatureError(did::SignatureError::InvalidNonce) + DidError::SignatureError(did::SignatureError::InvalidNonce) ); }); } @@ -1614,7 +1651,7 @@ fn check_equal_counter_operation_verification() { let auth_key = get_ed25519_authentication_key(true); let did = get_did_identifier_from_ed25519_key(auth_key.public()); - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let mut call_operation = generate_test_did_call(did::DidVerificationKeyRelationship::CapabilityDelegation, did.clone()); @@ -1629,7 +1666,7 @@ fn check_equal_counter_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::SignatureError(did::SignatureError::InvalidNonce) + DidError::SignatureError(did::SignatureError::InvalidNonce) ); }); } @@ -1639,7 +1676,7 @@ fn check_too_large_counter_operation_verification() { let auth_key = get_ed25519_authentication_key(true); let did = get_did_identifier_from_ed25519_key(auth_key.public()); - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let mut call_operation = generate_test_did_call(did::DidVerificationKeyRelationship::CapabilityDelegation, did.clone()); @@ -1654,7 +1691,7 @@ fn check_too_large_counter_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::SignatureError(did::SignatureError::InvalidNonce) + DidError::SignatureError(did::SignatureError::InvalidNonce) ); }); } @@ -1664,7 +1701,7 @@ fn check_verification_key_not_present_operation_verification() { let auth_key = get_ed25519_authentication_key(true); let did = get_did_identifier_from_ed25519_key(auth_key.public()); - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let call_operation = generate_test_did_call(did::DidVerificationKeyRelationship::AssertionMethod, did.clone()); let signature = auth_key.sign(call_operation.encode().as_ref()); @@ -1677,7 +1714,7 @@ fn check_verification_key_not_present_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::StorageError(did::StorageError::DidKeyNotPresent( + DidError::StorageError(did::StorageError::DidKeyNotPresent( did::DidVerificationKeyRelationship::AssertionMethod )) ); @@ -1691,7 +1728,7 @@ fn check_invalid_signature_format_operation_verification() { // Expected an Sr25519, given an Ed25519 let invalid_key = get_ed25519_authentication_key(true); - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let call_operation = generate_test_did_call(did::DidVerificationKeyRelationship::Authentication, did.clone()); let signature = invalid_key.sign(call_operation.encode().as_ref()); @@ -1704,7 +1741,7 @@ fn check_invalid_signature_format_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::SignatureError(did::SignatureError::InvalidSignatureFormat) + DidError::SignatureError(did::SignatureError::InvalidSignatureFormat) ); }); } @@ -1716,7 +1753,7 @@ fn check_invalid_signature_operation_verification() { // Using same key type but different seed (default = false) let alternative_key = get_sr25519_authentication_key(false); - let mock_did = generate_base_did_details(did::DidVerificationKey::from(auth_key.public())); + let mock_did = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); let call_operation = generate_test_did_call(did::DidVerificationKeyRelationship::Authentication, did.clone()); let signature = alternative_key.sign(&call_operation.encode()); @@ -1729,7 +1766,7 @@ fn check_invalid_signature_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::SignatureError(did::SignatureError::InvalidSignature) + DidError::SignatureError(did::SignatureError::InvalidSignature) ); }); } @@ -1738,48 +1775,48 @@ fn check_invalid_signature_operation_verification() { #[test] fn check_http_url() { - assert_ok!(did::HttpUrl::try_from("http://kilt.io".as_bytes())); + assert_ok!(HttpUrl::::try_from("http://kilt.io".as_bytes())); - assert_ok!(did::HttpUrl::try_from("https://kilt.io".as_bytes())); + assert_ok!(HttpUrl::::try_from("https://kilt.io".as_bytes())); - assert_ok!(did::HttpUrl::try_from( + assert_ok!(HttpUrl::::try_from( "https://super.long.domain.kilt.io:12345/public/files/test.txt".as_bytes() )); // All other valid ASCII characters - assert_ok!(did::HttpUrl::try_from("http://:/?#[]@!$&'()*+,;=-._~".as_bytes())); + assert_ok!(HttpUrl::::try_from("http://:/?#[]@!$&'()*+,;=-._~".as_bytes())); assert_eq!( - did::HttpUrl::try_from("".as_bytes()), - Err(did::UrlError::InvalidUrlScheme) + HttpUrl::::try_from("".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlScheme)) ); // Non-printable ASCII characters assert_eq!( - did::HttpUrl::try_from("http://kilt.io/\x00".as_bytes()), - Err(did::UrlError::InvalidUrlEncoding) + HttpUrl::::try_from("http://kilt.io/\x00".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlEncoding)) ); // Some invalid ASCII characters assert_eq!( - did::HttpUrl::try_from("http://kilt.io/".as_bytes()), - Err(did::UrlError::InvalidUrlEncoding) + HttpUrl::::try_from("http://kilt.io/".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlEncoding)) ); // Non-ASCII characters assert_eq!( - did::HttpUrl::try_from("http://¶.com".as_bytes()), - Err(did::UrlError::InvalidUrlEncoding) + HttpUrl::::try_from("http://¶.com".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlEncoding)) ); assert_eq!( - did::HttpUrl::try_from("htt://kilt.io".as_bytes()), - Err(did::UrlError::InvalidUrlScheme) + HttpUrl::::try_from("htt://kilt.io".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlScheme)) ); assert_eq!( - did::HttpUrl::try_from("httpss://kilt.io".as_bytes()), - Err(did::UrlError::InvalidUrlScheme) + HttpUrl::::try_from("httpss://kilt.io".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlScheme)) ); } @@ -1787,48 +1824,48 @@ fn check_http_url() { #[test] fn check_ftp_url() { - assert_ok!(did::FtpUrl::try_from("ftp://kilt.io".as_bytes())); + assert_ok!(FtpUrl::::try_from("ftp://kilt.io".as_bytes())); - assert_ok!(did::FtpUrl::try_from("ftps://kilt.io".as_bytes())); + assert_ok!(FtpUrl::::try_from("ftps://kilt.io".as_bytes())); - assert_ok!(did::FtpUrl::try_from( + assert_ok!(FtpUrl::::try_from( "ftps://user@super.long.domain.kilt.io:12345/public/files/test.txt".as_bytes() )); // All other valid ASCII characters - assert_ok!(did::FtpUrl::try_from("ftps://:/?#[]@%!$&'()*+,;=-._~".as_bytes())); + assert_ok!(FtpUrl::::try_from("ftps://:/?#[]@%!$&'()*+,;=-._~".as_bytes())); assert_eq!( - did::FtpUrl::try_from("".as_bytes()), - Err(did::UrlError::InvalidUrlScheme) + FtpUrl::::try_from("".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlScheme)) ); // Non-printable ASCII characters assert_eq!( - did::HttpUrl::try_from("http://kilt.io/\x00".as_bytes()), - Err(did::UrlError::InvalidUrlEncoding) + HttpUrl::::try_from("http://kilt.io/\x00".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlEncoding)) ); // Some invalid ASCII characters assert_eq!( - did::FtpUrl::try_from("ftp://kilt.io/".as_bytes()), - Err(did::UrlError::InvalidUrlEncoding) + FtpUrl::::try_from("ftp://kilt.io/".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlEncoding)) ); // Non-ASCII characters assert_eq!( - did::FtpUrl::try_from("ftps://¶.com".as_bytes()), - Err(did::UrlError::InvalidUrlEncoding) + FtpUrl::::try_from("ftps://¶.com".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlEncoding)) ); assert_eq!( - did::FtpUrl::try_from("ft://kilt.io".as_bytes()), - Err(did::UrlError::InvalidUrlScheme) + FtpUrl::::try_from("ft://kilt.io".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlScheme)) ); assert_eq!( - did::HttpUrl::try_from("ftpss://kilt.io".as_bytes()), - Err(did::UrlError::InvalidUrlScheme) + HttpUrl::::try_from("ftpss://kilt.io".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlScheme)) ); } @@ -1837,33 +1874,33 @@ fn check_ftp_url() { #[test] fn check_ipfs_url() { // Base58 address - assert_ok!(did::IpfsUrl::try_from( + assert_ok!(IpfsUrl::::try_from( "ipfs://QmdQ1rHHHTbgbGorfuMMYDQQ36q4sxvYcB4GDEHREuJQkL".as_bytes() )); // Base32 address (at the moment, padding characters can appear anywhere in the // string) - assert_ok!(did::IpfsUrl::try_from( + assert_ok!(IpfsUrl::::try_from( "ipfs://OQQHHHTGMMYDQQ364YB4GDE=HREJQL==".as_bytes() )); assert_eq!( - did::IpfsUrl::try_from("".as_bytes()), - Err(did::UrlError::InvalidUrlScheme) + IpfsUrl::::try_from("".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlScheme)) ); assert_eq!( - did::IpfsUrl::try_from("ipfs://¶QmdQ1rHHHTbgbGorfuMMYDQQ36q4sxvYcB4GDEHREuJQkL".as_bytes()), - Err(did::UrlError::InvalidUrlEncoding) + IpfsUrl::::try_from("ipfs://¶QmdQ1rHHHTbgbGorfuMMYDQQ36q4sxvYcB4GDEHREuJQkL".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlEncoding)) ); assert_eq!( - did::IpfsUrl::try_from("ipf://QmdQ1rHHHTbgbGorfuMMYDQQ36q4sxvYcB4GDEHREuJQkL".as_bytes()), - Err(did::UrlError::InvalidUrlScheme) + IpfsUrl::::try_from("ipf://QmdQ1rHHHTbgbGorfuMMYDQQ36q4sxvYcB4GDEHREuJQkL".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlScheme)) ); assert_eq!( - did::IpfsUrl::try_from("ipfss://QmdQ1rHHHTbgbGorfuMMYDQQ36q4sxvYcB4GDEHREuJQk".as_bytes()), - Err(did::UrlError::InvalidUrlScheme) + IpfsUrl::::try_from("ipfss://QmdQ1rHHHTbgbGorfuMMYDQQ36q4sxvYcB4GDEHREuJQk".as_bytes()), + Err(DidError::UrlError(did::UrlError::InvalidUrlScheme)) ); } diff --git a/pallets/did/src/url.rs b/pallets/did/src/url.rs index 78862f7c2d..5821c652f3 100644 --- a/pallets/did/src/url.rs +++ b/pallets/did/src/url.rs @@ -16,10 +16,15 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org +use sp_std::fmt; + +use frame_support::{ensure, BoundedVec}; +use sp_std::convert::TryFrom; + use codec::{Decode, Encode}; use sp_std::str; -use crate::*; +use crate::{utils, Config, DidError, InputError, UrlError}; /// The expected URI scheme for HTTP endpoints. pub const HTTP_URI_SCHEME: &str = "http://"; @@ -41,15 +46,25 @@ pub enum ContentType { ApplicationJsonLd, } +pub(crate) type UrlPayload = BoundedVec::MaxUrlLength>; + /// A web URL starting with either http:// or https:// /// and containing only ASCII URL-encoded characters. -#[derive(Clone, Decode, Debug, Encode, PartialEq, Eq)] -pub struct HttpUrl { - payload: Vec, +#[derive(Clone, Decode, Encode, PartialEq)] +pub struct HttpUrl { + payload: UrlPayload, +} + +impl fmt::Debug for HttpUrl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("HttpUrl") + .field("payload", &self.payload.clone().into_inner()) + .finish() + } } -impl TryFrom<&[u8]> for HttpUrl { - type Error = UrlError; +impl TryFrom<&[u8]> for HttpUrl { + type Error = DidError; // It fails if the byte sequence does not result in an ASCII-encoded string or // if the resulting string contains characters that are not allowed in a URL. @@ -63,21 +78,30 @@ impl TryFrom<&[u8]> for HttpUrl { ensure!(utils::is_valid_ascii_url(str_url), UrlError::InvalidUrlEncoding); - Ok(HttpUrl { - payload: value.to_vec(), - }) + let payload = BoundedVec::::try_from(value.to_vec()) + .map_err(|_| InputError::MaxUrlLengthExceeded)?; + + Ok(HttpUrl:: { payload }) } } /// An FTP URL starting with ftp:// or ftps:// /// and containing only ASCII URL-encoded characters. -#[derive(Clone, Decode, Debug, Encode, PartialEq, Eq)] -pub struct FtpUrl { - payload: Vec, +#[derive(Clone, Decode, Encode, PartialEq)] +pub struct FtpUrl { + payload: UrlPayload, } -impl TryFrom<&[u8]> for FtpUrl { - type Error = UrlError; +impl fmt::Debug for FtpUrl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FtpUrl") + .field("payload", &self.payload.clone().into_inner()) + .finish() + } +} + +impl TryFrom<&[u8]> for FtpUrl { + type Error = DidError; // It fails if the byte sequence does not result in an ASCII-encoded string or // if the resulting string contains characters that are not allowed in a URL. @@ -91,20 +115,29 @@ impl TryFrom<&[u8]> for FtpUrl { ensure!(utils::is_valid_ascii_url(str_url), UrlError::InvalidUrlEncoding); - Ok(FtpUrl { - payload: value.to_vec(), - }) + let payload = BoundedVec::::try_from(value.to_vec()) + .map_err(|_| InputError::MaxUrlLengthExceeded)?; + + Ok(FtpUrl:: { payload }) } } /// An IPFS URL starting with ipfs://. Both CIDs v0 and v1 supported. -#[derive(Clone, Decode, Debug, Encode, PartialEq, Eq)] -pub struct IpfsUrl { - payload: Vec, +#[derive(Clone, Decode, Encode, PartialEq)] +pub struct IpfsUrl { + payload: UrlPayload, } -impl TryFrom<&[u8]> for IpfsUrl { - type Error = UrlError; +impl fmt::Debug for IpfsUrl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("IpfsUrl") + .field("payload", &self.payload.clone().into_inner()) + .finish() + } +} + +impl TryFrom<&[u8]> for IpfsUrl { + type Error = DidError; // It fails if the URL is not ASCII-encoded or does not start with the expected // URL scheme. @@ -125,28 +158,31 @@ impl TryFrom<&[u8]> for IpfsUrl { UrlError::InvalidUrlEncoding ); - Ok(IpfsUrl { - payload: value.to_vec(), - }) + let payload = BoundedVec::::try_from(value.to_vec()) + .map_err(|_| InputError::MaxUrlLengthExceeded)?; + + Ok(IpfsUrl:: { payload }) } } /// Supported URLs. -#[derive(Clone, Decode, Debug, Encode, PartialEq, Eq)] -pub enum Url { +#[derive(Clone, Decode, Debug, Encode, PartialEq)] +pub enum Url { /// See [HttpUrl]. - Http(HttpUrl), + Http(HttpUrl), /// See [FtpUrl]. - Ftp(FtpUrl), + Ftp(FtpUrl), /// See [IpfsUrl]. - Ipfs(IpfsUrl), + Ipfs(IpfsUrl), } -impl Url { +impl Url { #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize { match self { - Self::Http(HttpUrl { payload }) | Self::Ftp(FtpUrl { payload }) | Self::Ipfs(IpfsUrl { payload }) => { + Self::Http(HttpUrl:: { payload }) + | Self::Ftp(FtpUrl:: { payload }) + | Self::Ipfs(IpfsUrl:: { payload }) => { // We can use .len() as we know the string is ASCII, so 1 byte <-> 1 character payload.len() } @@ -154,20 +190,20 @@ impl Url { } } -impl From for Url { - fn from(url: HttpUrl) -> Self { +impl From> for Url { + fn from(url: HttpUrl) -> Self { Self::Http(url) } } -impl From for Url { - fn from(url: FtpUrl) -> Self { +impl From> for Url { + fn from(url: FtpUrl) -> Self { Self::Ftp(url) } } -impl From for Url { - fn from(url: IpfsUrl) -> Self { +impl From> for Url { + fn from(url: IpfsUrl) -> Self { Self::Ipfs(url) } } diff --git a/pallets/did/src/utils.rs b/pallets/did/src/utils.rs index e66086673e..860382a819 100644 --- a/pallets/did/src/utils.rs +++ b/pallets/did/src/utils.rs @@ -16,10 +16,10 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org +use crate::*; use codec::Encode; use sp_runtime::traits::Hash; - -use crate::*; +use sp_std::vec::Vec; pub fn calculate_key_id(key: &DidPublicKey) -> KeyIdOf { let hashed_values: Vec = key.encode(); diff --git a/pallets/kilt-launch/src/benchmarking.rs b/pallets/kilt-launch/src/benchmarking.rs index f0e5949a80..68c8f2b7df 100644 --- a/pallets/kilt-launch/src/benchmarking.rs +++ b/pallets/kilt-launch/src/benchmarking.rs @@ -161,7 +161,7 @@ benchmarks! { block: UNLOCK_BLOCK.into(), amount: (2 * AMOUNT).into(), }), "Source BalanceLock not set"); - assert_eq!(UnlockingAt::::get::(UNLOCK_BLOCK.into()).expect("UnlockingAt should not be empty"), vec![source.clone()]); + assert_eq!(UnlockingAt::::get::(UNLOCK_BLOCK.into()).expect("UnlockingAt should not be empty").into_inner(), vec![source.clone()]); // Set custom lock with amount `AMOUNT` for target let target: T::AccountId = account("target", 0, SEED); @@ -171,12 +171,12 @@ benchmarks! { block: UNLOCK_BLOCK.into(), amount: AMOUNT.into(), }), "Target BalanceLock not set"); - assert_eq!(UnlockingAt::::get::(UNLOCK_BLOCK.into()).expect("UnlockingAt should not be empty"), vec![source.clone(), target.clone()]); + assert_eq!(UnlockingAt::::get::(UNLOCK_BLOCK.into()).expect("UnlockingAt should not be empty").into_inner(), vec![source.clone(), target.clone()]); // Transfer AMOUNT from source to target }: _(RawOrigin::Signed(source.clone()), target_lookup, AMOUNT.into()) verify { - assert_eq!(UnlockingAt::::get::(UNLOCK_BLOCK.into()).expect("UnlockingAt should not be empty"), vec![source.clone(), target.clone()]); + assert_eq!(UnlockingAt::::get::(UNLOCK_BLOCK.into()).expect("UnlockingAt should not be empty").into_inner(), vec![source.clone(), target.clone()]); assert_eq!(BalanceLocks::::get(&source), Some(LockedBalance:: { block: UNLOCK_BLOCK.into(), amount: AMOUNT.into(), diff --git a/pallets/kilt-launch/src/default_weights.rs b/pallets/kilt-launch/src/default_weights.rs index 9f631cfb7a..959ee4059a 100644 --- a/pallets/kilt-launch/src/default_weights.rs +++ b/pallets/kilt-launch/src/default_weights.rs @@ -19,24 +19,22 @@ //! Autogenerated weights for kilt_launch //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-22, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! DATE: 2021-08-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: // /home/willi/mashnet-node/target/release/kilt-parachain // benchmark // --chain=dev -// --execution=wasm -// --wasm-execution=Compiled -// --heap-pages=4096 -// --extrinsic=* -// --pallet=kilt-launch // --steps=50 // --repeat=20 -// --output -// ../../pallets/kilt-launch/src/default_weights.rs -// --template -// ../../.maintain/weight-template.hbs +// --pallet=kilt-launch +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=../../pallets/kilt-launch/src/default_weights.rs +// --template=../../.maintain/weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -61,46 +59,46 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn change_transfer_account() -> Weight { - (4_138_000_u64) + (3_757_000_u64) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn force_unlock(n: u32, ) -> Weight { - (25_007_000_u64) - // Standard Error: 111_000 - .saturating_add((45_497_000_u64).saturating_mul(n as Weight)) + (27_828_000_u64) + // Standard Error: 67_000 + .saturating_add((42_038_000_u64).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } fn locked_transfer() -> Weight { - (203_030_000_u64) + (185_829_000_u64) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } fn migrate_genesis_account_vesting() -> Weight { - (208_370_000_u64) + (210_436_000_u64) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } fn migrate_genesis_account_locking() -> Weight { - (214_892_000_u64) + (212_519_000_u64) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } fn migrate_multiple_genesis_accounts_vesting(n: u32, ) -> Weight { - (71_398_000_u64) - // Standard Error: 388_000 - .saturating_add((153_271_000_u64).saturating_mul(n as Weight)) + (42_458_000_u64) + // Standard Error: 212_000 + .saturating_add((142_227_000_u64).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } fn migrate_multiple_genesis_accounts_locking(n: u32, ) -> Weight { - (57_211_000_u64) - // Standard Error: 343_000 - .saturating_add((156_094_000_u64).saturating_mul(n as Weight)) + (59_886_000_u64) + // Standard Error: 225_000 + .saturating_add((144_149_000_u64).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -111,46 +109,46 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn change_transfer_account() -> Weight { - (4_138_000_u64) + (3_757_000_u64) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn force_unlock(n: u32, ) -> Weight { - (25_007_000_u64) - // Standard Error: 111_000 - .saturating_add((45_497_000_u64).saturating_mul(n as Weight)) + (27_828_000_u64) + // Standard Error: 67_000 + .saturating_add((42_038_000_u64).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } fn locked_transfer() -> Weight { - (203_030_000_u64) + (185_829_000_u64) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } fn migrate_genesis_account_vesting() -> Weight { - (208_370_000_u64) + (210_436_000_u64) .saturating_add(RocksDbWeight::get().reads(9_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } fn migrate_genesis_account_locking() -> Weight { - (214_892_000_u64) + (212_519_000_u64) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } fn migrate_multiple_genesis_accounts_vesting(n: u32, ) -> Weight { - (71_398_000_u64) - // Standard Error: 388_000 - .saturating_add((153_271_000_u64).saturating_mul(n as Weight)) + (42_458_000_u64) + // Standard Error: 212_000 + .saturating_add((142_227_000_u64).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(3_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } fn migrate_multiple_genesis_accounts_locking(n: u32, ) -> Weight { - (57_211_000_u64) - // Standard Error: 343_000 - .saturating_add((156_094_000_u64).saturating_mul(n as Weight)) + (59_886_000_u64) + // Standard Error: 225_000 + .saturating_add((144_149_000_u64).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().reads((5_u64).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(4_u64)) diff --git a/pallets/kilt-launch/src/lib.rs b/pallets/kilt-launch/src/lib.rs index 5c626df6fa..690df5abd6 100644 --- a/pallets/kilt-launch/src/lib.rs +++ b/pallets/kilt-launch/src/lib.rs @@ -134,6 +134,7 @@ pub mod pallet { use pallet_balances::{BalanceLock, Locks}; use pallet_vesting::{Vesting, VestingInfo}; use sp_runtime::traits::{CheckedDiv, Convert, SaturatedConversion, Saturating}; + use sp_std::convert::TryInto; pub const KILT_LAUNCH_ID: LockIdentifier = *b"kiltlnch"; pub const VESTING_ID: LockIdentifier = *b"vesting "; @@ -291,7 +292,7 @@ pub mod pallet { _, Blake2_128Concat, ::BlockNumber, - Vec<::AccountId>, + BoundedVec<::AccountId, ::MaxClaims>, >; /// Maps an account id to the (block, balance) pair in which the latter can @@ -341,7 +342,7 @@ pub mod pallet { ConflictingVestingStarts, /// When migrating multiple accounts to the same target, the size of the /// list of source addresses should never exceed `MaxClaims`. - ExceedsMaxClaims, + MaxClaimsExceeded, /// The source address does not have any balance lock at all which is /// required for `locked_transfer`. ExpectedLocks, @@ -520,7 +521,7 @@ pub mod pallet { ensure!( sources.len() < T::MaxClaims::get().saturated_into::(), - Error::::ExceedsMaxClaims + Error::::MaxClaimsExceeded ); let mut post_weight: Weight = 0; @@ -786,7 +787,7 @@ pub mod pallet { } else { // If no custom lock has been set up for target account, we can default to the // one of the source account and append it to `UnlockingAt` - >::append(unlock_block, &target); + >::try_append(unlock_block, &target).map_err(|_| Error::::MaxClaimsExceeded)?; max_add_amount }; @@ -810,12 +811,19 @@ pub mod pallet { // `max_amount` is set because else the source address is never added to // `UnlockingAt` if max_amount.is_some() { - let remove_source_map: Vec = >::take(unlock_block) - .unwrap_or_default() - .into_iter() - .filter(|acc_id| acc_id != source) - .collect(); - >::insert(unlock_block, remove_source_map); + >::try_mutate(unlock_block, |maybe_bv| -> DispatchResult { + if let Some(bv) = maybe_bv { + *bv = bv + .clone() + .into_inner() + .into_iter() + .filter(|acc_id| acc_id != source) + .collect::>() + .try_into() + .map_err(|_| Error::::MaxClaimsExceeded)? + } + Ok(()) + })?; } } else { // Reduce the locked amount diff --git a/pallets/kilt-launch/src/mock.rs b/pallets/kilt-launch/src/mock.rs index b6f627d900..8d0051b4ce 100644 --- a/pallets/kilt-launch/src/mock.rs +++ b/pallets/kilt-launch/src/mock.rs @@ -185,8 +185,10 @@ pub fn ensure_single_migration_works( if lock.block > now { assert_eq!(kilt_launch::BalanceLocks::::get(dest), Some(lock.clone())); assert_eq!( - kilt_launch::UnlockingAt::::get(lock.block), - Some(vec![dest.to_owned()]) + kilt_launch::UnlockingAt::::get(lock.block) + .unwrap_or_default() + .into_inner(), + vec![dest.to_owned()] ); locked_balance = locked_balance.max(lock.amount); num_of_locks += 1; diff --git a/pallets/kilt-launch/src/tests.rs b/pallets/kilt-launch/src/tests.rs index 0aa327934e..f4ea3b4f22 100644 --- a/pallets/kilt-launch/src/tests.rs +++ b/pallets/kilt-launch/src/tests.rs @@ -249,7 +249,10 @@ fn check_migrate_accounts_locked() { )); // Check unlocking info migration - assert_eq!(UnlockingAt::::get(100), Some(vec![USER])); + assert_eq!( + UnlockingAt::::get(100).unwrap_or_default().into_inner(), + vec![USER] + ); assert_eq!(BalanceLocks::::get(&USER), Some(locked_info.clone())); // Check correct setting of lock @@ -354,7 +357,7 @@ fn check_locked_transfer() { reasons: Reasons::All, }] ); - assert_eq!(UnlockingAt::::get(100), Some(vec![USER, PSEUDO_1])); + assert_eq!(UnlockingAt::::get(100).unwrap_or_default().into_inner(), vec![USER, PSEUDO_1]); assert_balance(PSEUDO_1, locked_info.amount - 3000, 0, 0, false); // Locked_Transfer rest @@ -370,7 +373,7 @@ fn check_locked_transfer() { ); assert!(BalanceLocks::::get(&USER).is_none()); assert_eq!(BalanceLocks::::get(&PSEUDO_1), Some(locked_info.clone())); - assert_eq!(UnlockingAt::::get(100), Some(vec![PSEUDO_1])); + assert_eq!(UnlockingAt::::get(100).unwrap_or_default().into_inner(), vec![PSEUDO_1]); assert_balance(PSEUDO_1, locked_info.amount, 0, 0, false); // Reach balance lock limit @@ -570,7 +573,7 @@ fn check_negative_migrate_accounts_vested() { vec![PSEUDO_1, PSEUDO_2, PSEUDO_3, PSEUDO_4], USER ), - Error::::ExceedsMaxClaims + Error::::MaxClaimsExceeded ); // Set up vesting with conflicting start block diff --git a/pallets/parachain-staking/src/benchmarking.rs b/pallets/parachain-staking/src/benchmarking.rs index 1e4d46c7aa..73d172b2f5 100644 --- a/pallets/parachain-staking/src/benchmarking.rs +++ b/pallets/parachain-staking/src/benchmarking.rs @@ -58,7 +58,8 @@ fn setup_collator_candidates( } CandidatePool::::get() - .into_vec() + .into_bounded_vec() + .into_inner() .drain(..) .map(|c| c.owner) .collect() @@ -401,7 +402,7 @@ benchmarks! { // make sure delegator collated to collator let state = >::get(&collator).unwrap(); - let delegator = state.delegators.into_vec()[0].owner.clone(); + let delegator = state.delegators.into_bounded_vec()[0].owner.clone(); assert_eq!(>::get(&delegator).unwrap().total, amount); // increase stake so we can unstake, because current stake is minimum @@ -435,7 +436,7 @@ benchmarks! { // make sure delegator collated to collator let state = >::get(&collator).unwrap(); - let delegator = state.delegators.into_vec()[0].owner.clone(); + let delegator = state.delegators.into_bounded_vec()[0].owner.clone(); assert_eq!(>::get(&delegator).unwrap().total, T::MinDelegatorStake::get()); // increase stake so we can unstake, because current stake is minimum @@ -471,7 +472,7 @@ benchmarks! { // make sure delegator collated to collator let state = >::get(&collator).unwrap(); - let delegator = state.delegators.into_vec()[0].owner.clone(); + let delegator = state.delegators.into_bounded_vec()[0].owner.clone(); assert_eq!(>::get(&delegator).unwrap().total, T::MinDelegatorStake::get()); // increase stake so we can unstake, because current stake is minimum @@ -507,7 +508,7 @@ benchmarks! { // make sure delegator collated to collator let state = >::get(&collator).unwrap(); - let delegator = state.delegators.into_vec()[0].owner.clone(); + let delegator = state.delegators.into_bounded_vec()[0].owner.clone(); assert_eq!(>::get(&delegator).unwrap().total, T::MinDelegatorStake::get()); // increase stake so we can unstake, because current stake is minimum @@ -605,7 +606,7 @@ benchmarks! { // // make sure delegator collated to collator_delegated // let state_delegated = >::get(&collator_delegated).unwrap(); - // let delegator = state_delegated.delegators.into_vec()[0].owner.clone(); + // let delegator = state_delegated.delegators.into_bounded_vec()[0].owner.clone(); // assert!(>::get(&delegator).is_some()); // // should not have delegated to collator yet diff --git a/pallets/parachain-staking/src/default_weights.rs b/pallets/parachain-staking/src/default_weights.rs index a401b3df9f..b095d25060 100644 --- a/pallets/parachain-staking/src/default_weights.rs +++ b/pallets/parachain-staking/src/default_weights.rs @@ -19,24 +19,22 @@ //! Autogenerated weights for parachain_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-07-09, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("spiritnet-dev"), DB CACHE: 128 +//! DATE: 2021-08-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: // /home/willi/mashnet-node/target/release/kilt-parachain // benchmark -// --chain=spiritnet-dev -// --execution=wasm -// --wasm-execution=Compiled -// --heap-pages=4096 -// --extrinsic=* -// --pallet=parachain_staking +// --chain=dev // --steps=50 // --repeat=20 -// --output -// ../../pallets/parachain-staking/src/default_weights.rs -// --template -// ../../.maintain/weight-template.hbs +// --pallet=parachain-staking +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=../../pallets/parachain-staking/src/default_weights.rs +// --template=../../.maintain/weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -76,179 +74,178 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn on_initialize_no_action() -> Weight { - (6_623_000_u64) + (6_853_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn on_initialize_round_update() -> Weight { - (25_949_000_u64) + (30_216_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn on_initialize_new_year() -> Weight { - (50_535_000_u64) + (56_085_000_u64) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } fn force_new_round() -> Weight { - (11_933_000_u64) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(2_u64)) + (3_847_000_u64) + .saturating_add(T::DbWeight::get().writes(1_u64)) } fn set_inflation() -> Weight { - (23_353_000_u64) + (28_523_000_u64) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn set_max_selected_candidates(n: u32, m: u32, ) -> Weight { (0_u64) - // Standard Error: 70_000 - .saturating_add((24_079_000_u64).saturating_mul(n as Weight)) - // Standard Error: 197_000 - .saturating_add((14_997_000_u64).saturating_mul(m as Weight)) + // Standard Error: 61_000 + .saturating_add((25_089_000_u64).saturating_mul(n as Weight)) + // Standard Error: 172_000 + .saturating_add((16_276_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(4_u64)) } fn set_blocks_per_round() -> Weight { - (30_818_000_u64) + (30_918_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn force_remove_candidate(n: u32, m: u32, ) -> Weight { - (256_842_000_u64) - // Standard Error: 61_000 - .saturating_add((2_473_000_u64).saturating_mul(n as Weight)) - // Standard Error: 168_000 - .saturating_add((37_184_000_u64).saturating_mul(m as Weight)) + (206_999_000_u64) + // Standard Error: 74_000 + .saturating_add((3_498_000_u64).saturating_mul(n as Weight)) + // Standard Error: 205_000 + .saturating_add((40_964_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(24_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(m as Weight))) .saturating_add(T::DbWeight::get().writes(7_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(m as Weight))) } fn join_candidates(n: u32, m: u32, ) -> Weight { - (179_642_000_u64) - // Standard Error: 88_000 - .saturating_add((3_917_000_u64).saturating_mul(n as Weight)) - // Standard Error: 320_000 - .saturating_add((8_823_000_u64).saturating_mul(m as Weight)) + (192_349_000_u64) + // Standard Error: 93_000 + .saturating_add((4_159_000_u64).saturating_mul(n as Weight)) + // Standard Error: 340_000 + .saturating_add((9_366_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(17_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } fn init_leave_candidates(n: u32, m: u32, ) -> Weight { - (314_776_000_u64) - // Standard Error: 24_000 - .saturating_add((1_456_000_u64).saturating_mul(n as Weight)) - // Standard Error: 65_000 - .saturating_add((5_965_000_u64).saturating_mul(m as Weight)) + (336_470_000_u64) + // Standard Error: 27_000 + .saturating_add((1_636_000_u64).saturating_mul(n as Weight)) + // Standard Error: 74_000 + .saturating_add((6_236_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(21_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } fn cancel_leave_candidates(n: u32, m: u32, ) -> Weight { - (316_316_000_u64) - // Standard Error: 26_000 - .saturating_add((1_351_000_u64).saturating_mul(n as Weight)) - // Standard Error: 71_000 - .saturating_add((5_840_000_u64).saturating_mul(m as Weight)) + (338_223_000_u64) + // Standard Error: 29_000 + .saturating_add((1_468_000_u64).saturating_mul(n as Weight)) + // Standard Error: 78_000 + .saturating_add((6_225_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(19_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } fn execute_leave_candidates(n: u32, m: u32, u: u32, ) -> Weight { (0_u64) - // Standard Error: 49_000 - .saturating_add((2_355_000_u64).saturating_mul(n as Weight)) - // Standard Error: 134_000 - .saturating_add((34_131_000_u64).saturating_mul(m as Weight)) - // Standard Error: 589_000 - .saturating_add((467_000_u64).saturating_mul(u as Weight)) + // Standard Error: 35_000 + .saturating_add((2_270_000_u64).saturating_mul(n as Weight)) + // Standard Error: 96_000 + .saturating_add((36_246_000_u64).saturating_mul(m as Weight)) + // Standard Error: 422_000 + .saturating_add((1_090_000_u64).saturating_mul(u as Weight)) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(m as Weight))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(m as Weight))) } fn candidate_stake_more(n: u32, m: u32, u: u32, ) -> Weight { - (108_582_000_u64) - // Standard Error: 87_000 - .saturating_add((3_870_000_u64).saturating_mul(n as Weight)) - // Standard Error: 323_000 - .saturating_add((8_787_000_u64).saturating_mul(m as Weight)) - // Standard Error: 1_070_000 - .saturating_add((6_961_000_u64).saturating_mul(u as Weight)) + (115_540_000_u64) + // Standard Error: 90_000 + .saturating_add((4_227_000_u64).saturating_mul(n as Weight)) + // Standard Error: 335_000 + .saturating_add((9_456_000_u64).saturating_mul(m as Weight)) + // Standard Error: 1_113_000 + .saturating_add((6_654_000_u64).saturating_mul(u as Weight)) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } fn candidate_stake_less(n: u32, m: u32, ) -> Weight { - (125_060_000_u64) - // Standard Error: 91_000 - .saturating_add((3_814_000_u64).saturating_mul(n as Weight)) - // Standard Error: 332_000 - .saturating_add((8_699_000_u64).saturating_mul(m as Weight)) + (140_434_000_u64) + // Standard Error: 93_000 + .saturating_add((4_100_000_u64).saturating_mul(n as Weight)) + // Standard Error: 341_000 + .saturating_add((8_914_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } fn join_delegators(n: u32, m: u32, ) -> Weight { - (181_776_000_u64) - // Standard Error: 91_000 - .saturating_add((4_046_000_u64).saturating_mul(n as Weight)) - // Standard Error: 376_000 - .saturating_add((9_952_000_u64).saturating_mul(m as Weight)) + (193_909_000_u64) + // Standard Error: 101_000 + .saturating_add((4_337_000_u64).saturating_mul(n as Weight)) + // Standard Error: 417_000 + .saturating_add((10_629_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(18_u64)) .saturating_add(T::DbWeight::get().writes(9_u64)) } fn delegator_stake_more(n: u32, m: u32, u: u32, ) -> Weight { - (90_904_000_u64) - // Standard Error: 82_000 - .saturating_add((3_945_000_u64).saturating_mul(n as Weight)) - // Standard Error: 345_000 - .saturating_add((9_549_000_u64).saturating_mul(m as Weight)) - // Standard Error: 1_182_000 - .saturating_add((7_724_000_u64).saturating_mul(u as Weight)) + (116_048_000_u64) + // Standard Error: 91_000 + .saturating_add((4_135_000_u64).saturating_mul(n as Weight)) + // Standard Error: 382_000 + .saturating_add((9_973_000_u64).saturating_mul(m as Weight)) + // Standard Error: 1_308_000 + .saturating_add((7_593_000_u64).saturating_mul(u as Weight)) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } fn delegator_stake_less(n: u32, m: u32, ) -> Weight { - (132_451_000_u64) - // Standard Error: 87_000 - .saturating_add((3_822_000_u64).saturating_mul(n as Weight)) - // Standard Error: 360_000 - .saturating_add((9_176_000_u64).saturating_mul(m as Weight)) + (144_889_000_u64) + // Standard Error: 99_000 + .saturating_add((4_048_000_u64).saturating_mul(n as Weight)) + // Standard Error: 408_000 + .saturating_add((9_997_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } fn revoke_delegation(n: u32, m: u32, ) -> Weight { - (140_353_000_u64) - // Standard Error: 87_000 - .saturating_add((3_803_000_u64).saturating_mul(n as Weight)) - // Standard Error: 358_000 - .saturating_add((9_240_000_u64).saturating_mul(m as Weight)) + (152_499_000_u64) + // Standard Error: 92_000 + .saturating_add((4_120_000_u64).saturating_mul(n as Weight)) + // Standard Error: 381_000 + .saturating_add((9_819_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } fn leave_delegators(n: u32, m: u32, ) -> Weight { - (142_811_000_u64) - // Standard Error: 86_000 - .saturating_add((3_801_000_u64).saturating_mul(n as Weight)) - // Standard Error: 356_000 - .saturating_add((9_142_000_u64).saturating_mul(m as Weight)) + (153_615_000_u64) + // Standard Error: 93_000 + .saturating_add((4_178_000_u64).saturating_mul(n as Weight)) + // Standard Error: 385_000 + .saturating_add((9_744_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads(13_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } fn unlock_unstaked(u: u32, ) -> Weight { - (56_092_000_u64) - // Standard Error: 15_000 - .saturating_add((193_000_u64).saturating_mul(u as Weight)) + (60_311_000_u64) + // Standard Error: 50_000 + .saturating_add((413_000_u64).saturating_mul(u as Weight)) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } fn increase_max_candidate_stake_by() -> Weight { - (25_518_000_u64) + (29_014_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn decrease_max_candidate_stake_by(n: u32, m: u32, ) -> Weight { (0_u64) // Standard Error: 128_000 - .saturating_add((59_819_000_u64).saturating_mul(n as Weight)) + .saturating_add((63_038_000_u64).saturating_mul(n as Weight)) // Standard Error: 452_000 - .saturating_add((36_894_000_u64).saturating_mul(m as Weight)) + .saturating_add((39_172_000_u64).saturating_mul(m as Weight)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } @@ -257,179 +254,178 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn on_initialize_no_action() -> Weight { - (6_623_000_u64) + (6_853_000_u64) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn on_initialize_round_update() -> Weight { - (25_949_000_u64) + (30_216_000_u64) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn on_initialize_new_year() -> Weight { - (50_535_000_u64) + (56_085_000_u64) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } fn force_new_round() -> Weight { - (11_933_000_u64) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(2_u64)) + (3_847_000_u64) + .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn set_inflation() -> Weight { - (23_353_000_u64) + (28_523_000_u64) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn set_max_selected_candidates(n: u32, m: u32, ) -> Weight { (0_u64) - // Standard Error: 70_000 - .saturating_add((24_079_000_u64).saturating_mul(n as Weight)) - // Standard Error: 197_000 - .saturating_add((14_997_000_u64).saturating_mul(m as Weight)) + // Standard Error: 61_000 + .saturating_add((25_089_000_u64).saturating_mul(n as Weight)) + // Standard Error: 172_000 + .saturating_add((16_276_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes(4_u64)) } fn set_blocks_per_round() -> Weight { - (30_818_000_u64) + (30_918_000_u64) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn force_remove_candidate(n: u32, m: u32, ) -> Weight { - (256_842_000_u64) - // Standard Error: 61_000 - .saturating_add((2_473_000_u64).saturating_mul(n as Weight)) - // Standard Error: 168_000 - .saturating_add((37_184_000_u64).saturating_mul(m as Weight)) + (206_999_000_u64) + // Standard Error: 74_000 + .saturating_add((3_498_000_u64).saturating_mul(n as Weight)) + // Standard Error: 205_000 + .saturating_add((40_964_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(24_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(m as Weight))) .saturating_add(RocksDbWeight::get().writes(7_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(m as Weight))) } fn join_candidates(n: u32, m: u32, ) -> Weight { - (179_642_000_u64) - // Standard Error: 88_000 - .saturating_add((3_917_000_u64).saturating_mul(n as Weight)) - // Standard Error: 320_000 - .saturating_add((8_823_000_u64).saturating_mul(m as Weight)) + (192_349_000_u64) + // Standard Error: 93_000 + .saturating_add((4_159_000_u64).saturating_mul(n as Weight)) + // Standard Error: 340_000 + .saturating_add((9_366_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(17_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } fn init_leave_candidates(n: u32, m: u32, ) -> Weight { - (314_776_000_u64) - // Standard Error: 24_000 - .saturating_add((1_456_000_u64).saturating_mul(n as Weight)) - // Standard Error: 65_000 - .saturating_add((5_965_000_u64).saturating_mul(m as Weight)) + (336_470_000_u64) + // Standard Error: 27_000 + .saturating_add((1_636_000_u64).saturating_mul(n as Weight)) + // Standard Error: 74_000 + .saturating_add((6_236_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(21_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } fn cancel_leave_candidates(n: u32, m: u32, ) -> Weight { - (316_316_000_u64) - // Standard Error: 26_000 - .saturating_add((1_351_000_u64).saturating_mul(n as Weight)) - // Standard Error: 71_000 - .saturating_add((5_840_000_u64).saturating_mul(m as Weight)) + (338_223_000_u64) + // Standard Error: 29_000 + .saturating_add((1_468_000_u64).saturating_mul(n as Weight)) + // Standard Error: 78_000 + .saturating_add((6_225_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(19_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } fn execute_leave_candidates(n: u32, m: u32, u: u32, ) -> Weight { (0_u64) - // Standard Error: 49_000 - .saturating_add((2_355_000_u64).saturating_mul(n as Weight)) - // Standard Error: 134_000 - .saturating_add((34_131_000_u64).saturating_mul(m as Weight)) - // Standard Error: 589_000 - .saturating_add((467_000_u64).saturating_mul(u as Weight)) + // Standard Error: 35_000 + .saturating_add((2_270_000_u64).saturating_mul(n as Weight)) + // Standard Error: 96_000 + .saturating_add((36_246_000_u64).saturating_mul(m as Weight)) + // Standard Error: 422_000 + .saturating_add((1_090_000_u64).saturating_mul(u as Weight)) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(m as Weight))) .saturating_add(RocksDbWeight::get().writes(4_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(m as Weight))) } fn candidate_stake_more(n: u32, m: u32, u: u32, ) -> Weight { - (108_582_000_u64) - // Standard Error: 87_000 - .saturating_add((3_870_000_u64).saturating_mul(n as Weight)) - // Standard Error: 323_000 - .saturating_add((8_787_000_u64).saturating_mul(m as Weight)) - // Standard Error: 1_070_000 - .saturating_add((6_961_000_u64).saturating_mul(u as Weight)) + (115_540_000_u64) + // Standard Error: 90_000 + .saturating_add((4_227_000_u64).saturating_mul(n as Weight)) + // Standard Error: 335_000 + .saturating_add((9_456_000_u64).saturating_mul(m as Weight)) + // Standard Error: 1_113_000 + .saturating_add((6_654_000_u64).saturating_mul(u as Weight)) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } fn candidate_stake_less(n: u32, m: u32, ) -> Weight { - (125_060_000_u64) - // Standard Error: 91_000 - .saturating_add((3_814_000_u64).saturating_mul(n as Weight)) - // Standard Error: 332_000 - .saturating_add((8_699_000_u64).saturating_mul(m as Weight)) + (140_434_000_u64) + // Standard Error: 93_000 + .saturating_add((4_100_000_u64).saturating_mul(n as Weight)) + // Standard Error: 341_000 + .saturating_add((8_914_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } fn join_delegators(n: u32, m: u32, ) -> Weight { - (181_776_000_u64) - // Standard Error: 91_000 - .saturating_add((4_046_000_u64).saturating_mul(n as Weight)) - // Standard Error: 376_000 - .saturating_add((9_952_000_u64).saturating_mul(m as Weight)) + (193_909_000_u64) + // Standard Error: 101_000 + .saturating_add((4_337_000_u64).saturating_mul(n as Weight)) + // Standard Error: 417_000 + .saturating_add((10_629_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(18_u64)) .saturating_add(RocksDbWeight::get().writes(9_u64)) } fn delegator_stake_more(n: u32, m: u32, u: u32, ) -> Weight { - (90_904_000_u64) - // Standard Error: 82_000 - .saturating_add((3_945_000_u64).saturating_mul(n as Weight)) - // Standard Error: 345_000 - .saturating_add((9_549_000_u64).saturating_mul(m as Weight)) - // Standard Error: 1_182_000 - .saturating_add((7_724_000_u64).saturating_mul(u as Weight)) + (116_048_000_u64) + // Standard Error: 91_000 + .saturating_add((4_135_000_u64).saturating_mul(n as Weight)) + // Standard Error: 382_000 + .saturating_add((9_973_000_u64).saturating_mul(m as Weight)) + // Standard Error: 1_308_000 + .saturating_add((7_593_000_u64).saturating_mul(u as Weight)) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } fn delegator_stake_less(n: u32, m: u32, ) -> Weight { - (132_451_000_u64) - // Standard Error: 87_000 - .saturating_add((3_822_000_u64).saturating_mul(n as Weight)) - // Standard Error: 360_000 - .saturating_add((9_176_000_u64).saturating_mul(m as Weight)) + (144_889_000_u64) + // Standard Error: 99_000 + .saturating_add((4_048_000_u64).saturating_mul(n as Weight)) + // Standard Error: 408_000 + .saturating_add((9_997_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } fn revoke_delegation(n: u32, m: u32, ) -> Weight { - (140_353_000_u64) - // Standard Error: 87_000 - .saturating_add((3_803_000_u64).saturating_mul(n as Weight)) - // Standard Error: 358_000 - .saturating_add((9_240_000_u64).saturating_mul(m as Weight)) + (152_499_000_u64) + // Standard Error: 92_000 + .saturating_add((4_120_000_u64).saturating_mul(n as Weight)) + // Standard Error: 381_000 + .saturating_add((9_819_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } fn leave_delegators(n: u32, m: u32, ) -> Weight { - (142_811_000_u64) - // Standard Error: 86_000 - .saturating_add((3_801_000_u64).saturating_mul(n as Weight)) - // Standard Error: 356_000 - .saturating_add((9_142_000_u64).saturating_mul(m as Weight)) + (153_615_000_u64) + // Standard Error: 93_000 + .saturating_add((4_178_000_u64).saturating_mul(n as Weight)) + // Standard Error: 385_000 + .saturating_add((9_744_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads(13_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } fn unlock_unstaked(u: u32, ) -> Weight { - (56_092_000_u64) - // Standard Error: 15_000 - .saturating_add((193_000_u64).saturating_mul(u as Weight)) + (60_311_000_u64) + // Standard Error: 50_000 + .saturating_add((413_000_u64).saturating_mul(u as Weight)) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } fn increase_max_candidate_stake_by() -> Weight { - (25_518_000_u64) + (29_014_000_u64) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn decrease_max_candidate_stake_by(n: u32, m: u32, ) -> Weight { (0_u64) // Standard Error: 128_000 - .saturating_add((59_819_000_u64).saturating_mul(n as Weight)) + .saturating_add((63_038_000_u64).saturating_mul(n as Weight)) // Standard Error: 452_000 - .saturating_add((36_894_000_u64).saturating_mul(m as Weight)) + .saturating_add((39_172_000_u64).saturating_mul(m as Weight)) .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(n as Weight))) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 5687dd836d..27d6757102 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -179,10 +179,12 @@ pub mod pallet { use frame_support::{ assert_ok, pallet_prelude::*, + storage::bounded_btree_map::BoundedBTreeMap, traits::{ Currency, EstimateNextSessionRotation, Get, Imbalance, LockIdentifier, LockableCurrency, ReservableCurrency, WithdrawReasons, }, + BoundedVec, }; use frame_system::pallet_prelude::*; use kilt_primitives::constants::BLOCKS_PER_YEAR; @@ -193,15 +195,17 @@ pub mod pallet { Permill, Perquintill, }; use sp_staking::SessionIndex; - use sp_std::{collections::btree_map::BTreeMap, prelude::*}; + use sp_std::prelude::*; use crate::{ + migrations::StakingStorageVersion, set::OrderedSet, types::{ - BalanceOf, Collator, CollatorOf, CollatorStatus, DelegationCounter, Delegator, Releases, RoundInfo, Stake, - StakeOf, TotalStake, + BalanceOf, Collator, CollatorOf, CollatorStatus, DelegationCounter, Delegator, RoundInfo, Stake, StakeOf, + TotalStake, }, }; + use sp_std::{convert::TryInto, fmt::Debug}; /// Kilt-specific lock for staking rewards. pub(crate) const STAKING_ID: LockIdentifier = *b"kiltpstk"; @@ -224,6 +228,7 @@ pub mod pallet { + ReservableCurrency + LockableCurrency + Eq; + /// Just the `Currency::Balance` type; we have this item to allow us to /// constrain it to `From`. /// Note: Definition taken from pallet_gilt @@ -237,49 +242,78 @@ pub mod pallet { + From + Into<::Balance> + From<::Balance>; + /// Minimum number of blocks validation rounds can last. + #[pallet::constant] type MinBlocksPerRound: Get; + /// Default number of blocks validation rounds last, as set in the /// genesis configuration. + #[pallet::constant] type DefaultBlocksPerRound: Get; /// Number of blocks for which unstaked balance will still be locked /// before it can be unlocked by actively calling the extrinsic /// `unlock_unstaked`. + #[pallet::constant] type StakeDuration: Get; /// Number of rounds a collator has to stay active after submitting a /// request to leave the set of collator candidates. + #[pallet::constant] type ExitQueueDelay: Get; + /// Minimum number of collators selected from the set of candidates at /// every validation round. + #[pallet::constant] type MinSelectedCandidates: Get; + /// Minimum number of collators which cannot leave the network if there /// are no others. + #[pallet::constant] type MinRequiredCollators: Get; + /// Maximum number of delegations which can be made within the same /// round. /// /// NOTE: To prevent re-delegation-reward attacks, we should keep this /// to be one. + #[pallet::constant] type MaxDelegationsPerRound: Get; + /// Maximum number of delegators a single collator can have. - type MaxDelegatorsPerCollator: Get; + #[pallet::constant] + type MaxDelegatorsPerCollator: Get + Debug + PartialEq; + /// Maximum number of collators a single delegator can delegate. - type MaxCollatorsPerDelegator: Get; + #[pallet::constant] + type MaxCollatorsPerDelegator: Get + Debug + PartialEq; + /// Maximum size of the collator candidates set. - type MaxCollatorCandidates: Get; + #[pallet::constant] + type MaxCollatorCandidates: Get + Debug + PartialEq; + /// Minimum stake required for any account to be elected as validator /// for a round. + #[pallet::constant] type MinCollatorStake: Get>; + /// Minimum stake required for any account to be added to the set of /// candidates. + #[pallet::constant] type MinCollatorCandidateStake: Get>; + /// Minimum stake required for any account to be able to delegate. + #[pallet::constant] type MinDelegation: Get>; + /// Minimum stake required for any account to become a delegator. + #[pallet::constant] type MinDelegatorStake: Get>; + /// Max number of concurrent active unstaking requests before /// unlocking. + #[pallet::constant] type MaxUnstakeRequests: Get; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } @@ -326,11 +360,11 @@ pub mod pallet { /// This protects against attacks in which a delegator can re-delegate /// from a collator who has already authored a block, to another one /// which has not in this round. - ExceededDelegationsPerRound, + DelegationsPerRoundExceeded, /// The collator candidate has already reached the maximum number of /// delegators. /// - /// This error is generated in cases a new delegation request does not + /// This error is generated in case a new delegation request does not /// stake enough funds to replace some other existing delegation. TooManyDelegators, /// The set of collator candidates has already reached the maximum size @@ -349,7 +383,7 @@ pub mod pallet { CannotDelegateIfLeaving, /// The delegator has already delegated the maximum number of candidates /// allowed. - ExceedMaxCollatorsPerDelegator, + MaxCollatorsPerDelegatorExceeded, /// The delegator has already previously delegated the collator /// candidate. AlreadyDelegatedCollator, @@ -485,40 +519,16 @@ pub mod pallet { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result<(), &'static str> { - log::debug!("[BEGIN] parachain-staking::pre_upgrade"); - let pre_migration_checks = match >::get() { - Releases::V1_0_0 => migrations::v2::pre_migrate::(), - Releases::V2_0_0 => migrations::v3::pre_migrate::(), - Releases::V3_0_0 => migrations::v4::pre_migrate::(), - Releases::V4 => Err("Already migrated"), - }; - log::debug!("[END] parachain-staking::pre_upgrade"); - pre_migration_checks + migrations::StakingStorageMigrator::::pre_migrate() } - #[allow(clippy::let_and_return)] fn on_runtime_upgrade() -> Weight { - #[cfg(feature = "try-runtime")] - log::debug!("[BEGIN] parachain-staking::on_runtime_upgrade"); - let weight = match >::get() { - Releases::V1_0_0 => migrations::v2::migrate::() - .saturating_add(migrations::v3::migrate::()) - .saturating_add(migrations::v4::migrate::()), - Releases::V2_0_0 => migrations::v3::migrate::().saturating_add(migrations::v4::migrate::()), - Releases::V3_0_0 => migrations::v4::migrate::(), - Releases::V4 => Weight::zero(), - } - .saturating_add(T::DbWeight::get().reads(1)); - log::debug!("[END] parachain-staking::on_runtime_upgrade"); - weight + migrations::StakingStorageMigrator::::migrate() } #[cfg(feature = "try-runtime")] fn post_upgrade() -> Result<(), &'static str> { - log::debug!("[BEGIN] parachain-staking::post_upgrade"); - let post_migration_checks = migrations::v4::post_migrate::(); - log::debug!("[END] parachain-staking::post_upgrade"); - post_migration_checks + migrations::StakingStorageMigrator::::post_migrate() } } @@ -527,7 +537,7 @@ pub mod pallet { /// /// This is set to v2.0.0 for new networks. #[pallet::storage] - pub(crate) type StorageVersion = StorageValue<_, Releases, ValueQuery>; + pub(crate) type StorageVersion = StorageValue<_, StakingStorageVersion, ValueQuery>; /// The maximum number of collator candidates selected at each round. #[pallet::storage] @@ -554,21 +564,32 @@ pub mod pallet { /// It maps from an account to its delegation details. #[pallet::storage] #[pallet::getter(fn delegator_state)] - pub(crate) type DelegatorState = - StorageMap<_, Twox64Concat, T::AccountId, Delegator>, OptionQuery>; + pub(crate) type DelegatorState = StorageMap< + _, + Twox64Concat, + T::AccountId, + Delegator, T::MaxCollatorsPerDelegator>, + OptionQuery, + >; /// Collator candidates staking information. /// /// It maps from an account to its collator details. #[pallet::storage] #[pallet::getter(fn collator_state)] - pub(crate) type CollatorState = - StorageMap<_, Twox64Concat, T::AccountId, Collator>, OptionQuery>; + pub(crate) type CollatorState = StorageMap< + _, + Twox64Concat, + T::AccountId, + Collator, T::MaxDelegatorsPerCollator>, + OptionQuery, + >; /// The collator candidates selected for the latest validation round. #[pallet::storage] #[pallet::getter(fn selected_candidates)] - pub(crate) type SelectedCandidates = StorageValue<_, Vec, ValueQuery>; + pub(crate) type SelectedCandidates = + StorageValue<_, BoundedVec, ValueQuery>; /// Total funds locked by this staking pallet. #[pallet::storage] @@ -579,7 +600,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn candidate_pool)] pub(crate) type CandidatePool = - StorageValue<_, OrderedSet>>, ValueQuery>; + StorageValue<_, OrderedSet>, T::MaxCollatorCandidates>, ValueQuery>; /// Inflation configuration. #[pallet::storage] @@ -592,8 +613,13 @@ pub mod pallet { /// blocks. #[pallet::storage] #[pallet::getter(fn unstaking)] - pub(crate) type Unstaking = - StorageMap<_, Twox64Concat, T::AccountId, BTreeMap>, ValueQuery>; + pub(crate) type Unstaking = StorageMap< + _, + Twox64Concat, + T::AccountId, + BoundedBTreeMap, T::MaxUnstakeRequests>, + ValueQuery, + >; /// The maximum amount a collator candidate can stake. #[pallet::storage] @@ -965,7 +991,7 @@ pub mod pallet { >::put(candidates); } - Self::remove_candidate(&collator, state); + Self::remove_candidate(&collator, state)?; // update candidates for next round let (num_collators, num_delegators, _, _) = Self::select_top_candidates(); @@ -1017,7 +1043,6 @@ pub mod pallet { let acc = ensure_signed(origin)?; let is_active_candidate = Self::is_active_candidate(&acc); ensure!(is_active_candidate.unwrap_or(true), Error::::AlreadyLeaving); - ensure!(is_active_candidate.is_none(), Error::::CandidateExists); ensure!(!Self::is_delegator(&acc), Error::::DelegatorExists); ensure!( stake >= T::MinCollatorCandidateStake::get(), @@ -1029,20 +1054,24 @@ pub mod pallet { ); let mut candidates = >::get(); - // should never fail but let's be safe - ensure!( - candidates.insert(Stake { - owner: acc.clone(), - amount: stake - }), - Error::::CandidateExists - ); - // [Post-launch TODO] Replace with `check_collator_candidate_inclusion`. ensure!( - (candidates.len().saturated_into::()) <= T::MaxCollatorCandidates::get(), + (candidates.len().saturated_into::()) < T::MaxCollatorCandidates::get(), Error::::TooManyCollatorCandidates ); + + // attempt to insert candidate and check for excess + // NOTE: We don't support replacing a candidate with fewer stake in case of + // excess right now, but will be in future. + let insert_candidate = candidates + .try_insert(Stake { + owner: acc.clone(), + amount: stake, + }) + .map_err(|_| Error::::TooManyCollatorCandidates)?; + // should never fail but let's be safe + ensure!(insert_candidate, Error::::CandidateExists); + Self::increase_lock(&acc, stake, BalanceOf::::zero())?; let candidate = Collator::new(acc.clone(), stake); @@ -1175,7 +1204,7 @@ pub mod pallet { let num_delegators = state.delegators.len().saturated_into::(); let total_amount = state.total; - Self::remove_candidate(&collator, state); + Self::remove_candidate(&collator, state)?; Self::deposit_event(Event::CollatorLeft(collator, total_amount)); @@ -1225,14 +1254,19 @@ pub mod pallet { (candidates.len().saturated_into::()) < T::MaxCollatorCandidates::get(), Error::::TooManyCollatorCandidates ); - // should never fail but let's be safe - ensure!( - candidates.insert(Stake { + + // attempt to insert candidate and check for excess + // NOTE: We don't support replacing a candidate with fewer stake in case of + // excess right now, but will be in future. + let insert_candidate = candidates + .try_insert(Stake { owner: acc.clone(), amount: state.total, - }), - Error::::CandidateExists - ); + }) + .map_err(|_| Error::::TooManyCollatorCandidates)?; + // should never fail but let's be safe + ensure!(insert_candidate, Error::::CandidateExists); + // revert leaving state state.revert_leaving(); @@ -1295,7 +1329,7 @@ pub mod pallet { let unstaking_len = Self::increase_lock(&collator, after, more)?; if state.is_active() { - Self::update(collator.clone(), state.total); + Self::update(collator.clone(), state.total)?; } >::insert(&collator, state); @@ -1357,7 +1391,7 @@ pub mod pallet { Self::prep_unstake(&collator, less)?; if state.is_active() { - Self::update(collator.clone(), state.total); + Self::update(collator.clone(), state.total)?; } >::insert(&collator, state); @@ -1391,6 +1425,9 @@ pub mod pallet { /// increased accordingly. /// /// Emits `Delegation`. + /// Emits `DelegationReplaced` if the candidate has + /// `MaxDelegatorsPerCollator` many delegations but this delegator + /// staked more than one of the other delegators of this candidate. /// /// # /// - The transaction's complexity is mainly dependent on updating the @@ -1426,26 +1463,33 @@ pub mod pallet { // prepare update of collator state let mut state = >::get(&collator).ok_or(Error::::CandidateNotFound)?; + let num_delegations_pre_insertion: u32 = state.delegators.len().saturated_into(); + ensure!(!state.is_leaving(), Error::::CannotDelegateIfLeaving); let delegation = Stake { owner: acc.clone(), amount, }; + + // attempt to insert delegator and check for uniqueness + // NOTE: excess is handled below because we support replacing a delegator with + // fewer stake + let insert_delegator = state + .delegators + // we handle TooManyDelegators error below in do_update_delegator + .try_insert(delegation.clone()) + .unwrap_or(true); // should never fail but let's be safe - ensure!(state.delegators.insert(delegation.clone()), Error::::DelegatorExists); + ensure!(insert_delegator, Error::::DelegatorExists); + + // can only throw if MaxCollatorsPerDelegator is set to 0 which should never + // occur in practice, even if the delegator rewards are set to 0 + let delegator_state = Delegator::try_new(collator.clone(), amount) + .map_err(|_| Error::::MaxCollatorsPerDelegatorExceeded)?; // update state and potentially kick a delegator with less staked amount - state = if (state.delegators.len().saturated_into::()) > T::MaxDelegatorsPerCollator::get() { - let (new_state, replaced_delegation) = Self::do_update_delegator(delegation.clone(), state)?; - Self::deposit_event(Event::DelegationReplaced( - delegation.owner, - delegation.amount, - replaced_delegation.owner, - replaced_delegation.amount, - new_state.id.clone(), - new_state.total, - )); - new_state + state = if num_delegations_pre_insertion == T::MaxDelegatorsPerCollator::get() { + Self::do_update_delegator(delegation, state)? } else { state.total = state.total.saturating_add(amount); state @@ -1455,12 +1499,12 @@ pub mod pallet { // lock stake Self::increase_lock(&acc, amount, BalanceOf::::zero())?; if state.is_active() { - Self::update(collator.clone(), new_total); + Self::update(collator.clone(), new_total)?; } // update states >::insert(&collator, state); - >::insert(&acc, Delegator::new(collator.clone(), amount)); + >::insert(&acc, delegator_state); >::insert(&acc, delegation_counter); // update candidates for next round @@ -1501,6 +1545,9 @@ pub mod pallet { /// set to one. /// /// Emits `Delegation`. + /// Emits `DelegationReplaced` if the candidate has + /// `MaxDelegatorsPerCollator` many delegations but this delegator + /// staked more than one of the other delegators of this candidate. /// /// # /// - The transaction's complexity is mainly dependent on updating the @@ -1533,7 +1580,7 @@ pub mod pallet { ensure!(amount >= T::MinDelegation::get(), Error::::DelegationBelowMin); ensure!( (delegator.delegations.len().saturated_into::()) < T::MaxCollatorsPerDelegator::get(), - Error::::ExceedMaxCollatorsPerDelegator + Error::::MaxCollatorsPerDelegatorExceeded ); // cannot delegate if number of delegations in this round exceeds // MaxDelegationsPerRound @@ -1541,33 +1588,36 @@ pub mod pallet { // prepare new collator state let mut state = >::get(&collator).ok_or(Error::::CandidateNotFound)?; + let num_delegations_pre_insertion: u32 = state.delegators.len().saturated_into(); ensure!(!state.is_leaving(), Error::::CannotDelegateIfLeaving); + + // attempt to insert delegator and check for uniqueness + // NOTE: excess is handled below because we support replacing a delegator with + // fewer stake ensure!( - delegator.add_delegation(Stake { - owner: collator.clone(), - amount - }), + delegator + .add_delegation(Stake { + owner: collator.clone(), + amount + }) + .unwrap_or(true), Error::::AlreadyDelegatedCollator ); let delegation = Stake { owner: acc.clone(), amount, }; - // should never fail but let's be safe - ensure!(state.delegators.insert(delegation.clone()), Error::::DelegatorExists); + + // throws if delegation insertion exceeds bounded vec limit which we will handle + // below in Self::do_update_delegator + ensure!( + state.delegators.try_insert(delegation.clone()).unwrap_or(true), + Error::::DelegatorExists + ); // update state and potentially kick a delegator with less staked amount - state = if (state.delegators.len().saturated_into::()) > T::MaxDelegatorsPerCollator::get() { - let (new_state, replaced_delegation) = Self::do_update_delegator(delegation.clone(), state)?; - Self::deposit_event(Event::DelegationReplaced( - delegation.owner, - delegation.amount, - replaced_delegation.owner, - replaced_delegation.amount, - new_state.id.clone(), - new_state.total, - )); - new_state + state = if num_delegations_pre_insertion == T::MaxDelegatorsPerCollator::get() { + Self::do_update_delegator(delegation, state)? } else { state.total = state.total.saturating_add(amount); state @@ -1577,7 +1627,7 @@ pub mod pallet { // lock stake Self::increase_lock(&acc, delegator.total, amount)?; if state.is_active() { - Self::update(collator.clone(), new_total); + Self::update(collator.clone(), new_total)?; } // Update states @@ -1745,7 +1795,7 @@ pub mod pallet { let after = collator.total; if collator.is_active() { - Self::update(candidate.clone(), collator.total); + Self::update(candidate.clone(), collator.total)?; } >::insert(&candidate, collator); >::insert(&delegator, delegations); @@ -1823,7 +1873,7 @@ pub mod pallet { collator.dec_delegator(delegator.clone(), less); let after = collator.total; if collator.is_active() { - Self::update(candidate.clone(), collator.total); + Self::update(candidate.clone(), collator.total)?; } >::insert(&candidate, collator); >::insert(&delegator, delegations); @@ -1912,14 +1962,18 @@ pub mod pallet { /// - Reads: CandidatePool /// - Writes: CandidatePool /// # - fn update(candidate: T::AccountId, total: BalanceOf) { + fn update(candidate: T::AccountId, total: BalanceOf) -> DispatchResult { let mut candidates = >::get(); - candidates.upsert(Stake { - owner: candidate, - amount: total, - }); + candidates + .try_upsert(Stake { + owner: candidate, + amount: total, + }) + .map_err(|_| Error::::TooManyCollatorCandidates)?; >::put(candidates); + + Ok(()) } /// Update the delegator's state by removing the collator candidate from @@ -1995,7 +2049,7 @@ pub mod pallet { Self::prep_unstake(&delegator, delegator_stake)?; if state.is_active() { - Self::update(collator.clone(), state.total); + Self::update(collator.clone(), state.total)?; } let new_total = state.total; >::insert(&collator, state); @@ -2099,8 +2153,8 @@ pub mod pallet { /// `MaxCollatorCandidates` /// - Reads: CandidatePool, CollatorState, SelectedCandidates /// # - fn get_collator_list(top_n: u32) -> Vec { - let mut candidates = >::get().into_vec(); + fn get_collator_list(top_n: u32) -> BoundedVec { + let mut candidates = >::get().into_bounded_vec().into_inner(); log::trace!("{} Candidates for {} Collator seats", candidates.len(), top_n); @@ -2123,9 +2177,11 @@ pub mod pallet { .collect::>(); // update pool - >::set(OrderedSet::from_sorted_set(candidates)); + >::set(OrderedSet::from_sorted_set( + candidates.try_into().expect("Did not extend Candidates"), + )); - collators + collators.try_into().expect("Did not extend Collators") } /// Attempts to add the stake to the set of delegators of a collator @@ -2136,6 +2192,9 @@ pub mod pallet { /// /// Returns the old delegation that is updated, if any. /// + /// Emits `DelegationReplaced` if the stake exceeds one of the current + /// delegations. + /// /// # /// Weight: O(D) where D is the number of delegators for this collator /// bounded by `MaxDelegatorsPerCollator`. @@ -2143,27 +2202,40 @@ pub mod pallet { /// # fn do_update_delegator( stake: Stake>, - mut state: Collator>, - ) -> Result<(CollatorOf, StakeOf), DispatchError> { - // add stake & sort by amount - let mut delegators: Vec>> = state.delegators.into(); - - // check whether stake is at last place - match delegators.pop() { - Some(stake_to_remove) if stake_to_remove.amount < stake.amount => { - state.total = state - .total - .saturating_sub(stake_to_remove.amount) - .saturating_add(stake.amount); - state.delegators = OrderedSet::from_sorted_set(delegators); - - // update storage of kicked delegator - Self::kick_delegator(&stake_to_remove, &state.id)?; - - Ok((state, stake_to_remove)) - } - _ => Err(Error::::TooManyDelegators.into()), - } + mut state: Collator, T::MaxDelegatorsPerCollator>, + ) -> Result, DispatchError> { + // attempt to replace the last element of the set + let stake_to_remove = state + .delegators + .try_insert_replace(stake.clone()) + .map_err(|err_too_many| { + if err_too_many { + Error::::TooManyDelegators + } else { + // should never occur because we previously check this case, but let's be sure + Error::::AlreadyDelegating + } + })?; + + // update total stake + state.total = state + .total + .saturating_sub(stake_to_remove.amount) + .saturating_add(stake.amount); + + // update storage of kicked delegator + Self::kick_delegator(&stake_to_remove, &state.id)?; + + Self::deposit_event(Event::DelegationReplaced( + stake.owner, + stake.amount, + stake_to_remove.owner, + stake_to_remove.amount, + state.id.clone(), + state.total, + )); + + Ok(state) } /// Either set or increase the BalanceLock of target account to @@ -2188,7 +2260,8 @@ pub mod pallet { // in unstaking in case that unstaking.sum > amount let mut total_locked: BalanceOf = Zero::zero(); let mut unstaking_len = 0u32; - >::mutate(who, |unstaking| { + + >::try_mutate(who, |unstaking| -> DispatchResult { // reduce {amount | more} by unstaking until either {amount | more} is zero or // no unstaking is left // if more is set, we only want to reduce by more to achieve 100 - 40 + 30 = 90 @@ -2202,7 +2275,9 @@ pub mod pallet { // amount is only reducible by locked_balance - amt_consuming_unstaking let delta = locked_balance.saturating_sub(amt_consuming_unstaking); // replace old entry with delta - unstaking.insert(block_number, delta); + unstaking + .try_insert(block_number, delta) + .map_err(|_| Error::::NoMoreUnstaking)?; amt_consuming_unstaking = Zero::zero(); total_locked = total_locked.saturating_add(locked_balance); } else { @@ -2212,7 +2287,8 @@ pub mod pallet { } unstaking_len = unstaking_len.saturating_add(1u32); } - }); + Ok(()) + })?; // Handle case of collator/delegator decreasing their stake and increasing // afterwards which results in amount != locked @@ -2249,7 +2325,7 @@ pub mod pallet { /// - Reads: BlockNumber, Unstaking /// - Writes: Unstaking /// # - fn prep_unstake(who: &T::AccountId, amount: BalanceOf) -> Result<(), DispatchError> { + fn prep_unstake(who: &T::AccountId, amount: BalanceOf) -> DispatchResult { // should never occur but let's be safe ensure!(!amount.is_zero(), Error::::StakeNotFound); @@ -2265,29 +2341,13 @@ pub mod pallet { // if existent, we have to add the current amount of same unlock_block, because // insert overwrites the current value let amount = amount.saturating_add(*unstaking.get(&unlock_block).unwrap_or(&BalanceOf::::zero())); - unstaking.insert(unlock_block, amount); + unstaking + .try_insert(unlock_block, amount) + .map_err(|_| Error::::NoMoreUnstaking)?; >::insert(who, unstaking); Ok(()) } - /// Prepare unstaking without checking for exceeding the unstake request - /// limit. Same as `prep_unstake` but without checking for errors. - /// - /// NOTE: Should only be called in `execute_leave_candidates`! - /// - /// # - /// Weight: O(1) - /// - Reads: BlockNumber, Unstaking - /// - Writes: Unstaking - /// # - fn prep_unstake_exit_queue(who: &T::AccountId, amount: BalanceOf) { - let now = >::block_number(); - let unlock_block = now.saturating_add(T::StakeDuration::get()); - let mut unstaking = >::get(who); - unstaking.insert(unlock_block, amount); - >::insert(who, unstaking); - } - /// Clear the CollatorState of the candidate and remove all delegations /// to the candidate. Moreover, prepare unstaking for the candidate and /// their former delegations. @@ -2300,11 +2360,14 @@ pub mod pallet { /// - Kills: CollatorState, DelegatorState for all delegators which only /// delegated to the candidate /// # - fn remove_candidate(collator: &T::AccountId, state: CollatorOf) { + fn remove_candidate( + collator: &T::AccountId, + state: CollatorOf, + ) -> DispatchResult { // iterate over delegators for stake in state.delegators.into_iter() { // prepare unstaking of delegator - Self::prep_unstake_exit_queue(&stake.owner, stake.amount); + Self::prep_unstake(&stake.owner, stake.amount)?; // remove delegation from delegator state if let Some(mut delegator) = >::get(&stake.owner) { if let Some(remaining) = delegator.rm_delegation(collator) { @@ -2317,7 +2380,7 @@ pub mod pallet { } } // prepare unstaking of collator candidate - Self::prep_unstake_exit_queue(&state.id, state.stake); + Self::prep_unstake(&state.id, state.stake)?; // disable validator for next session if they were in the set of validators pallet_session::Pallet::::validators() @@ -2334,6 +2397,7 @@ pub mod pallet { .map(pallet_session::Pallet::::disable_index); >::remove(&collator); + Ok(()) } /// Withdraw all staked currency which was unstaked at least @@ -2357,12 +2421,12 @@ pub mod pallet { let mut expired = Vec::new(); // check potential unlocks - for (block_number, locked_balance) in &unstaking { - if block_number <= &now { - expired.push(*block_number); - total_unlocked = total_unlocked.saturating_add(*locked_balance); + for (block_number, locked_balance) in unstaking.clone().into_iter() { + if block_number <= now { + expired.push(block_number); + total_unlocked = total_unlocked.saturating_add(locked_balance); } else { - total_locked = total_locked.saturating_add(*locked_balance); + total_locked = total_locked.saturating_add(locked_balance); } } for block_number in expired { @@ -2464,7 +2528,7 @@ pub mod pallet { ensure!( T::MaxDelegationsPerRound::get() > counter, - Error::::ExceededDelegationsPerRound + Error::::DelegationsPerRoundExceeded ); Ok(DelegationCounter { @@ -2480,8 +2544,8 @@ pub mod pallet { // /// set. On failure, an error is returned. removing an already existing // fn check_collator_candidate_inclusion( // stake: Stake>, - // mut candidates: OrderedSet>>, - // ) -> Result<(), DispatchError> { + // mut candidates: OrderedSet>, + // T::MaxCollatorCandidates>, ) -> Result<(), DispatchError> { // todo!() // } } @@ -2608,7 +2672,7 @@ pub mod pallet { // get top collator candidates which are updated in any transaction which // affects either the stake of collators or delegators, see // `select_top_candidates` for details - Some(>::get()) + Some(>::get().to_vec()) } fn end_session(_end_index: SessionIndex) { diff --git a/pallets/parachain-staking/src/migrations.rs b/pallets/parachain-staking/src/migrations.rs index d1f7669968..ceb56ed944 100644 --- a/pallets/parachain-staking/src/migrations.rs +++ b/pallets/parachain-staking/src/migrations.rs @@ -15,131 +15,236 @@ // along with this program. If not, see . // If you feel like getting in touch with us, you can do so at info@botlabs.org - -use crate::{ - inflation::InflationInfo, - pallet::*, - types::{BalanceOf, Releases}, -}; +#[cfg(feature = "try-runtime")] +use frame_support::ensure; use frame_support::{dispatch::Weight, traits::Get}; -use kilt_primitives::constants::MAX_COLLATOR_STAKE; -use sp_runtime::traits::Zero; - -pub mod v2 { +use sp_runtime::{ + codec::{Decode, Encode}, + traits::Zero, +}; +use sp_std::marker::PhantomData; + +use crate::*; + +mod v2; +mod v3; +mod v4; + +/// A trait that allows version migrators to access the underlying pallet's +/// context, e.g., its Config trait. +/// +/// In this way, the migrator can access the pallet's storage and the pallet's +/// types directly. +pub trait VersionMigratorTrait { + #[cfg(feature = "try-runtime")] + fn pre_migrate(&self) -> Result<(), &str>; + fn migrate(&self) -> Weight; + #[cfg(feature = "try-runtime")] + fn post_migrate(&self) -> Result<(), &str>; +} - use super::*; +// A value placed in storage that represents the current version of the Staking +// storage. This value is used by the `on_runtime_upgrade` logic to determine +// whether we run storage migration logic. This should match directly with the +// semantic versions of the Rust crate. +#[derive(Copy, Clone, Encode, Eq, Decode, Debug, Ord, PartialEq, PartialOrd)] +pub enum StakingStorageVersion { + V1_0_0, + V2_0_0, // New Reward calculation, MaxCollatorCandidateStake + V3_0_0, // Update InflationConfig + V4, // Sort CandidatePool and parachain-stakings by amount +} - pub fn pre_migrate() -> Result<(), &'static str> { - assert!( - MaxCollatorCandidateStake::::get().is_zero(), - "MaxCollatorCandidateStake already set." - ); - // should use default value if it has not existed before - assert_eq!(StorageVersion::::get(), Releases::V1_0_0); - Ok(()) +#[cfg(feature = "try-runtime")] +impl StakingStorageVersion { + /// The latest storage version. + fn latest() -> Self { + Self::V4 } +} - pub fn migrate() -> Weight { - log::info!("Migrating staking to Releases::V2_0_0"); - - MaxCollatorCandidateStake::::put(BalanceOf::::from(MAX_COLLATOR_STAKE)); - - // update rewards per block - InflationConfig::::mutate(|inflation| { - *inflation = InflationInfo::new( - inflation.collator.max_rate, - inflation.collator.reward_rate.annual, - inflation.delegator.max_rate, - inflation.delegator.reward_rate.annual, - ); - }); +// All nodes will default to this, which is not bad, as in case the "real" +// version is a later one (i.e. the node has been started with already the +// latest version), the migration will simply do nothing as there's nothing in +// the old storage entries to migrate from. +// +// It might get updated in the future when we know that no node is running this +// old version anymore. +impl Default for StakingStorageVersion { + fn default() -> Self { + Self::V4 + } +} - StorageVersion::::put(Releases::V2_0_0); - log::info!("Completed staking migration to Releases::V2_0_0"); +impl VersionMigratorTrait for StakingStorageVersion { + // It runs the right pre_migrate logic depending on the current storage version. + #[cfg(feature = "try-runtime")] + fn pre_migrate(&self) -> Result<(), &str> { + match *self { + Self::V1_0_0 => v2::pre_migrate::(), + Self::V2_0_0 => v3::pre_migrate::(), + Self::V3_0_0 => v4::pre_migrate::(), + Self::V4 => Err("Already on latest version v4."), + } + } - T::DbWeight::get().reads_writes(1, 3) + // It runs the right migration logic depending on the current storage version. + fn migrate(&self) -> Weight { + match *self { + Self::V1_0_0 => v2::migrate::(), + Self::V2_0_0 => v3::migrate::(), + Self::V3_0_0 => v4::migrate::(), + Self::V4 => Weight::zero(), + } } - pub fn post_migrate() -> Result<(), &'static str> { - assert_eq!( - MaxCollatorCandidateStake::::get(), - BalanceOf::::from(MAX_COLLATOR_STAKE) - ); - assert_eq!(StorageVersion::::get(), Releases::V2_0_0); - Ok(()) + // It runs the right post_migrate logic depending on the current storage + // version. + #[cfg(feature = "try-runtime")] + fn post_migrate(&self) -> Result<(), &str> { + match *self { + Self::V1_0_0 => v2::post_migrate::(), + Self::V2_0_0 => v3::post_migrate::(), + Self::V3_0_0 => v4::post_migrate::(), + Self::V4 => Err("Migration from v4 should have never happened in the first place."), + } } } -pub mod v3 { - use kilt_primitives::constants::INFLATION_CONFIG; - - use super::*; - - pub fn pre_migrate() -> Result<(), &'static str> { - assert_eq!(StorageVersion::::get(), Releases::V2_0_0); - Ok(()) +/// The parachain-staking pallet's storage migrator, which handles all version +/// migrations in a sequential fashion. +/// +/// If a node has missed on more than one upgrade, the migrator will apply the +/// needed migrations one after the other. Otherwise, if no migration is needed, +/// the migrator will simply not do anything. +pub struct StakingStorageMigrator(PhantomData); + +impl StakingStorageMigrator { + // Contains the migration sequence logic. + fn get_next_storage_version(current: StakingStorageVersion) -> Option { + match current { + StakingStorageVersion::V1_0_0 => Some(StakingStorageVersion::V2_0_0), + StakingStorageVersion::V2_0_0 => Some(StakingStorageVersion::V3_0_0), + // Migration happens naturally, no need to point to the latest version + StakingStorageVersion::V3_0_0 => None, + StakingStorageVersion::V4 => None, + } } - pub fn migrate() -> Weight { - log::info!("Migrating staking to Releases::V3_0_0"); - - // update rewards per block - InflationConfig::::mutate(|inflation| *inflation = InflationInfo::from(INFLATION_CONFIG)); + /// Checks whether the latest storage version deployed is lower than the + /// latest possible. + #[cfg(feature = "try-runtime")] + pub(crate) fn pre_migrate() -> Result<(), &'static str> { + ensure!( + StorageVersion::::get() < StakingStorageVersion::latest(), + "Already the latest storage version." + ); - StorageVersion::::put(Releases::V3_0_0); - log::info!("Completed staking migration to Releases::V3_0_0"); + // Don't need to check for any other pre_migrate, as in try-runtime it is also + // called in the migrate() function. Same applies for post_migrate checks for + // each version migrator. - T::DbWeight::get().reads_writes(1, 2) + Ok(()) } - pub fn post_migrate() -> Result<(), &'static str> { - assert_eq!(InflationConfig::::get(), InflationInfo::from(INFLATION_CONFIG)); - assert_eq!(StorageVersion::::get(), Releases::V3_0_0); - Ok(()) + /// Applies all the needed migrations from the currently deployed version to + /// the latest possible, one after the other. + /// + /// It returns the total weight consumed by ALL the migrations applied. + pub(crate) fn migrate() -> Weight { + let mut current_version: Option = Some(StorageVersion::::get()); + // Weight for StorageVersion::get(). + let mut total_weight = T::DbWeight::get().reads(1); + + while let Some(ver) = current_version { + // If any of the needed migrations pre-checks fail, the whole chain panics + // (during tests). + #[cfg(feature = "try-runtime")] + if let Err(err) = >::pre_migrate(&ver) { + panic!("{:?}", err); + } + let consumed_weight = >::migrate(&ver); + total_weight = total_weight.saturating_add(consumed_weight); + // If any of the needed migrations post-checks fail, the whole chain panics + // (during tests). + #[cfg(feature = "try-runtime")] + if let Err(err) = >::post_migrate(&ver) { + panic!("{:?}", err); + } + // If more migrations should be applied, current_version will not be None. + current_version = Self::get_next_storage_version(ver); + } + + total_weight } -} -pub mod v4 { - use super::*; - use crate::types::{CollatorOf, Delegator}; + /// Checks whether the storage version after all the needed migrations match + /// the latest one. + #[cfg(feature = "try-runtime")] + pub(crate) fn post_migrate() -> Result<(), &'static str> { + ensure!( + StorageVersion::::get() == StakingStorageVersion::latest(), + "Not updated to the latest version." + ); - pub fn pre_migrate() -> Result<(), &'static str> { - assert_eq!(StorageVersion::::get(), Releases::V3_0_0); Ok(()) } +} - pub fn migrate() -> Weight { - log::info!("Migrating staking to Releases::V4"); +// Tests for the entire storage migrator. +#[cfg(test)] +mod tests { + use super::*; - // sort candidates from greatest to lowest - CandidatePool::::mutate(|candidates| candidates.sort_greatest_to_lowest()); - let mut n = 1u64; + use crate::mock::Test as TestRuntime; + + #[test] + fn ok_from_v1_migration() { + let mut ext = mock::ExtBuilder::default() + .with_balances(vec![(1, 100), (2, 100)]) + .with_collators(vec![(1, 100), (2, 100)]) + .with_storage_version(StakingStorageVersion::V1_0_0) + .build(); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + assert!( + StakingStorageMigrator::::pre_migrate().is_ok(), + "Storage pre-migrate from v1 should not fail." + ); - // for each candidate: sort delegators from greatest to lowest - CollatorState::::translate_values(|mut state: CollatorOf| { - state.delegators.sort_greatest_to_lowest(); - n = n.saturating_add(1u64); - Some(state) - }); + StakingStorageMigrator::::migrate(); - // for each delegator: sort delegations from greatest to lowest - DelegatorState::::translate_values(|mut state: Delegator| { - state.delegations.sort_greatest_to_lowest(); - n = n.saturating_add(1u64); - Some(state) + #[cfg(feature = "try-runtime")] + assert!( + StakingStorageMigrator::::post_migrate().is_ok(), + "Storage post-migrate from v1 should not fail." + ); }); - - StorageVersion::::put(Releases::V4); - log::info!("Completed staking migration to Releases::V4"); - - T::DbWeight::get().reads_writes(n, n) } - pub fn post_migrate() -> Result<(), &'static str> { - let mut candidates = CandidatePool::::get(); - candidates.sort_greatest_to_lowest(); - assert_eq!(CandidatePool::::get(), candidates); - assert_eq!(StorageVersion::::get(), Releases::V4); - Ok(()) + #[test] + fn ok_from_default_migration() { + let mut ext = mock::ExtBuilder::default() + .with_balances(vec![(1, 100), (2, 100)]) + .with_collators(vec![(1, 100), (2, 100)]) + .build(); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + if StakingStorageVersion::default() != StakingStorageVersion::latest() { + #[cfg(feature = "try-runtime")] + assert!( + StakingStorageMigrator::::pre_migrate().is_ok(), + "Storage pre-migrate from default version should not fail." + ); + + StakingStorageMigrator::::migrate(); + + #[cfg(feature = "try-runtime")] + assert!( + StakingStorageMigrator::::post_migrate().is_ok(), + "Storage post-migrate from default version should not fail." + ); + } + }); } } diff --git a/pallets/parachain-staking/src/migrations/v2.rs b/pallets/parachain-staking/src/migrations/v2.rs new file mode 100644 index 0000000000..e540ff73f9 --- /dev/null +++ b/pallets/parachain-staking/src/migrations/v2.rs @@ -0,0 +1,59 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2021 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::{inflation::InflationInfo, migrations::StakingStorageVersion, pallet::*, types::BalanceOf}; +use frame_support::{dispatch::Weight, traits::Get}; +use kilt_primitives::constants::MAX_COLLATOR_STAKE; + +#[cfg(feature = "try-runtime")] +pub(crate) fn pre_migrate() -> Result<(), &'static str> { + // should use default value if it has not existed before + assert_eq!(StorageVersion::::get(), StakingStorageVersion::V1_0_0); + Ok(()) +} + +pub(crate) fn migrate() -> Weight { + log::info!("Migrating staking to StakingStorageVersion::V2_0_0"); + + MaxCollatorCandidateStake::::put(BalanceOf::::from(MAX_COLLATOR_STAKE)); + + // update rewards per block + InflationConfig::::mutate(|inflation| { + *inflation = InflationInfo::new( + inflation.collator.max_rate, + inflation.collator.reward_rate.annual, + inflation.delegator.max_rate, + inflation.delegator.reward_rate.annual, + ); + }); + + StorageVersion::::put(StakingStorageVersion::V2_0_0); + log::info!("Completed staking migration to StakingStorageVersion::V2_0_0"); + + T::DbWeight::get().reads_writes(1, 3) +} + +#[cfg(feature = "try-runtime")] +pub(crate) fn post_migrate() -> Result<(), &'static str> { + assert_eq!( + MaxCollatorCandidateStake::::get(), + BalanceOf::::from(MAX_COLLATOR_STAKE) + ); + assert_eq!(StorageVersion::::get(), StakingStorageVersion::V2_0_0); + Ok(()) +} diff --git a/pallets/parachain-staking/src/migrations/v3.rs b/pallets/parachain-staking/src/migrations/v3.rs new file mode 100644 index 0000000000..9af028facd --- /dev/null +++ b/pallets/parachain-staking/src/migrations/v3.rs @@ -0,0 +1,46 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2021 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::{inflation::InflationInfo, migrations::StakingStorageVersion, pallet::*}; +use frame_support::{dispatch::Weight, traits::Get}; +use kilt_primitives::constants::INFLATION_CONFIG; + +#[cfg(feature = "try-runtime")] +pub(crate) fn pre_migrate() -> Result<(), &'static str> { + assert_eq!(StorageVersion::::get(), StakingStorageVersion::V2_0_0); + Ok(()) +} + +pub(crate) fn migrate() -> Weight { + log::info!("Migrating staking to StakingStorageVersion::V3_0_0"); + + // update rewards per block + InflationConfig::::mutate(|inflation| *inflation = InflationInfo::from(INFLATION_CONFIG)); + + StorageVersion::::put(StakingStorageVersion::V3_0_0); + log::info!("Completed staking migration to StakingStorageVersion::V3_0_0"); + + T::DbWeight::get().reads_writes(1, 2) +} + +#[cfg(feature = "try-runtime")] +pub(crate) fn post_migrate() -> Result<(), &'static str> { + assert_eq!(InflationConfig::::get(), InflationInfo::from(INFLATION_CONFIG)); + assert_eq!(StorageVersion::::get(), StakingStorageVersion::V3_0_0); + Ok(()) +} diff --git a/pallets/parachain-staking/src/migrations/v4.rs b/pallets/parachain-staking/src/migrations/v4.rs new file mode 100644 index 0000000000..6253a1d61c --- /dev/null +++ b/pallets/parachain-staking/src/migrations/v4.rs @@ -0,0 +1,71 @@ +// KILT Blockchain – https://botlabs.org +// Copyright (C) 2019-2021 BOTLabs GmbH + +// The KILT Blockchain is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The KILT Blockchain 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// If you feel like getting in touch with us, you can do so at info@botlabs.org + +use crate::{ + migrations::StakingStorageVersion, + types::{CollatorOf, Delegator}, + CandidatePool, CollatorState, Config, DelegatorState, StorageVersion, +}; +use frame_support::{dispatch::Weight, traits::Get}; + +#[cfg(feature = "try-runtime")] +pub(crate) fn pre_migrate() -> Result<(), &'static str> { + assert_eq!(StorageVersion::::get(), StakingStorageVersion::V3_0_0); + Ok(()) +} + +pub(crate) fn migrate() -> Weight { + log::info!("Migrating staking to StakingStorageVersion::V4"); + + // sort candidates from greatest to lowest + CandidatePool::::mutate(|candidates| candidates.sort_greatest_to_lowest()); + let mut n = 1u64; + + // for each candidate: sort delegators from greatest to lowest + CollatorState::::translate_values(|mut state: CollatorOf| { + state.delegators.sort_greatest_to_lowest(); + n = n.saturating_add(1u64); + Some(state) + }); + + // for each delegator: sort delegations from greatest to lowest + DelegatorState::::translate_values( + |mut state: Delegator| { + state.delegations.sort_greatest_to_lowest(); + n = n.saturating_add(1u64); + Some(state) + }, + ); + + StorageVersion::::put(StakingStorageVersion::V4); + log::info!("Completed staking migration to StakingStorageVersion::V4"); + + T::DbWeight::get().reads_writes(n, n) +} + +#[cfg(feature = "try-runtime")] +pub(crate) fn post_migrate() -> Result<(), &'static str> { + let mut candidates = CandidatePool::::get(); + candidates.sort_greatest_to_lowest(); + assert_eq!( + CandidatePool::::get().into_bounded_vec().into_inner(), + candidates.into_bounded_vec().into_inner() + ); + assert_eq!(StorageVersion::::get(), StakingStorageVersion::V4); + Ok(()) +} diff --git a/pallets/parachain-staking/src/mock.rs b/pallets/parachain-staking/src/mock.rs index c4289d0a44..f632f46dbb 100644 --- a/pallets/parachain-staking/src/mock.rs +++ b/pallets/parachain-staking/src/mock.rs @@ -20,7 +20,7 @@ #![allow(clippy::from_over_into)] use super::*; -use crate::{self as stake}; +use crate::{self as stake, migrations::StakingStorageVersion}; use frame_support::{ construct_runtime, parameter_types, traits::{GenesisBuild, OnFinalize, OnInitialize}, @@ -36,6 +36,7 @@ use sp_runtime::{ traits::{BlakeTwo256, ConvertInto, IdentityLookup, OpaqueKeys}, Perbill, Perquintill, }; +use sp_std::fmt::Debug; pub use kilt_primitives::BlockNumber; @@ -129,10 +130,13 @@ parameter_types! { pub const ExitQueueDelay: u32 = 2; pub const DefaultBlocksPerRound: BlockNumber = BLOCKS_PER_ROUND; pub const MinSelectedCandidates: u32 = 2; + #[derive(Debug, PartialEq)] pub const MaxDelegatorsPerCollator: u32 = 4; + #[derive(Debug, PartialEq)] pub const MaxCollatorsPerDelegator: u32 = 4; pub const DefaultCollatorCommission: Perbill = Perbill::from_percent(20); pub const MinCollatorStake: Balance = 10; + #[derive(Debug, PartialEq)] pub const MaxCollatorCandidates: u32 = 10; pub const MinDelegatorStake: Balance = 5; pub const MinDelegation: Balance = 3; @@ -206,6 +210,8 @@ pub(crate) struct ExtBuilder { inflation_config: InflationInfo, // blocks per round blocks_per_round: BlockNumber, + // version of storage + storage_version: StakingStorageVersion, } impl Default for ExtBuilder { @@ -221,6 +227,7 @@ impl Default for ExtBuilder { Perquintill::from_percent(40), Perquintill::from_percent(10), ), + storage_version: StakingStorageVersion::default(), } } } @@ -265,6 +272,11 @@ impl ExtBuilder { self } + pub(crate) fn with_storage_version(mut self, storage_version: StakingStorageVersion) -> Self { + self.storage_version = storage_version; + self + } + pub(crate) fn build(self) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default() .build_storage::() @@ -321,6 +333,10 @@ impl ExtBuilder { }); } + ext.execute_with(|| { + crate::StorageVersion::::set(self.storage_version); + }); + ext.execute_with(|| System::set_block_number(1)); ext } diff --git a/pallets/parachain-staking/src/set.rs b/pallets/parachain-staking/src/set.rs index 7551ea5625..1adea2d275 100644 --- a/pallets/parachain-staking/src/set.rs +++ b/pallets/parachain-staking/src/set.rs @@ -16,79 +16,107 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org +use frame_support::{traits::Get, BoundedVec, DefaultNoBound}; use parity_scale_codec::{Decode, Encode}; -use sp_runtime::RuntimeDebug; use sp_std::{ cmp::Ordering, + convert::TryInto, ops::{Index, IndexMut, Range, RangeFull}, - prelude::*, }; - #[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; +use sp_std::{fmt, prelude::*}; -/// An ordered set backed by `Vec`. -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode, Default, Clone)] -pub struct OrderedSet(Vec); +/// An ordered set backed by `BoundedVec`. +#[derive(PartialEq, Eq, Encode, Decode, DefaultNoBound, Clone)] +pub struct OrderedSet(BoundedVec); -impl OrderedSet { +impl> OrderedSet { /// Create a new empty set. pub fn new() -> Self { - Self(Vec::new()) + Self(BoundedVec::default()) } - /// Create an ordered set from a `Vec`. + /// Creates an ordered set from a `BoundedVec`. /// /// The vector will be sorted reversily (from greatest to lowest) and /// deduped first. - pub fn from(mut v: Vec) -> Self { + pub fn from(bv: BoundedVec) -> Self { + let mut v = bv.into_inner(); v.sort_by(|a, b| b.cmp(a)); v.dedup(); - Self::from_sorted_set(v) + Self::from_sorted_set(v.try_into().expect("No values were added")) } - /// Create a set from a `Vec`. + /// Create a set from a `BoundedVec`. /// /// Assumes that `v` is sorted reversely (from greatest to lowest) and only /// contains unique elements. - pub fn from_sorted_set(v: Vec) -> Self { - Self(v) + pub fn from_sorted_set(bv: BoundedVec) -> Self { + Self(bv) } - /// Insert an element, if no equal item exist in the set. + /// Inserts an element, if no equal item exist in the set. + /// + /// Throws if insertion would exceed the bounded vec's max size. /// - /// Return true if the item is unique in the set, otherwise returns false. - pub fn insert(&mut self, value: T) -> bool { + /// Returns true if the item is unique in the set, otherwise returns false. + pub fn try_insert(&mut self, value: T) -> Result { match self.linear_search(&value) { - Ok(_) => false, + Ok(_) => Ok(false), Err(loc) => { - self.0.insert(loc, value); - true + self.0.try_insert(loc, value)?; + Ok(true) } } } - /// Insert or replaces an element. + /// Attempts to replace the last element of the set with the provided value. + /// Assumes the set to have reached its bounded size. /// - /// Returns the old value if existing. - pub fn upsert(&mut self, value: T) -> Option { + /// Throws with `false` if the value already exists in the set. + /// Throws with `true` if the value has the least order in the set, i.e., + /// it would be appended (inserted at i == length). + /// + /// Returns the replaced element upon success. + pub fn try_insert_replace(&mut self, value: T) -> Result { + let last_idx = self.len().saturating_sub(1); + match self.linear_search(&value) { + Ok(_) => Err(false), + Err(i) if i < self.len() => { + // always replace the last element + let old = sp_std::mem::replace(&mut self.0[last_idx], value); + self.sort_greatest_to_lowest(); + Ok(old) + } + _ => Err(true), + } + } + + /// Inserts a new element or updates the value of an existing one. + /// + /// Throws if the maximum size of the bounded vec would be exceeded + /// upon insertion. + /// + /// Returns the old value if existing or None if the value did not exist + /// before. + pub fn try_upsert(&mut self, value: T) -> Result, ()> { match self.linear_search(&value) { Ok(i) => { let old = sp_std::mem::replace(&mut self.0[i], value); self.sort_greatest_to_lowest(); - Some(old) + Ok(Some(old)) } Err(i) => { - self.0.insert(i, value); - None + // Delegator + self.0.try_insert(i, value)?; + Ok(None) } } } - /// Remove an element. + /// Removes an element. /// - /// Return true if removal happened. + /// Returns true if removal happened. pub fn remove(&mut self, value: &T) -> Option { match self.linear_search(value) { Ok(loc) => Some(self.0.remove(loc)), @@ -96,9 +124,9 @@ impl OrderedSet { } } - /// Remove an element. + /// Removes an element. /// - /// Return true if removal happened. + /// Returns true if removal happened. pub fn remove_by(&mut self, f: F) -> Option where F: FnMut(&T) -> Ordering, @@ -127,7 +155,7 @@ impl OrderedSet { self.0.binary_search(value) } - /// Iteratively searchis this (from greatest to lowest) ordered set for a + /// Iteratively searches this (from greatest to lowest) ordered set for a /// given element. /// /// 1. If the value is found, then Result::Ok is returned, containing the @@ -178,7 +206,7 @@ impl OrderedSet { /// Clear the set. pub fn clear(&mut self) { - self.0.clear(); + self.0 = BoundedVec::default(); } /// Return the length of the set. @@ -191,24 +219,40 @@ impl OrderedSet { self.0.is_empty() } - /// Convert the set to a vector. - pub fn into_vec(self) -> Vec { + /// Convert the set to a bounded vector. + pub fn into_bounded_vec(self) -> BoundedVec { self.0 } - /// Sort from greatest to lowest + /// Sorts from greatest to lowest. pub fn sort_greatest_to_lowest(&mut self) { - self.0.sort_by(|a, b| b.cmp(a)); + // NOTE: BoundedVec does not implement DerefMut because it would allow for + // unchecked extension of the inner vector. Thus, we have to work with a + // clone unfortunately. + let mut sorted_v: sp_std::vec::Vec = sp_std::mem::take(&mut self.0).into(); + sorted_v.sort_by(|a, b| b.cmp(a)); + self.0 = sorted_v.try_into().expect("Did not extend size of bounded vec"); + } +} + +#[cfg(feature = "std")] +impl fmt::Debug for OrderedSet +where + T: fmt::Debug, + S: Get, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("OrderedSet").field(&self.0).finish() } } -impl From> for OrderedSet { - fn from(v: Vec) -> Self { - Self::from(v) +impl> From> for OrderedSet { + fn from(bv: BoundedVec) -> Self { + Self::from(bv) } } -impl Index for OrderedSet { +impl> Index for OrderedSet { type Output = T; fn index(&self, index: usize) -> &Self::Output { @@ -216,7 +260,7 @@ impl Index for OrderedSet { } } -impl Index> for OrderedSet { +impl> Index> for OrderedSet { type Output = [T]; fn index(&self, range: Range) -> &Self::Output { @@ -224,7 +268,7 @@ impl Index> for OrderedSet { } } -impl Index for OrderedSet { +impl> Index for OrderedSet { type Output = [T]; fn index(&self, range: RangeFull) -> &Self::Output { @@ -232,13 +276,13 @@ impl Index for OrderedSet { } } -impl IndexMut for OrderedSet { +impl> IndexMut for OrderedSet { fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut self.0[index] } } -impl IntoIterator for OrderedSet { +impl> IntoIterator for OrderedSet { type Item = T; type IntoIter = sp_std::vec::IntoIter; @@ -247,19 +291,19 @@ impl IntoIterator for OrderedSet { } } -impl From> for Vec { - fn from(s: OrderedSet) -> Self { +impl> From> for BoundedVec { + fn from(s: OrderedSet) -> Self { s.0 } } -impl IndexMut> for OrderedSet { +impl> IndexMut> for OrderedSet { fn index_mut(&mut self, range: Range) -> &mut Self::Output { &mut self.0[range] } } -impl IndexMut for OrderedSet { +impl> IndexMut for OrderedSet { fn index_mut(&mut self, range: RangeFull) -> &mut Self::Output { &mut self.0[range] } @@ -268,87 +312,128 @@ impl IndexMut for OrderedSet { #[cfg(test)] mod tests { use crate::{mock::Test, types::StakeOf}; + use frame_support::parameter_types; + use sp_runtime::RuntimeDebug; use super::*; + parameter_types! { + #[derive(PartialEq, RuntimeDebug)] + pub const Eight: u32 = 8; + #[derive(PartialEq, RuntimeDebug, Clone)] + pub const Five: u32 = 5; + } + #[test] fn from() { - let v = vec![4, 2, 3, 4, 3, 1]; - let set: OrderedSet = v.into(); - assert_eq!(set, OrderedSet::from(vec![1, 2, 3, 4])); + let v: BoundedVec = vec![4, 2, 3, 4, 3, 1].try_into().unwrap(); + let set: OrderedSet = v.into(); + assert_eq!( + set, + OrderedSet::::from(vec![1, 2, 3, 4].try_into().unwrap()) + ); } #[test] fn insert() { - let mut set: OrderedSet = OrderedSet::new(); - assert_eq!(set, OrderedSet::from(vec![])); + let mut set: OrderedSet = OrderedSet::new(); + assert_eq!(set, OrderedSet::::from(vec![].try_into().unwrap())); - assert!(set.insert(1)); - assert_eq!(set, OrderedSet::from(vec![1])); + assert_eq!(set.try_insert(1), Ok(true)); + assert_eq!(set, OrderedSet::::from(vec![1].try_into().unwrap())); - assert!(set.insert(5)); - assert_eq!(set, OrderedSet::from(vec![1, 5])); + assert_eq!(set.try_insert(5), Ok(true)); + assert_eq!(set, OrderedSet::::from(vec![1, 5].try_into().unwrap())); - assert!(set.insert(3)); - assert_eq!(set, OrderedSet::from(vec![1, 3, 5])); + assert_eq!(set.try_insert(3), Ok(true)); + assert_eq!(set, OrderedSet::::from(vec![1, 3, 5].try_into().unwrap())); - assert!(!set.insert(3)); - assert_eq!(set, OrderedSet::from(vec![1, 3, 5])); + assert_eq!(set.try_insert(3), Ok(false)); + assert_eq!(set, OrderedSet::::from(vec![1, 3, 5].try_into().unwrap())); } #[test] fn remove() { - let mut set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4]); + let mut set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4].try_into().unwrap()); assert_eq!(set.remove(&5), None); - assert_eq!(set, OrderedSet::from(vec![1, 2, 3, 4])); + assert_eq!( + set, + OrderedSet::::from(vec![1, 2, 3, 4].try_into().unwrap()) + ); assert_eq!(set.remove(&1), Some(1)); - assert_eq!(set, OrderedSet::from(vec![2, 3, 4])); + assert_eq!(set, OrderedSet::::from(vec![2, 3, 4].try_into().unwrap())); assert_eq!(set.remove(&3), Some(3)); - assert_eq!(set, OrderedSet::from(vec![2, 4])); + assert_eq!(set, OrderedSet::::from(vec![2, 4].try_into().unwrap())); assert_eq!(set.remove(&3), None); - assert_eq!(set, OrderedSet::from(vec![2, 4])); + assert_eq!(set, OrderedSet::::from(vec![2, 4].try_into().unwrap())); assert_eq!(set.remove(&4), Some(4)); - assert_eq!(set, OrderedSet::from(vec![2])); + assert_eq!(set, OrderedSet::::from(vec![2].try_into().unwrap())); assert_eq!(set.remove(&2), Some(2)); - assert_eq!(set, OrderedSet::from(vec![])); + assert_eq!(set, OrderedSet::::from(vec![].try_into().unwrap())); assert_eq!(set.remove(&2), None); - assert_eq!(set, OrderedSet::from(vec![])); + assert_eq!(set, OrderedSet::::from(vec![].try_into().unwrap())); } #[test] fn contains() { - let set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4]); - + let set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4].try_into().unwrap()); assert!(!set.contains(&5)); - assert!(set.contains(&1)); - assert!(set.contains(&3)); } #[test] fn clear() { - let mut set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4]); + let mut set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4].try_into().unwrap()); set.clear(); assert_eq!(set, OrderedSet::new()); } + #[test] + fn try_insert_replace() { + let mut set: OrderedSet = OrderedSet::from(vec![10, 9, 8, 7, 5].try_into().unwrap()); + assert_eq!(set.clone().into_bounded_vec().into_inner(), vec![10, 9, 8, 7, 5]); + assert!(set.try_insert(11).is_err()); + + assert_eq!(set.try_insert_replace(6), Ok(5)); + assert_eq!(set.clone().into_bounded_vec().into_inner(), vec![10, 9, 8, 7, 6]); + + assert_eq!(set.try_insert_replace(6), Err(false)); + assert_eq!(set.try_insert_replace(5), Err(true)); + + assert_eq!(set.try_insert_replace(10), Err(false)); + assert_eq!(set.try_insert_replace(11), Ok(6)); + assert_eq!(set.into_bounded_vec().into_inner(), vec![11, 10, 9, 8, 7]); + } + + #[test] + fn exceeding_max_size_should_fail() { + let mut set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4, 5].try_into().unwrap()); + let inserted = set.try_insert(6); + + assert!(inserted.is_err()); + } + #[test] fn linear_search() { - let set: OrderedSet> = OrderedSet::from(vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 3, amount: 90 }, - StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 7, amount: 70 }, - StakeOf:: { owner: 9, amount: 60 }, - ]); + let set: OrderedSet, Eight> = OrderedSet::from( + vec![ + StakeOf:: { owner: 1, amount: 100 }, + StakeOf:: { owner: 3, amount: 90 }, + StakeOf:: { owner: 5, amount: 80 }, + StakeOf:: { owner: 7, amount: 70 }, + StakeOf:: { owner: 9, amount: 60 }, + ] + .try_into() + .unwrap(), + ); assert_eq!(set.linear_search(&StakeOf:: { owner: 1, amount: 0 }), Ok(0)); assert_eq!(set.linear_search(&StakeOf:: { owner: 7, amount: 100 }), Ok(3)); assert_eq!(set.linear_search(&StakeOf:: { owner: 7, amount: 50 }), Ok(3)); @@ -361,54 +446,70 @@ mod tests { #[test] fn upsert_set() { - let mut set: OrderedSet> = OrderedSet::from(vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 3, amount: 90 }, - StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 7, amount: 70 }, - StakeOf:: { owner: 9, amount: 60 }, - ]); - assert!(set.insert(StakeOf:: { owner: 2, amount: 75 })); - assert_eq!( - set, - OrderedSet::from(vec![ + let mut set: OrderedSet, Eight> = OrderedSet::from( + vec![ StakeOf:: { owner: 1, amount: 100 }, StakeOf:: { owner: 3, amount: 90 }, StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 2, amount: 75 }, StakeOf:: { owner: 7, amount: 70 }, StakeOf:: { owner: 9, amount: 60 }, - ]) + ] + .try_into() + .unwrap(), + ); + assert_eq!(set.try_insert(StakeOf:: { owner: 2, amount: 75 }), Ok(true)); + assert_eq!( + set, + OrderedSet::from( + vec![ + StakeOf:: { owner: 1, amount: 100 }, + StakeOf:: { owner: 3, amount: 90 }, + StakeOf:: { owner: 5, amount: 80 }, + StakeOf:: { owner: 2, amount: 75 }, + StakeOf:: { owner: 7, amount: 70 }, + StakeOf:: { owner: 9, amount: 60 }, + ] + .try_into() + .unwrap() + ) ); assert_eq!( - set.upsert(StakeOf:: { owner: 2, amount: 90 }), - Some(StakeOf:: { owner: 2, amount: 75 }) + set.try_upsert(StakeOf:: { owner: 2, amount: 90 }), + Ok(Some(StakeOf:: { owner: 2, amount: 75 })) ); assert_eq!( set, - OrderedSet::from(vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 3, amount: 90 }, - StakeOf:: { owner: 2, amount: 90 }, - StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 7, amount: 70 }, - StakeOf:: { owner: 9, amount: 60 }, - ]) + OrderedSet::from( + vec![ + StakeOf:: { owner: 1, amount: 100 }, + StakeOf:: { owner: 3, amount: 90 }, + StakeOf:: { owner: 2, amount: 90 }, + StakeOf:: { owner: 5, amount: 80 }, + StakeOf:: { owner: 7, amount: 70 }, + StakeOf:: { owner: 9, amount: 60 }, + ] + .try_into() + .unwrap() + ) ); assert_eq!( - set.upsert(StakeOf:: { owner: 2, amount: 60 }), - Some(StakeOf:: { owner: 2, amount: 90 }) + set.try_upsert(StakeOf:: { owner: 2, amount: 60 }), + Ok(Some(StakeOf:: { owner: 2, amount: 90 })) ); assert_eq!( set, - OrderedSet::from(vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 3, amount: 90 }, - StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 7, amount: 70 }, - StakeOf:: { owner: 2, amount: 60 }, - StakeOf:: { owner: 9, amount: 60 }, - ]) + OrderedSet::from( + vec![ + StakeOf:: { owner: 1, amount: 100 }, + StakeOf:: { owner: 3, amount: 90 }, + StakeOf:: { owner: 5, amount: 80 }, + StakeOf:: { owner: 7, amount: 70 }, + StakeOf:: { owner: 2, amount: 60 }, + StakeOf:: { owner: 9, amount: 60 }, + ] + .try_into() + .unwrap() + ) ); } } diff --git a/pallets/parachain-staking/src/tests.rs b/pallets/parachain-staking/src/tests.rs index 4a57856c00..1405c07eeb 100644 --- a/pallets/parachain-staking/src/tests.rs +++ b/pallets/parachain-staking/src/tests.rs @@ -18,9 +18,12 @@ //! Unit testing -use std::{collections::BTreeMap, iter}; +use std::{convert::TryInto, iter}; -use frame_support::{assert_noop, assert_ok, traits::EstimateNextSessionRotation}; +use frame_support::{ + assert_noop, assert_ok, storage::bounded_btree_map::BoundedBTreeMap, traits::EstimateNextSessionRotation, + BoundedVec, +}; use pallet_balances::{BalanceLock, Error as BalancesError, Reasons}; use pallet_session::{SessionManager, ShouldEndSession}; use sp_runtime::{traits::Zero, Perbill, Permill, Perquintill, SaturatedConversion}; @@ -100,8 +103,12 @@ fn genesis() { } ); assert_eq!( - vec![Stake { owner: 1, amount: 700 }, Stake { owner: 2, amount: 400 }], - StakePallet::candidate_pool().into_vec() + vec![ + StakeOf:: { owner: 1, amount: 700 }, + StakeOf:: { owner: 2, amount: 400 } + ] + .try_into(), + Ok(StakePallet::candidate_pool().into_bounded_vec()) ); // 1 assert_eq!(Balances::usable_balance(&1), 500); @@ -109,16 +116,22 @@ fn genesis() { assert!(StakePallet::is_active_candidate(&1).is_some()); assert_eq!( StakePallet::collator_state(&1), - Some(Collator { - id: 1, - stake: 500, - delegators: OrderedSet::from_sorted_set(vec![ - Stake { owner: 3, amount: 100 }, - Stake { owner: 4, amount: 100 } - ]), - total: 700, - state: CollatorStatus::Active, - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: 1, + stake: 500, + delegators: OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 3, amount: 100 }, + StakeOf:: { owner: 4, amount: 100 } + ] + .try_into() + .unwrap() + ), + total: 700, + state: CollatorStatus::Active, + } + ) ); // 2 assert_eq!(Balances::usable_balance(&2), 100); @@ -126,16 +139,22 @@ fn genesis() { assert!(StakePallet::is_active_candidate(&2).is_some()); assert_eq!( StakePallet::collator_state(&2), - Some(Collator { - id: 2, - stake: 200, - delegators: OrderedSet::from_sorted_set(vec![ - Stake { owner: 5, amount: 100 }, - Stake { owner: 6, amount: 100 } - ]), - total: 400, - state: CollatorStatus::Active, - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: 2, + stake: 200, + delegators: OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 5, amount: 100 }, + StakeOf:: { owner: 6, amount: 100 } + ] + .try_into() + .unwrap() + ), + total: 400, + state: CollatorStatus::Active, + } + ) ); // Delegators assert_eq!( @@ -199,14 +218,15 @@ fn genesis() { } ); assert_eq!( - StakePallet::candidate_pool().into_vec(), + Ok(StakePallet::candidate_pool().into_bounded_vec()), vec![ - Stake { owner: 1, amount: 50 }, - Stake { owner: 2, amount: 40 }, - Stake { owner: 3, amount: 20 }, - Stake { owner: 4, amount: 20 }, - Stake { owner: 5, amount: 10 } + StakeOf:: { owner: 1, amount: 50 }, + StakeOf:: { owner: 2, amount: 40 }, + StakeOf:: { owner: 3, amount: 20 }, + StakeOf:: { owner: 4, amount: 20 }, + StakeOf:: { owner: 5, amount: 10 } ] + .try_into() ); for x in 1..5 { assert!(StakePallet::is_active_candidate(&x).is_some()); @@ -328,7 +348,7 @@ fn collator_exit_executes_after_delay() { .build() .execute_with(|| { assert_ok!(StakePallet::set_max_selected_candidates(Origin::root(), 5)); - assert_eq!(StakePallet::selected_candidates(), vec![1, 2, 7]); + assert_eq!(Ok(StakePallet::selected_candidates()), vec![1, 2, 7].try_into()); roll_to(4, vec![]); assert_noop!( StakePallet::init_leave_candidates(Origin::signed(3)), @@ -341,7 +361,7 @@ fn collator_exit_executes_after_delay() { StakePallet::delegate_another_candidate(Origin::signed(3), 2, 10), Error::::CannotDelegateIfLeaving ); - assert_eq!(StakePallet::selected_candidates(), vec![1, 7]); + assert_eq!(Ok(StakePallet::selected_candidates()), vec![1, 7].try_into()); assert_eq!( last_event(), MetaEvent::StakePallet(Event::CollatorScheduledExit(2, 2, 4)) @@ -394,7 +414,7 @@ fn collator_selection_chooses_top_candidates() { assert_ok!(StakePallet::set_max_selected_candidates(Origin::root(), 5)); roll_to(8, vec![]); // should choose top MaxSelectedCandidates (5), in order - assert_eq!(StakePallet::selected_candidates(), vec![1, 2, 3, 4, 5]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5]); let expected = vec![ Event::CollatorChosen(1, 100, 0), Event::CollatorChosen(2, 90, 0), @@ -406,7 +426,7 @@ fn collator_selection_chooses_top_candidates() { ]; assert_eq!(events(), expected); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(6))); - assert_eq!(StakePallet::selected_candidates(), vec![1, 2, 3, 4, 5]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5],); assert_eq!( last_event(), MetaEvent::StakePallet(Event::CollatorScheduledExit(1, 6, 3)) @@ -417,7 +437,7 @@ fn collator_selection_chooses_top_candidates() { roll_to(21, vec![]); assert_ok!(StakePallet::join_candidates(Origin::signed(6), 69u128)); - assert_eq!(StakePallet::selected_candidates(), vec![1, 2, 3, 4, 6]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 6]); assert_eq!( last_event(), MetaEvent::StakePallet(Event::JoinedCollatorCandidates(6, 69u128, 409u128)) @@ -439,7 +459,7 @@ fn collator_selection_chooses_top_candidates() { Event::CollatorChosen(4, 70, 0), Event::CollatorChosen(5, 60, 0), Event::CollatorScheduledExit(1, 6, 3), - // TotalStake is updated once candidate 6 left in `execute_delayed_collator_exits` + // TotalStakeis updated once candidate 6 left in `execute_delayed_collator_exits` Event::NewRound(10, 2), Event::NewRound(15, 3), Event::CollatorLeft(6, 50), @@ -477,7 +497,7 @@ fn exit_queue_with_events() { assert_ok!(StakePallet::set_max_selected_candidates(Origin::root(), 5)); roll_to(8, vec![]); // should choose top MaxSelectedCandidates (5), in order - assert_eq!(StakePallet::selected_candidates(), vec![1, 2, 3, 4, 5]); + assert_eq!(Ok(StakePallet::selected_candidates()), vec![1, 2, 3, 4, 5].try_into()); let mut expected = vec![ Event::CollatorChosen(1, 100, 0), Event::CollatorChosen(2, 90, 0), @@ -489,7 +509,7 @@ fn exit_queue_with_events() { ]; assert_eq!(events(), expected); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(6))); - assert_eq!(StakePallet::selected_candidates(), vec![1, 2, 3, 4, 5]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5]); assert_eq!( last_event(), MetaEvent::StakePallet(Event::CollatorScheduledExit(1, 6, 3)) @@ -497,7 +517,7 @@ fn exit_queue_with_events() { roll_to(11, vec![]); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(5))); - assert_eq!(StakePallet::selected_candidates(), vec![1, 2, 3, 4]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4]); assert_eq!( last_event(), MetaEvent::StakePallet(Event::CollatorScheduledExit(2, 5, 4)) @@ -506,7 +526,7 @@ fn exit_queue_with_events() { roll_to(16, vec![]); assert_ok!(StakePallet::execute_leave_candidates(Origin::signed(6), 6)); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(4))); - assert_eq!(StakePallet::selected_candidates(), vec![1, 2, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3]); assert_eq!( last_event(), MetaEvent::StakePallet(Event::CollatorScheduledExit(3, 4, 5)) @@ -597,7 +617,7 @@ fn execute_leave_candidates_with_delay() { delegators: 500, } ); - assert_eq!(StakePallet::selected_candidates(), vec![2, 1, 10, 9, 8]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 1, 10, 9, 8]); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(10))); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(9))); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(1))); @@ -606,7 +626,7 @@ fn execute_leave_candidates_with_delay() { assert_ok!(StakePallet::init_leave_candidates(Origin::signed(5))); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(8))); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(2))); - assert_eq!(StakePallet::selected_candidates(), vec![4, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![4, 3]); for owner in vec![1, 2, 5, 6, 7, 8, 9, 10].iter() { assert!(StakePallet::collator_state(owner) .unwrap() @@ -619,71 +639,101 @@ fn execute_leave_candidates_with_delay() { assert_eq!(StakePallet::total(), old_stake); assert_eq!( StakePallet::collator_state(1), - Some(Collator:: { - id: 1, - stake: 10, - delegators: OrderedSet::from(vec![ - Stake { owner: 11, amount: 110 }, - Stake { owner: 12, amount: 120 } - ]), - total: 240, - state: CollatorStatus::Leaving(3) - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: 1, + stake: 10, + delegators: OrderedSet::from( + vec![ + StakeOf:: { owner: 11, amount: 110 }, + StakeOf:: { owner: 12, amount: 120 } + ] + .try_into() + .unwrap() + ), + total: 240, + state: CollatorStatus::Leaving(3) + } + ) ); assert_eq!( StakePallet::collator_state(2), - Some(Collator:: { - id: 2, - stake: 20, - delegators: OrderedSet::from(vec![ - Stake { owner: 13, amount: 130 }, - Stake { owner: 14, amount: 140 } - ]), - total: 290, - state: CollatorStatus::Leaving(3) - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: 2, + stake: 20, + delegators: OrderedSet::from( + vec![ + StakeOf:: { owner: 13, amount: 130 }, + StakeOf:: { owner: 14, amount: 140 } + ] + .try_into() + .unwrap() + ), + total: 290, + state: CollatorStatus::Leaving(3) + } + ) ); for collator in 5u64..=10u64 { assert_eq!( StakePallet::collator_state(collator), - Some(Collator:: { - id: collator, - stake: collator as u128 * 10u128, - delegators: OrderedSet::from(vec![]), - total: collator as u128 * 10u128, - state: CollatorStatus::Leaving(3) - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: collator, + stake: collator as u128 * 10u128, + delegators: OrderedSet::from(BoundedVec::default()), + total: collator as u128 * 10u128, + state: CollatorStatus::Leaving(3) + } + ) ); assert!(StakePallet::is_active_candidate(&collator).is_some()); assert!(StakePallet::unstaking(collator).is_empty()); } assert_eq!( StakePallet::delegator_state(11), - Some(Delegator:: { - delegations: OrderedSet::from(vec![Stake { owner: 1, amount: 110 }]), - total: 110 - }) + Some( + Delegator::::MaxCollatorsPerDelegator> { + delegations: OrderedSet::from( + vec![StakeOf:: { owner: 1, amount: 110 }].try_into().unwrap() + ), + total: 110 + } + ) ); assert_eq!( StakePallet::delegator_state(12), - Some(Delegator:: { - delegations: OrderedSet::from(vec![Stake { owner: 1, amount: 120 }]), - total: 120 - }) + Some( + Delegator::::MaxCollatorsPerDelegator> { + delegations: OrderedSet::from( + vec![StakeOf:: { owner: 1, amount: 120 }].try_into().unwrap() + ), + total: 120 + } + ) ); assert_eq!( StakePallet::delegator_state(13), - Some(Delegator:: { - delegations: OrderedSet::from(vec![Stake { owner: 2, amount: 130 }]), - total: 130 - }) + Some( + Delegator::::MaxCollatorsPerDelegator> { + delegations: OrderedSet::from( + vec![StakeOf:: { owner: 2, amount: 130 }].try_into().unwrap() + ), + total: 130 + } + ) ); assert_eq!( StakePallet::delegator_state(14), - Some(Delegator:: { - delegations: OrderedSet::from(vec![Stake { owner: 2, amount: 140 }]), - total: 140 - }) + Some( + Delegator::::MaxCollatorsPerDelegator> { + delegations: OrderedSet::from( + vec![StakeOf:: { owner: 2, amount: 140 }].try_into().unwrap() + ), + total: 140 + } + ) ); for delegator in 11u64..=14u64 { assert!(StakePallet::is_delegator(&delegator)); @@ -693,7 +743,7 @@ fn execute_leave_candidates_with_delay() { // exits cannot be executed yet but in the next round roll_to(10, vec![]); assert_eq!(StakePallet::total(), old_stake); - assert_eq!(StakePallet::selected_candidates(), vec![4, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![4, 3]); for owner in vec![1, 2, 5, 6, 7, 8, 9, 10].iter() { assert!(StakePallet::collator_state(owner) .unwrap() @@ -706,71 +756,101 @@ fn execute_leave_candidates_with_delay() { assert_eq!(StakePallet::total(), old_stake); assert_eq!( StakePallet::collator_state(1), - Some(Collator:: { - id: 1, - stake: 10, - delegators: OrderedSet::from(vec![ - Stake { owner: 11, amount: 110 }, - Stake { owner: 12, amount: 120 } - ]), - total: 240, - state: CollatorStatus::Leaving(3) - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: 1, + stake: 10, + delegators: OrderedSet::from( + vec![ + StakeOf:: { owner: 11, amount: 110 }, + StakeOf:: { owner: 12, amount: 120 } + ] + .try_into() + .unwrap() + ), + total: 240, + state: CollatorStatus::Leaving(3) + } + ) ); assert_eq!( StakePallet::collator_state(2), - Some(Collator:: { - id: 2, - stake: 20, - delegators: OrderedSet::from(vec![ - Stake { owner: 13, amount: 130 }, - Stake { owner: 14, amount: 140 } - ]), - total: 290, - state: CollatorStatus::Leaving(3) - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: 2, + stake: 20, + delegators: OrderedSet::from( + vec![ + StakeOf:: { owner: 13, amount: 130 }, + StakeOf:: { owner: 14, amount: 140 } + ] + .try_into() + .unwrap() + ), + total: 290, + state: CollatorStatus::Leaving(3) + } + ) ); for collator in 5u64..=10u64 { assert_eq!( StakePallet::collator_state(collator), - Some(Collator:: { - id: collator, - stake: collator as u128 * 10u128, - delegators: OrderedSet::from(vec![]), - total: collator as u128 * 10u128, - state: CollatorStatus::Leaving(3) - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: collator, + stake: collator as u128 * 10u128, + delegators: OrderedSet::from(BoundedVec::default()), + total: collator as u128 * 10u128, + state: CollatorStatus::Leaving(3) + } + ) ); assert!(StakePallet::is_active_candidate(&collator).is_some()); assert!(StakePallet::unstaking(collator).is_empty()); } assert_eq!( StakePallet::delegator_state(11), - Some(Delegator:: { - delegations: OrderedSet::from(vec![Stake { owner: 1, amount: 110 }]), - total: 110 - }) + Some( + Delegator::::MaxCollatorsPerDelegator> { + delegations: OrderedSet::from( + vec![StakeOf:: { owner: 1, amount: 110 }].try_into().unwrap() + ), + total: 110 + } + ) ); assert_eq!( StakePallet::delegator_state(12), - Some(Delegator:: { - delegations: OrderedSet::from(vec![Stake { owner: 1, amount: 120 }]), - total: 120 - }) + Some( + Delegator::::MaxCollatorsPerDelegator> { + delegations: OrderedSet::from( + vec![StakeOf:: { owner: 1, amount: 120 }].try_into().unwrap() + ), + total: 120 + } + ) ); assert_eq!( StakePallet::delegator_state(13), - Some(Delegator:: { - delegations: OrderedSet::from(vec![Stake { owner: 2, amount: 130 }]), - total: 130 - }) + Some( + Delegator::::MaxCollatorsPerDelegator> { + delegations: OrderedSet::from( + vec![StakeOf:: { owner: 2, amount: 130 }].try_into().unwrap() + ), + total: 130 + } + ) ); assert_eq!( StakePallet::delegator_state(14), - Some(Delegator:: { - delegations: OrderedSet::from(vec![Stake { owner: 2, amount: 140 }]), - total: 140 - }) + Some( + Delegator::::MaxCollatorsPerDelegator> { + delegations: OrderedSet::from( + vec![StakeOf:: { owner: 2, amount: 140 }].try_into().unwrap() + ), + total: 140 + } + ) ); for delegator in 11u64..=14u64 { assert!(StakePallet::is_delegator(&delegator)); @@ -780,7 +860,7 @@ fn execute_leave_candidates_with_delay() { // execute first five exits are executed roll_to(15, vec![]); assert_eq!(StakePallet::total(), old_stake); - assert_eq!(StakePallet::selected_candidates(), vec![4, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![4, 3]); for collator in vec![1u64, 2u64, 5u64, 6u64, 7u64].iter() { assert_ok!(StakePallet::execute_leave_candidates( Origin::signed(*collator), @@ -835,7 +915,7 @@ fn multiple_delegations() { assert_ok!(StakePallet::set_max_selected_candidates(Origin::root(), 5)); roll_to(8, vec![]); // chooses top MaxSelectedCandidates (5), in order - assert_eq!(StakePallet::selected_candidates(), vec![1, 2, 3, 4, 5]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5]); let mut expected = vec![ Event::CollatorChosen(1, 20, 30), Event::CollatorChosen(2, 20, 20), @@ -857,10 +937,10 @@ fn multiple_delegations() { assert_ok!(StakePallet::delegate_another_candidate(Origin::signed(6), 2, 10)); assert_ok!(StakePallet::delegate_another_candidate(Origin::signed(6), 4, 10)); assert_ok!(StakePallet::delegate_another_candidate(Origin::signed(6), 3, 10)); - assert_eq!(StakePallet::selected_candidates(), vec![1, 2, 4, 3, 5]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 4, 3, 5]); assert_noop!( StakePallet::delegate_another_candidate(Origin::signed(6), 5, 10), - Error::::ExceedMaxCollatorsPerDelegator, + Error::::MaxCollatorsPerDelegatorExceeded, ); roll_to(16, vec![]); @@ -912,7 +992,7 @@ fn multiple_delegations() { assert!(!StakePallet::collator_state(2) .unwrap() .delegators - .contains(&Stake { owner: 9, amount: 10 })); + .contains(&StakeOf:: { owner: 9, amount: 10 })); roll_to(26, vec![]); let mut new2 = vec![ @@ -984,11 +1064,11 @@ fn multiple_delegations() { roll_to(35, vec![]); assert_ok!(StakePallet::execute_leave_candidates(Origin::signed(2), 2)); - let mut unbonding_7 = BTreeMap::new(); - unbonding_7.insert(35u64 + ::StakeDuration::get() as u64, 80); + let mut unbonding_7 = BoundedBTreeMap::new(); + assert_ok!(unbonding_7.try_insert(35u64 + ::StakeDuration::get() as u64, 80)); assert_eq!(StakePallet::unstaking(7), unbonding_7); - let mut unbonding_11 = BTreeMap::new(); - unbonding_11.insert(35u64 + ::StakeDuration::get() as u64, 11); + let mut unbonding_11 = BoundedBTreeMap::new(); + assert_ok!(unbonding_11.try_insert(35u64 + ::StakeDuration::get() as u64, 11)); assert_eq!(StakePallet::unstaking(11), unbonding_11); roll_to(37, vec![]); @@ -1124,7 +1204,7 @@ fn should_update_total_stake() { let old_stake = StakePallet::total(); assert_eq!(StakePallet::collator_state(2).unwrap().total, 30); assert_eq!(StakePallet::collator_state(2).unwrap().stake, 20); - assert_eq!(StakePallet::selected_candidates(), vec![2, 1]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 1]); assert_eq!( StakePallet::collator_state(2).unwrap().stake, StakePallet::collator_state(3).unwrap().stake @@ -1136,7 +1216,7 @@ fn should_update_total_stake() { // replacement has the same self stake as 2 collators: old_stake.collators, }; - assert_eq!(StakePallet::selected_candidates(), vec![1, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 3]); assert_eq!(StakePallet::total(), old_stake); // shouldn't change total stake when 2 leaves @@ -1743,8 +1823,8 @@ fn coinbase_rewards_many_blocks_simple_check() { }); } -// Could only occur if we increase MinDelegatorStake via runtime upgrade and -// don't migrate delegators which fall below minimum +// Could only occur if we increase MinDelegatorStakeOf::via runtime +// upgrade and don't migrate delegators which fall below minimum #[test] fn should_not_reward_delegators_below_min_stake() { ExtBuilder::default() @@ -1759,11 +1839,11 @@ fn should_not_reward_delegators_below_min_stake() { let delegator_stake_below_min = ::MinDelegatorStake::get() - 1; state.stake += delegator_stake_below_min; state.total += delegator_stake_below_min; - let impossible_bond = Stake { + let impossible_bond = StakeOf:: { owner: 4u64, amount: delegator_stake_below_min, }; - state.delegators.insert(impossible_bond); + assert_eq!(state.delegators.try_insert(impossible_bond), Ok(true)); >::insert(&1u64, state); let authors: Vec> = vec![Some(1u64), Some(1u64), Some(1u64), Some(1u64)]; @@ -1846,8 +1926,9 @@ fn reach_max_collator_candidates() { StakePallet::candidate_pool().len().saturated_into::(), ::MaxCollatorCandidates::get() ); + // should not be possible to join candidate pool, even with more stake assert_noop!( - StakePallet::join_candidates(Origin::signed(11), 10), + StakePallet::join_candidates(Origin::signed(11), 11), Error::::TooManyCollatorCandidates ); }); @@ -2069,8 +2150,8 @@ fn unlock_unstaked() { // same_unstaked_as_restaked // block 1: stake & unstake for 100 // block 2: stake & unstake for 100 - // should remove first entry in unstaking BTreeMap when staking in block 2 - // should still have 100 locked until unlocking + // should remove first entry in unstaking BoundedBTreeMap when staking in block + // 2 should still have 100 locked until unlocking ExtBuilder::default() .with_balances(vec![(1, 10), (2, 100)]) .with_collators(vec![(1, 10)]) @@ -2078,8 +2159,8 @@ fn unlock_unstaked() { .build() .execute_with(|| { assert_ok!(StakePallet::revoke_delegation(Origin::signed(2), 1)); - let mut unstaking = BTreeMap::new(); - unstaking.insert(3, 100); + let mut unstaking = BoundedBTreeMap::new(); + assert_ok!(unstaking.try_insert(3, 100)); let lock = BalanceLock { id: STAKING_ID, amount: 100, @@ -2097,7 +2178,7 @@ fn unlock_unstaked() { assert_ok!(StakePallet::join_delegators(Origin::signed(2), 1, 100)); assert_ok!(StakePallet::revoke_delegation(Origin::signed(2), 1)); unstaking.remove(&3); - unstaking.insert(4, 100); + assert_ok!(unstaking.try_insert(4, 100)); assert_eq!(StakePallet::unstaking(2), unstaking); assert_eq!(Balances::locks(2), vec![lock.clone()]); // shouldn't be able to unlock anything @@ -2126,8 +2207,8 @@ fn unlock_unstaked() { // less_unstaked_than_restaked // block 1: stake & unstake for 10 // block 2: stake & unstake for 100 - // should remove first entry in unstaking BTreeMap when staking in block 2 - // should still have 90 locked until unlocking in block 4 + // should remove first entry in unstaking BoundedBTreeMap when staking in block + // 2 should still have 90 locked until unlocking in block 4 ExtBuilder::default() .with_balances(vec![(1, 10), (2, 100)]) .with_collators(vec![(1, 10)]) @@ -2135,8 +2216,8 @@ fn unlock_unstaked() { .build() .execute_with(|| { assert_ok!(StakePallet::revoke_delegation(Origin::signed(2), 1)); - let mut unstaking = BTreeMap::new(); - unstaking.insert(3, 10); + let mut unstaking = BoundedBTreeMap::new(); + assert_ok!(unstaking.try_insert(3, 10)); let mut lock = BalanceLock { id: STAKING_ID, amount: 10, @@ -2154,7 +2235,7 @@ fn unlock_unstaked() { assert_ok!(StakePallet::join_delegators(Origin::signed(2), 1, 100)); assert_ok!(StakePallet::revoke_delegation(Origin::signed(2), 1)); unstaking.remove(&3); - unstaking.insert(4, 100); + assert_ok!(unstaking.try_insert(4, 100)); lock.amount = 100; assert_eq!(StakePallet::unstaking(2), unstaking); assert_eq!(Balances::locks(2), vec![lock.clone()]); @@ -2183,8 +2264,8 @@ fn unlock_unstaked() { // more_unstaked_than_restaked // block 1: stake & unstake for 100 // block 2: stake & unstake for 10 - // should reduce first entry from amount 100 to 90 in unstaking BTreeMap when - // staking in block 2 + // should reduce first entry from amount 100 to 90 in unstaking BoundedBTreeMap + // when staking in block 2 // should have 100 locked until unlocking in block 3, then 10 // should have 10 locked until further unlocking in block 4 ExtBuilder::default() @@ -2194,8 +2275,8 @@ fn unlock_unstaked() { .build() .execute_with(|| { assert_ok!(StakePallet::revoke_delegation(Origin::signed(2), 1)); - let mut unstaking = BTreeMap::new(); - unstaking.insert(3, 100); + let mut unstaking = BoundedBTreeMap::new(); + assert_ok!(unstaking.try_insert(3, 100)); let mut lock = BalanceLock { id: STAKING_ID, amount: 100, @@ -2212,8 +2293,8 @@ fn unlock_unstaked() { roll_to(2, vec![]); assert_ok!(StakePallet::join_delegators(Origin::signed(2), 1, 10)); assert_ok!(StakePallet::revoke_delegation(Origin::signed(2), 1)); - unstaking.insert(3, 90); - unstaking.insert(4, 10); + assert_ok!(unstaking.try_insert(3, 90)); + assert_ok!(unstaking.try_insert(4, 10)); assert_eq!(StakePallet::unstaking(2), unstaking); assert_eq!(Balances::locks(2), vec![lock.clone()]); // shouldn't be able to unlock anything @@ -2244,8 +2325,8 @@ fn unlock_unstaked() { // test_stake_less // block 1: stake & unstake for 100 // block 2: stake & unstake for 10 - // should reduce first entry from amount 100 to 90 in unstaking BTreeMap when - // staking in block 2 + // should reduce first entry from amount 100 to 90 in unstaking BoundedBTreeMap + // when staking in block 2 // should have 100 locked until unlocking in block 3, then 10 // should have 10 locked until further unlocking in block 4 ExtBuilder::default() @@ -2269,8 +2350,8 @@ fn unlock_unstaked() { assert_ok!(StakePallet::delegator_stake_less(Origin::signed(2), 1, 10)); assert_ok!(StakePallet::delegator_stake_less(Origin::signed(2), 1, 10)); assert_ok!(StakePallet::delegator_stake_less(Origin::signed(2), 1, 10),); - let mut unstaking = BTreeMap::new(); - unstaking.insert(3, 60); + let mut unstaking = BoundedBTreeMap::new(); + assert_ok!(unstaking.try_insert(3, 60)); let mut lock = BalanceLock { id: STAKING_ID, amount: 200, @@ -2291,7 +2372,7 @@ fn unlock_unstaked() { roll_to(2, vec![]); assert_ok!(StakePallet::candidate_stake_less(Origin::signed(1), 10),); assert_ok!(StakePallet::delegator_stake_less(Origin::signed(2), 1, 10),); - unstaking.insert(4, 10); + assert_ok!(unstaking.try_insert(4, 10)); assert_eq!(Balances::locks(1), vec![lock.clone()]); assert_eq!(Balances::locks(2), vec![lock.clone()]); assert_eq!(StakePallet::unstaking(1), unstaking); @@ -2307,8 +2388,8 @@ fn unlock_unstaked() { roll_to(3, vec![]); assert_ok!(StakePallet::candidate_stake_less(Origin::signed(1), 10),); assert_ok!(StakePallet::delegator_stake_less(Origin::signed(2), 1, 10),); - unstaking.insert(5, 10); - unstaking.insert(5, 10); + assert_ok!(unstaking.try_insert(5, 10)); + assert_ok!(unstaking.try_insert(5, 10)); assert_eq!(Balances::locks(1), vec![lock.clone()]); assert_eq!(Balances::locks(2), vec![lock.clone()]); assert_eq!(StakePallet::unstaking(1), unstaking); @@ -2333,9 +2414,9 @@ fn unlock_unstaked() { roll_to(6, vec![]); assert_ok!(StakePallet::candidate_stake_less(Origin::signed(1), 10)); assert_ok!(StakePallet::delegator_stake_less(Origin::signed(2), 1, 10)); - unstaking.insert(6, 10); - unstaking.insert(7, 10); - unstaking.insert(8, 10); + assert_ok!(unstaking.try_insert(6, 10)); + assert_ok!(unstaking.try_insert(7, 10)); + assert_ok!(unstaking.try_insert(8, 10)); assert_eq!(StakePallet::unstaking(1), unstaking); assert_eq!(StakePallet::unstaking(2), unstaking); assert_eq!(Balances::locks(1), vec![lock.clone()]); @@ -2363,11 +2444,11 @@ fn unlock_unstaked() { assert_eq!(Balances::locks(2), vec![lock.clone()]); assert_ok!(StakePallet::candidate_stake_less(Origin::signed(1), 40)); assert_ok!(StakePallet::delegator_stake_less(Origin::signed(2), 1, 40)); - unstaking.insert(9, 40); + assert_ok!(unstaking.try_insert(9, 40)); assert_ok!(StakePallet::candidate_stake_more(Origin::signed(1), 30)); assert_ok!(StakePallet::delegator_stake_more(Origin::signed(2), 1, 30)); unstaking.remove(&8); - unstaking.insert(9, 20); + assert_ok!(unstaking.try_insert(9, 20)); assert_eq!(StakePallet::unstaking(1), unstaking); assert_eq!(StakePallet::unstaking(2), unstaking); assert_eq!(Balances::locks(1), vec![lock.clone()]); @@ -2431,8 +2512,8 @@ fn candidate_leaves() { StakePallet::execute_leave_candidates(Origin::signed(2), 1), Error::::CannotLeaveYet ); - // add 11 to max out CandidatePool and then leave again to enable 11 to cancel - // the exit request + // add 11 as candidate to reach max size for CandidatePool and then try leave + // again as 1 which should not be possible assert_ok!(StakePallet::join_candidates(Origin::signed(11), 100)); assert_noop!( StakePallet::cancel_leave_candidates(Origin::signed(1)), @@ -2444,9 +2525,12 @@ fn candidate_leaves() { let stake: Vec> = (1u64..11u64) .zip(iter::once(210).chain(iter::repeat(100))) - .map(|(id, amount)| Stake { owner: id, amount }) + .map(|(id, amount)| StakeOf:: { owner: id, amount }) .collect(); - assert_eq!(StakePallet::candidate_pool(), OrderedSet::from(stake)); + assert_eq!( + StakePallet::candidate_pool(), + OrderedSet::from(stake.try_into().unwrap()) + ); let state = StakePallet::collator_state(1).unwrap(); assert_eq!(state.state, CollatorStatus::Active); assert_eq!(state.delegators.len(), 2); @@ -2454,20 +2538,20 @@ fn candidate_leaves() { assert_eq!( state.total, StakePallet::candidate_pool() - .into_vec() + .into_bounded_vec() .iter() .find(|other| other.owner == 1) .unwrap() .amount ); - assert_eq!(StakePallet::selected_candidates(), vec![1, 2]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2]); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(1))); roll_to(15, vec![]); assert_ok!(StakePallet::execute_leave_candidates(Origin::signed(13), 1)); - let mut unstaking = BTreeMap::new(); - unstaking.insert(17, 100); + let mut unstaking = BoundedBTreeMap::new(); + assert_ok!(unstaking.try_insert(17, 100)); assert_eq!(StakePallet::unstaking(1), unstaking); assert_eq!(StakePallet::unstaking(12), unstaking); @@ -2598,14 +2682,18 @@ fn decrease_max_candidate_stake_by() { .with_delegators(vec![(4, 2, 10), (5, 3, 20)]) .build() .execute_with(|| { - assert_eq!(StakePallet::selected_candidates(), vec![1, 2]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2]); assert_eq!( StakePallet::candidate_pool(), - OrderedSet::from_sorted_set(vec![ - Stake { owner: 1, amount: 100 }, - Stake { owner: 2, amount: 100 }, - Stake { owner: 3, amount: 60 } - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 1, amount: 100 }, + StakeOf:: { owner: 2, amount: 100 }, + StakeOf:: { owner: 3, amount: 60 } + ] + .try_into() + .unwrap() + ) ); let max_stake = StakePallet::max_candidate_stake(); @@ -2622,43 +2710,57 @@ fn decrease_max_candidate_stake_by() { // check collator states assert_eq!( StakePallet::candidate_pool(), - OrderedSet::from_sorted_set(vec![ - Stake { owner: 2, amount: 60 }, - Stake { owner: 3, amount: 60 }, - Stake { owner: 1, amount: 50 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 2, amount: 60 }, + StakeOf:: { owner: 3, amount: 60 }, + StakeOf:: { owner: 1, amount: 50 }, + ] + .try_into() + .unwrap() + ) ); assert_eq!( StakePallet::collator_state(1), - Some(Collator { - id: 1, - stake: 50, - delegators: OrderedSet::from(vec![]), - total: 50, - state: CollatorStatus::Active - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: 1, + stake: 50, + delegators: OrderedSet::from(BoundedVec::default()), + total: 50, + state: CollatorStatus::Active + } + ) ); assert_eq!( StakePallet::collator_state(2), - Some(Collator { - id: 2, - stake: 50, - delegators: OrderedSet::from(vec![Stake { owner: 4, amount: 10 }]), - total: 60, - state: CollatorStatus::Active - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: 2, + stake: 50, + delegators: OrderedSet::from( + vec![StakeOf:: { owner: 4, amount: 10 }].try_into().unwrap() + ), + total: 60, + state: CollatorStatus::Active + } + ) ); assert_eq!( StakePallet::collator_state(3), - Some(Collator { - id: 3, - stake: 40, - delegators: OrderedSet::from(vec![Stake { owner: 5, amount: 20 }]), - total: 60, - state: CollatorStatus::Active - }) + Some( + Collator::::MaxDelegatorsPerCollator> { + id: 3, + stake: 40, + delegators: OrderedSet::from( + vec![StakeOf:: { owner: 5, amount: 20 }].try_into().unwrap() + ), + total: 60, + state: CollatorStatus::Active + } + ) ); - assert_eq!(StakePallet::selected_candidates(), vec![2, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 3]); assert_noop!( StakePallet::candidate_stake_more(Origin::signed(1), 0), @@ -2692,7 +2794,7 @@ fn exceed_delegations_per_round() { assert_ok!(StakePallet::delegate_another_candidate(Origin::signed(6), 4, 10)); assert_noop!( StakePallet::delegate_another_candidate(Origin::signed(6), 5, 10), - Error::::ExceedMaxCollatorsPerDelegator + Error::::MaxCollatorsPerDelegatorExceeded ); // revoke delegation to allow one more collator for this delegator @@ -2700,14 +2802,14 @@ fn exceed_delegations_per_round() { // reached max delegations in this round assert_noop!( StakePallet::delegate_another_candidate(Origin::signed(6), 5, 10), - Error::::ExceededDelegationsPerRound + Error::::DelegationsPerRoundExceeded ); // revoke all delegations in the same round assert_ok!(StakePallet::leave_delegators(Origin::signed(6))); assert_noop!( StakePallet::join_delegators(Origin::signed(6), 1, 10), - Error::::ExceededDelegationsPerRound + Error::::DelegationsPerRoundExceeded ); // roll to next round to clear DelegationCounter @@ -2734,7 +2836,7 @@ fn exceed_delegations_per_round() { ); assert_noop!( StakePallet::join_delegators(Origin::signed(6), 1, 10), - Error::::ExceededDelegationsPerRound + Error::::DelegationsPerRoundExceeded ); }); } @@ -2748,7 +2850,7 @@ fn force_remove_candidate() { .build() .execute_with(|| { assert_ok!(StakePallet::delegate_another_candidate(Origin::signed(4), 2, 50)); - assert_eq!(StakePallet::selected_candidates(), vec![1, 2]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2]); assert!(StakePallet::unstaking(1).get(&3).is_none()); assert!(StakePallet::unstaking(2).get(&3).is_none()); assert!(StakePallet::unstaking(3).get(&3).is_none()); @@ -2758,14 +2860,14 @@ fn force_remove_candidate() { assert_ok!(StakePallet::force_remove_candidate(Origin::root(), 1)); assert_eq!(Session::disabled_validators(), vec![0]); assert_eq!(last_event(), MetaEvent::StakePallet(Event::CollatorRemoved(1, 200))); - assert!(!StakePallet::candidate_pool().contains(&Stake { owner: 1, amount: 100 })); - assert_eq!(StakePallet::selected_candidates(), vec![2, 3]); + assert!(!StakePallet::candidate_pool().contains(&StakeOf:: { owner: 1, amount: 100 })); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 3]); assert!(StakePallet::collator_state(1).is_none()); assert!(StakePallet::delegator_state(5).is_none()); assert_eq!( StakePallet::delegator_state(4), Some(Delegator { - delegations: OrderedSet::from(vec![Stake { owner: 2, amount: 50 }]), + delegations: OrderedSet::from(vec![StakeOf:: { owner: 2, amount: 50 }].try_into().unwrap()), total: 50 }) ); @@ -2815,136 +2917,166 @@ fn prioritize_collators() { OrderedSet::from_sorted_set( vec![2, 3] .into_iter() - .map(|id| Stake { owner: id, amount: 100 }) + .map(|id| StakeOf:: { owner: id, amount: 100 }) .collect::>>() + .try_into() + .unwrap() ) ); - assert_eq!(StakePallet::selected_candidates(), vec![2, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 3]); assert_ok!(StakePallet::join_candidates(Origin::signed(1), 100)); assert_eq!( StakePallet::candidate_pool(), OrderedSet::from_sorted_set( vec![2, 3, 1] .into_iter() - .map(|id| Stake { owner: id, amount: 100 }) + .map(|id| StakeOf:: { owner: id, amount: 100 }) .collect::>>() + .try_into() + .unwrap() ) ); - assert_eq!(StakePallet::selected_candidates(), vec![2, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 3]); assert_ok!(StakePallet::init_leave_candidates(Origin::signed(2))); assert_eq!(StakePallet::candidate_pool().len(), 2); - assert_eq!(StakePallet::selected_candidates(), vec![3, 1]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![3, 1]); assert_ok!(StakePallet::candidate_stake_less(Origin::signed(3), 10)); - assert_eq!(StakePallet::selected_candidates(), vec![1, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 3]); // add 6 assert_ok!(StakePallet::join_candidates(Origin::signed(6), 100)); - assert_eq!(StakePallet::selected_candidates(), vec![1, 6]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 6]); assert_eq!( StakePallet::candidate_pool(), OrderedSet::from_sorted_set( vec![1, 6] .into_iter() - .map(|id| Stake { owner: id, amount: 100 }) - .chain(vec![Stake { owner: 3, amount: 90 }]) + .map(|id| StakeOf:: { owner: id, amount: 100 }) + .chain(vec![StakeOf:: { owner: 3, amount: 90 }]) .collect::>>() + .try_into() + .unwrap() ) ); // add 4 assert_ok!(StakePallet::join_candidates(Origin::signed(4), 100)); - assert_eq!(StakePallet::selected_candidates(), vec![1, 6]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 6]); assert_eq!( StakePallet::candidate_pool(), OrderedSet::from_sorted_set( vec![1, 6, 4] .into_iter() - .map(|id| Stake { owner: id, amount: 100 }) - .chain(vec![Stake { owner: 3, amount: 90 }]) + .map(|id| StakeOf:: { owner: id, amount: 100 }) + .chain(vec![StakeOf:: { owner: 3, amount: 90 }]) .collect::>>() + .try_into() + .unwrap() ) ); // add 5 assert_ok!(StakePallet::join_candidates(Origin::signed(5), 100)); - assert_eq!(StakePallet::selected_candidates(), vec![1, 6]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 6]); assert_eq!( StakePallet::candidate_pool(), OrderedSet::from_sorted_set( vec![1, 6, 4, 5] .into_iter() - .map(|id| Stake { owner: id, amount: 100 }) - .chain(vec![Stake { owner: 3, amount: 90 }]) + .map(|id| StakeOf:: { owner: id, amount: 100 }) + .chain(vec![StakeOf:: { owner: 3, amount: 90 }]) .collect::>>() + .try_into() + .unwrap() ) ); // 3 stake_more assert_ok!(StakePallet::candidate_stake_more(Origin::signed(3), 20)); - assert_eq!(StakePallet::selected_candidates(), vec![3, 1]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![3, 1]); assert_eq!( StakePallet::candidate_pool(), - OrderedSet::from_sorted_set(vec![ - Stake { owner: 3, amount: 110 }, - Stake { owner: 1, amount: 100 }, - Stake { owner: 6, amount: 100 }, - Stake { owner: 4, amount: 100 }, - Stake { owner: 5, amount: 100 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 3, amount: 110 }, + StakeOf:: { owner: 1, amount: 100 }, + StakeOf:: { owner: 6, amount: 100 }, + StakeOf:: { owner: 4, amount: 100 }, + StakeOf:: { owner: 5, amount: 100 }, + ] + .try_into() + .unwrap() + ) ); // 1 stake_less assert_ok!(StakePallet::candidate_stake_less(Origin::signed(1), 1)); - assert_eq!(StakePallet::selected_candidates(), vec![3, 6]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![3, 6]); assert_eq!( StakePallet::candidate_pool(), - OrderedSet::from_sorted_set(vec![ - Stake { owner: 3, amount: 110 }, - Stake { owner: 6, amount: 100 }, - Stake { owner: 4, amount: 100 }, - Stake { owner: 5, amount: 100 }, - Stake { owner: 1, amount: 99 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 3, amount: 110 }, + StakeOf:: { owner: 6, amount: 100 }, + StakeOf:: { owner: 4, amount: 100 }, + StakeOf:: { owner: 5, amount: 100 }, + StakeOf:: { owner: 1, amount: 99 }, + ] + .try_into() + .unwrap() + ) ); // 7 delegates to 4 assert_ok!(StakePallet::join_delegators(Origin::signed(7), 5, 20)); - assert_eq!(StakePallet::selected_candidates(), vec![5, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![5, 3]); assert_eq!( StakePallet::candidate_pool(), - OrderedSet::from_sorted_set(vec![ - Stake { owner: 5, amount: 120 }, - Stake { owner: 3, amount: 110 }, - Stake { owner: 6, amount: 100 }, - Stake { owner: 4, amount: 100 }, - Stake { owner: 1, amount: 99 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 5, amount: 120 }, + StakeOf:: { owner: 3, amount: 110 }, + StakeOf:: { owner: 6, amount: 100 }, + StakeOf:: { owner: 4, amount: 100 }, + StakeOf:: { owner: 1, amount: 99 }, + ] + .try_into() + .unwrap() + ) ); // 7 decreases delegation assert_ok!(StakePallet::delegator_stake_less(Origin::signed(7), 5, 10)); - assert_eq!(StakePallet::selected_candidates(), vec![5, 3]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![5, 3]); assert_eq!( StakePallet::candidate_pool(), - OrderedSet::from_sorted_set(vec![ - Stake { owner: 5, amount: 110 }, - Stake { owner: 3, amount: 110 }, - Stake { owner: 6, amount: 100 }, - Stake { owner: 4, amount: 100 }, - Stake { owner: 1, amount: 99 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 5, amount: 110 }, + StakeOf:: { owner: 3, amount: 110 }, + StakeOf:: { owner: 6, amount: 100 }, + StakeOf:: { owner: 4, amount: 100 }, + StakeOf:: { owner: 1, amount: 99 }, + ] + .try_into() + .unwrap() + ) ); assert_ok!(StakePallet::revoke_delegation(Origin::signed(7), 5)); - assert_eq!(StakePallet::selected_candidates(), vec![3, 5]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![3, 5]); assert_eq!( StakePallet::candidate_pool(), - OrderedSet::from_sorted_set(vec![ - Stake { owner: 3, amount: 110 }, - Stake { owner: 5, amount: 100 }, - Stake { owner: 6, amount: 100 }, - Stake { owner: 4, amount: 100 }, - Stake { owner: 1, amount: 99 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 3, amount: 110 }, + StakeOf:: { owner: 5, amount: 100 }, + StakeOf:: { owner: 6, amount: 100 }, + StakeOf:: { owner: 4, amount: 100 }, + StakeOf:: { owner: 1, amount: 99 }, + ] + .try_into() + .unwrap() + ) ); }); } @@ -2965,66 +3097,100 @@ fn prioritize_delegators() { .with_delegators(vec![(5, 1, 100), (4, 2, 100), (7, 2, 100), (6, 2, 100)]) .build() .execute_with(|| { - assert_eq!(StakePallet::selected_candidates(), vec![2, 1]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 1]); assert_eq!( StakePallet::collator_state(2).unwrap().delegators, - OrderedSet::from_sorted_set(vec![ - Stake { owner: 4, amount: 100 }, - Stake { owner: 7, amount: 100 }, - Stake { owner: 6, amount: 100 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 4, amount: 100 }, + StakeOf:: { owner: 7, amount: 100 }, + StakeOf:: { owner: 6, amount: 100 }, + ] + .try_into() + .unwrap() + ) ); assert_ok!(StakePallet::delegate_another_candidate(Origin::signed(5), 2, 110)); assert_eq!( StakePallet::collator_state(2).unwrap().delegators, - OrderedSet::from_sorted_set(vec![ - Stake { owner: 5, amount: 110 }, - Stake { owner: 4, amount: 100 }, - Stake { owner: 7, amount: 100 }, - Stake { owner: 6, amount: 100 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 5, amount: 110 }, + StakeOf:: { owner: 4, amount: 100 }, + StakeOf:: { owner: 7, amount: 100 }, + StakeOf:: { owner: 6, amount: 100 }, + ] + .try_into() + .unwrap() + ) ); assert_eq!( StakePallet::delegator_state(5).unwrap().delegations, - OrderedSet::from_sorted_set(vec![Stake { owner: 2, amount: 110 }, Stake { owner: 1, amount: 100 },]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 2, amount: 110 }, + StakeOf:: { owner: 1, amount: 100 } + ] + .try_into() + .unwrap() + ) ); // delegate_less assert_ok!(StakePallet::delegator_stake_less(Origin::signed(5), 2, 10)); assert_eq!( StakePallet::collator_state(2).unwrap().delegators, - OrderedSet::from_sorted_set(vec![ - Stake { owner: 5, amount: 100 }, - Stake { owner: 4, amount: 100 }, - Stake { owner: 7, amount: 100 }, - Stake { owner: 6, amount: 100 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 5, amount: 100 }, + StakeOf:: { owner: 4, amount: 100 }, + StakeOf:: { owner: 7, amount: 100 }, + StakeOf:: { owner: 6, amount: 100 }, + ] + .try_into() + .unwrap() + ) ); assert_eq!( StakePallet::delegator_state(5).unwrap().delegations, - OrderedSet::from_sorted_set(vec![Stake { owner: 2, amount: 100 }, Stake { owner: 1, amount: 100 },]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 2, amount: 100 }, + StakeOf:: { owner: 1, amount: 100 } + ] + .try_into() + .unwrap() + ) ); // delegate_more assert_ok!(StakePallet::delegator_stake_more(Origin::signed(6), 2, 10)); assert_eq!( StakePallet::collator_state(2).unwrap().delegators, - OrderedSet::from_sorted_set(vec![ - Stake { owner: 6, amount: 110 }, - Stake { owner: 5, amount: 100 }, - Stake { owner: 4, amount: 100 }, - Stake { owner: 7, amount: 100 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 6, amount: 110 }, + StakeOf:: { owner: 5, amount: 100 }, + StakeOf:: { owner: 4, amount: 100 }, + StakeOf:: { owner: 7, amount: 100 }, + ] + .try_into() + .unwrap() + ) ); assert_ok!(StakePallet::delegator_stake_more(Origin::signed(7), 2, 10)); assert_eq!( StakePallet::collator_state(2).unwrap().delegators, - OrderedSet::from_sorted_set(vec![ - Stake { owner: 6, amount: 110 }, - Stake { owner: 7, amount: 110 }, - Stake { owner: 5, amount: 100 }, - Stake { owner: 4, amount: 100 }, - ]) + OrderedSet::from_sorted_set( + vec![ + StakeOf:: { owner: 6, amount: 110 }, + StakeOf:: { owner: 7, amount: 110 }, + StakeOf:: { owner: 5, amount: 100 }, + StakeOf:: { owner: 4, amount: 100 }, + ] + .try_into() + .unwrap() + ) ); }); } @@ -3049,7 +3215,7 @@ fn authorities_per_round() { .with_collators(vec![(1, stake), (2, stake), (3, stake), (4, stake)]) .build() .execute_with(|| { - assert_eq!(StakePallet::selected_candidates(), vec![1, 2]); + assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2]); // reward 1 once per round let authors: Vec> = (0u64..=100) .map(|i| if i % 5 == 2 { Some(1u64) } else { None }) diff --git a/pallets/parachain-staking/src/types.rs b/pallets/parachain-staking/src/types.rs index 3d6a9c7079..38255362bd 100644 --- a/pallets/parachain-staking/src/types.rs +++ b/pallets/parachain-staking/src/types.rs @@ -16,7 +16,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use frame_support::traits::Currency; +use frame_support::traits::{Currency, Get}; use parity_scale_codec::{Decode, Encode}; use sp_runtime::{ traits::{AtLeast32BitUnsigned, Saturating, Zero}, @@ -25,6 +25,7 @@ use sp_runtime::{ use sp_staking::SessionIndex; use sp_std::{ cmp::Ordering, + convert::TryInto, fmt::Debug, ops::{Add, Sub}, vec, @@ -100,12 +101,13 @@ impl Default for CollatorStatus { } } -#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq)] +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)] /// Global collator state with commission fee, staked funds, and delegations -pub struct Collator +pub struct Collator where AccountId: Eq + Ord + Debug, Balance: Eq + Ord + Debug, + MaxDelegatorsPerCollator: Get + Debug + PartialEq, { /// The collators account id. pub id: AccountId, @@ -114,7 +116,7 @@ where pub stake: Balance, /// The delegators that back the collator. - pub delegators: OrderedSet>, + pub delegators: OrderedSet, MaxDelegatorsPerCollator>, /// The total backing a collator has. /// @@ -126,10 +128,11 @@ where pub state: CollatorStatus, } -impl Collator +impl Collator where A: Ord + Clone + Debug, B: AtLeast32BitUnsigned + Ord + Copy + Saturating + Debug + Zero, + S: Get + Debug + PartialEq, { pub fn new(id: A, stake: B) -> Self { let total = stake; @@ -203,37 +206,41 @@ where } #[derive(Encode, Decode, RuntimeDebug, PartialEq)] -pub struct Delegator { - pub delegations: OrderedSet>, +pub struct Delegator> { + pub delegations: OrderedSet, MaxCollatorsPerDelegator>, pub total: Balance, } -impl Delegator +impl Delegator where AccountId: Eq + Ord + Clone + Debug, Balance: Copy + Add + Saturating + PartialOrd + Eq + Ord + Debug + Zero, + MaxCollatorsPerDelegator: Get + Debug + PartialEq, { - pub fn new(collator: AccountId, amount: Balance) -> Self { - Delegator { - delegations: OrderedSet::from(vec![Stake { - owner: collator, - amount, - }]), + pub fn try_new(collator: AccountId, amount: Balance) -> Result { + Ok(Delegator { + delegations: OrderedSet::from( + vec![Stake { + owner: collator, + amount, + }] + .try_into()?, + ), total: amount, - } + }) } /// Adds a new delegation. /// /// If already delegating to the same account, this call returns false and /// doesn't insert the new delegation. - pub fn add_delegation(&mut self, stake: Stake) -> bool { + pub fn add_delegation(&mut self, stake: Stake) -> Result { let amt = stake.amount; - if self.delegations.insert(stake) { + if self.delegations.try_insert(stake)? { self.total = self.total.saturating_add(amt); - true + Ok(true) } else { - false + Ok(false) } } @@ -354,25 +361,7 @@ pub struct DelegationCounter { pub counter: u32, } -// A value placed in storage that represents the current version of the Staking -// storage. This value is used by the `on_runtime_upgrade` logic to determine -// whether we run storage migration logic. This should match directly with the -// semantic versions of the Rust crate. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug)] -pub enum Releases { - V1_0_0, - V2_0_0, // New Reward calculation, MaxCollatorCandidateStake - V3_0_0, // Update InflationConfig - V4, // Sort CandidatePool and delegations by amount -} - -impl Default for Releases { - fn default() -> Self { - Releases::V3_0_0 - } -} - pub type AccountIdOf = ::AccountId; pub type BalanceOf = <::Currency as Currency>>::Balance; -pub type CollatorOf = Collator, BalanceOf>; +pub type CollatorOf = Collator, BalanceOf, S>; pub type StakeOf = Stake, BalanceOf>; diff --git a/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index d8f9652a9b..7b65cbdcdc 100644 --- a/runtimes/peregrine/src/lib.rs +++ b/runtimes/peregrine/src/lib.rs @@ -121,7 +121,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("mashnet-node"), impl_name: create_runtime_str!("mashnet-node"), authoring_version: 4, - spec_version: 19, + spec_version: 20, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, @@ -651,16 +651,25 @@ impl delegation::VerifyDelegateSignature for Runtime { } } +parameter_types! { + // TODO: Find reasonable number + pub const MaxDelegatedAttestations: u32 = 1000; +} + impl attestation::Config for Runtime { type EnsureOrigin = EnsureSigned<::DelegationEntityId>; type Event = Event; type WeightInfo = weights::attestation::WeightInfo; + type MaxDelegatedAttestations = MaxDelegatedAttestations; } parameter_types! { pub const MaxSignatureByteLength: u16 = 64; pub const MaxParentChecks: u32 = 5; pub const MaxRevocations: u32 = 5; + // TODO: Find reasonable number + #[derive(Clone)] + pub const MaxChildren: u32 = 1000; } impl delegation::Config for Runtime { @@ -672,6 +681,7 @@ impl delegation::Config for Runtime { type MaxSignatureByteLength = MaxSignatureByteLength; type MaxParentChecks = MaxParentChecks; type MaxRevocations = MaxRevocations; + type MaxChildren = MaxChildren; type WeightInfo = weights::delegation::WeightInfo; } @@ -685,8 +695,14 @@ impl ctype::Config for Runtime { parameter_types! { pub const MaxNewKeyAgreementKeys: u32 = 10u32; pub const MaxVerificationKeysToRevoke: u32 = 10u32; + #[derive(Debug, Clone, PartialEq)] pub const MaxUrlLength: u32 = 200u32; - pub const MaxUrlsEndpointCounts: u32 = 3u32; + // TODO: Find reasonable numbers + pub const MaxPublicKeysPerDid: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxTotalKeyAgreementKeys: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxEndpointUrlsCount: u32 = 3u32; } impl did::Config for Runtime { @@ -699,9 +715,11 @@ impl did::Config for Runtime { #[cfg(feature = "runtime-benchmarks")] type EnsureOrigin = EnsureSigned; type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type MaxPublicKeysPerDid = MaxPublicKeysPerDid; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; - type MaxEndpointUrlsCount = MaxUrlsEndpointCounts; + type MaxEndpointUrlsCount = MaxEndpointUrlsCount; type WeightInfo = weights::did::WeightInfo; } @@ -747,14 +765,17 @@ parameter_types! { /// We only allow one delegation per round. pub const MaxDelegationsPerRound: u32 = 1; /// Maximum 25 delegators per collator at launch, might be increased later + #[derive(Debug, PartialEq)] pub const MaxDelegatorsPerCollator: u32 = 25; /// Maximum 1 collator per delegator at launch, will be increased later + #[derive(Debug, PartialEq)] pub const MaxCollatorsPerDelegator: u32 = 1; /// Minimum stake required to be reserved to be a collator is 10_000 pub const MinCollatorStake: Balance = 10_000 * KILT; /// Minimum stake required to be reserved to be a delegator is 1000 pub const MinDelegatorStake: Balance = 1000 * KILT; /// Maximum number of collator candidates + #[derive(Debug, PartialEq)] pub const MaxCollatorCandidates: u32 = MAX_CANDIDATES; /// Maximum number of concurrent requests to unlock unstaked balance pub const MaxUnstakeRequests: u32 = 10; diff --git a/runtimes/peregrine/src/weights/attestation.rs b/runtimes/peregrine/src/weights/attestation.rs index ca84370d96..610f1db455 100644 --- a/runtimes/peregrine/src/weights/attestation.rs +++ b/runtimes/peregrine/src/weights/attestation.rs @@ -19,24 +19,22 @@ //! Autogenerated weights for attestation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-07-21, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-08-11, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// target/release/kilt-parachain +// /home/willi/mashnet-node/target/release/kilt-parachain // benchmark // --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=attestation +// --extrinsic=* // --execution=wasm -// --wasm-execution=Compiled +// --wasm-execution=compiled // --heap-pages=4096 -// --extrinsic=* -// --pallet=attestation -// --steps=1 -// --repeat=20 -// --output -// runtimes/peregrine/src/weights/attestation.rs -// --template -// .maintain/runtime-weight-template.hbs +// --output=../../runtimes/peregrine/src/weights/attestation.rs +// --template=../../.maintain/runtime-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -50,14 +48,14 @@ use sp_std::marker::PhantomData; pub struct WeightInfo(PhantomData); impl attestation::WeightInfo for WeightInfo { fn add() -> Weight { - (68_138_000_u64) + (70_502_000_u64) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn revoke(d: u32, ) -> Weight { - (46_806_000_u64) - // Standard Error: 134_000 - .saturating_add((8_122_000_u64).saturating_mul(d as Weight)) + (46_447_000_u64) + // Standard Error: 142_000 + .saturating_add((8_535_000_u64).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(d as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) diff --git a/runtimes/peregrine/src/weights/delegation.rs b/runtimes/peregrine/src/weights/delegation.rs index f77437b42c..fd6d6b4403 100644 --- a/runtimes/peregrine/src/weights/delegation.rs +++ b/runtimes/peregrine/src/weights/delegation.rs @@ -19,24 +19,22 @@ //! Autogenerated weights for delegation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-07-21, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-08-11, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// target/release/kilt-parachain +// /home/willi/mashnet-node/target/release/kilt-parachain // benchmark // --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=delegation +// --extrinsic=* // --execution=wasm -// --wasm-execution=Compiled +// --wasm-execution=compiled // --heap-pages=4096 -// --extrinsic=* -// --pallet=delegation -// --steps=1 -// --repeat=20 -// --output -// runtimes/peregrine/src/weights/delegation.rs -// --template -// .maintain/runtime-weight-template.hbs +// --output=../../runtimes/peregrine/src/weights/delegation.rs +// --template=../../.maintain/runtime-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -50,31 +48,31 @@ use sp_std::marker::PhantomData; pub struct WeightInfo(PhantomData); impl delegation::WeightInfo for WeightInfo { fn create_hierarchy() -> Weight { - (48_641_000_u64) + (44_884_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn add_delegation() -> Weight { - (130_555_000_u64) + (132_107_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn revoke_delegation_root_child(r: u32, c: u32, ) -> Weight { - (24_607_000_u64) - // Standard Error: 425_000 - .saturating_add((30_915_000_u64).saturating_mul(r as Weight)) - // Standard Error: 425_000 - .saturating_add((860_000_u64).saturating_mul(c as Weight)) + (25_302_000_u64) + // Standard Error: 224_000 + .saturating_add((30_533_000_u64).saturating_mul(r as Weight)) + // Standard Error: 224_000 + .saturating_add((682_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r as Weight))) } fn revoke_delegation_leaf(r: u32, c: u32, ) -> Weight { - (58_402_000_u64) - // Standard Error: 307_000 + (58_744_000_u64) + // Standard Error: 71_000 .saturating_add((57_000_u64).saturating_mul(r as Weight)) - // Standard Error: 307_000 - .saturating_add((8_464_000_u64).saturating_mul(c as Weight)) + // Standard Error: 71_000 + .saturating_add((8_080_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) diff --git a/runtimes/peregrine/src/weights/did.rs b/runtimes/peregrine/src/weights/did.rs index 88109a2ffe..01a4b31f4d 100644 --- a/runtimes/peregrine/src/weights/did.rs +++ b/runtimes/peregrine/src/weights/did.rs @@ -19,24 +19,22 @@ //! Autogenerated weights for did //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-08-05, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-08-11, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// target/release/kilt-parachain +// /home/willi/mashnet-node/target/release/kilt-parachain // benchmark // --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=did +// --extrinsic=* // --execution=wasm -// --wasm-execution=Compiled +// --wasm-execution=compiled // --heap-pages=4096 -// --extrinsic=* -// --pallet=did -// --steps=1 -// --repeat=20 -// --output -// runtimes/peregrine/src/weights/did.rs -// --template -// .maintain/runtime-weight-template.hbs +// --output=../../runtimes/peregrine/src/weights/did.rs +// --template=../../.maintain/runtime-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -50,90 +48,90 @@ use sp_std::marker::PhantomData; pub struct WeightInfo(PhantomData); impl did::WeightInfo for WeightInfo { fn create_ed25519_keys(n: u32, u: u32, c: u32, ) -> Weight { - (119_310_000_u64) - // Standard Error: 23_000 - .saturating_add((2_712_000_u64).saturating_mul(n as Weight)) - // Standard Error: 1_000 - .saturating_add((22_000_u64).saturating_mul(u as Weight)) - // Standard Error: 104_000 - .saturating_add((2_170_000_u64).saturating_mul(c as Weight)) + (124_352_000_u64) + // Standard Error: 68_000 + .saturating_add((2_536_000_u64).saturating_mul(n as Weight)) + // Standard Error: 2_000 + .saturating_add((17_000_u64).saturating_mul(u as Weight)) + // Standard Error: 466_000 + .saturating_add((1_211_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - fn create_sr25519_keys(n: u32, u: u32, _c: u32, ) -> Weight { - (135_322_000_u64) - // Standard Error: 96_000 - .saturating_add((2_885_000_u64).saturating_mul(n as Weight)) - // Standard Error: 4_000 - .saturating_add((26_000_u64).saturating_mul(u as Weight)) + fn create_sr25519_keys(n: u32, u: u32, c: u32, ) -> Weight { + (120_475_000_u64) + // Standard Error: 67_000 + .saturating_add((2_882_000_u64).saturating_mul(n as Weight)) + // Standard Error: 2_000 + .saturating_add((29_000_u64).saturating_mul(u as Weight)) + // Standard Error: 458_000 + .saturating_add((2_584_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - fn create_ecdsa_keys(n: u32, u: u32, c: u32, ) -> Weight { - (252_507_000_u64) - // Standard Error: 111_000 - .saturating_add((2_516_000_u64).saturating_mul(n as Weight)) - // Standard Error: 5_000 - .saturating_add((4_000_u64).saturating_mul(u as Weight)) - // Standard Error: 502_000 - .saturating_add((1_663_000_u64).saturating_mul(c as Weight)) + fn create_ecdsa_keys(n: u32, u: u32, _c: u32, ) -> Weight { + (259_304_000_u64) + // Standard Error: 151_000 + .saturating_add((2_977_000_u64).saturating_mul(n as Weight)) + // Standard Error: 4_000 + .saturating_add((16_000_u64).saturating_mul(u as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn update_ed25519_keys(n: u32, m: u32, u: u32, c: u32, ) -> Weight { - (46_422_000_u64) - // Standard Error: 52_000 - .saturating_add((4_590_000_u64).saturating_mul(n as Weight)) - // Standard Error: 52_000 - .saturating_add((2_147_000_u64).saturating_mul(m as Weight)) - // Standard Error: 2_000 - .saturating_add((2_000_u64).saturating_mul(u as Weight)) - // Standard Error: 237_000 - .saturating_add((1_038_000_u64).saturating_mul(c as Weight)) + (60_412_000_u64) + // Standard Error: 55_000 + .saturating_add((2_652_000_u64).saturating_mul(n as Weight)) + // Standard Error: 55_000 + .saturating_add((783_000_u64).saturating_mul(m as Weight)) + // Standard Error: 1_000 + .saturating_add((7_000_u64).saturating_mul(u as Weight)) + // Standard Error: 382_000 + .saturating_add((531_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn update_sr25519_keys(n: u32, m: u32, u: u32, c: u32, ) -> Weight { - (43_904_000_u64) - // Standard Error: 47_000 - .saturating_add((4_510_000_u64).saturating_mul(n as Weight)) - // Standard Error: 47_000 - .saturating_add((2_511_000_u64).saturating_mul(m as Weight)) - // Standard Error: 2_000 - .saturating_add((2_000_u64).saturating_mul(u as Weight)) - // Standard Error: 213_000 - .saturating_add((893_000_u64).saturating_mul(c as Weight)) + (58_671_000_u64) + // Standard Error: 60_000 + .saturating_add((2_604_000_u64).saturating_mul(n as Weight)) + // Standard Error: 60_000 + .saturating_add((691_000_u64).saturating_mul(m as Weight)) + // Standard Error: 1_000 + .saturating_add((1_000_u64).saturating_mul(u as Weight)) + // Standard Error: 413_000 + .saturating_add((1_878_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - fn update_ecdsa_keys(n: u32, m: u32, u: u32, _c: u32, ) -> Weight { - (47_917_000_u64) + fn update_ecdsa_keys(n: u32, m: u32, _u: u32, c: u32, ) -> Weight { + (64_904_000_u64) // Standard Error: 79_000 - .saturating_add((4_531_000_u64).saturating_mul(n as Weight)) + .saturating_add((2_370_000_u64).saturating_mul(n as Weight)) // Standard Error: 79_000 - .saturating_add((2_648_000_u64).saturating_mul(m as Weight)) - // Standard Error: 3_000 - .saturating_add((6_000_u64).saturating_mul(u as Weight)) + .saturating_add((606_000_u64).saturating_mul(m as Weight)) + // Standard Error: 543_000 + .saturating_add((1_365_000_u64).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn delete() -> Weight { - (33_142_000_u64) + (33_893_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn submit_did_call_ed25519_key() -> Weight { - (113_963_000_u64) + (113_122_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn submit_did_call_sr25519_key() -> Weight { - (117_320_000_u64) + (115_356_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn submit_did_call_ecdsa_key() -> Weight { - (241_051_000_u64) + (236_744_000_u64) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } diff --git a/runtimes/peregrine/src/weights/kilt_launch.rs b/runtimes/peregrine/src/weights/kilt_launch.rs index 39e5b68c99..e37687b5f2 100644 --- a/runtimes/peregrine/src/weights/kilt_launch.rs +++ b/runtimes/peregrine/src/weights/kilt_launch.rs @@ -19,13 +19,13 @@ //! Autogenerated weights for kilt_launch //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-22, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2021-08-11, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("spiritnet-dev"), DB CACHE: 128 // Executed Command: // /home/willi/mashnet-node/target/release/kilt-parachain // benchmark -// --chain=dev +// --chain=spiritnet-dev // --execution=wasm // --wasm-execution=Compiled // --heap-pages=4096 @@ -50,49 +50,49 @@ use sp_std::marker::PhantomData; pub struct WeightInfo(PhantomData); impl kilt_launch::WeightInfo for WeightInfo { fn change_transfer_account() -> Weight { - (4_017_000_u64) + (4_168_000_u64) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn force_unlock(n: u32, ) -> Weight { - (20_199_000_u64) - // Standard Error: 129_000 - .saturating_add((45_058_000_u64).saturating_mul(n as Weight)) + (23_761_000_u64) + // Standard Error: 80_000 + .saturating_add((42_480_000_u64).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } fn locked_transfer() -> Weight { - (208_410_000_u64) + (183_684_000_u64) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } fn migrate_genesis_account_vesting() -> Weight { - (220_042_000_u64) + (210_053_000_u64) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } fn migrate_genesis_account_locking() -> Weight { - (226_475_000_u64) + (220_813_000_u64) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } fn migrate_multiple_genesis_accounts_vesting(n: u32, ) -> Weight { - (32_383_000_u64) - // Standard Error: 366_000 - .saturating_add((151_532_000_u64).saturating_mul(n as Weight)) + (65_896_000_u64) + // Standard Error: 214_000 + .saturating_add((143_552_000_u64).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } fn migrate_multiple_genesis_accounts_locking(n: u32, ) -> Weight { - (84_731_000_u64) - // Standard Error: 273_000 - .saturating_add((152_555_000_u64).saturating_mul(n as Weight)) + (79_825_000_u64) + // Standard Error: 212_000 + .saturating_add((145_386_000_u64).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(4_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } -} \ No newline at end of file +} diff --git a/runtimes/peregrine/src/weights/parachain_staking.rs b/runtimes/peregrine/src/weights/parachain_staking.rs index 6ae47a5e13..8172d26ab8 100644 --- a/runtimes/peregrine/src/weights/parachain_staking.rs +++ b/runtimes/peregrine/src/weights/parachain_staking.rs @@ -19,7 +19,7 @@ //! Autogenerated weights for parachain_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-07-09, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! DATE: 2021-08-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("spiritnet-dev"), DB CACHE: 128 // Executed Command: @@ -34,7 +34,7 @@ // --steps=50 // --repeat=20 // --output -// ../../runtimes/spiritnet/src/weights/parachain_staking.rs +// ../../runtimes/peregrine/src/weights/parachain_staking.rs // --template // ../../.maintain/runtime-weight-template.hbs diff --git a/runtimes/spiritnet/src/lib.rs b/runtimes/spiritnet/src/lib.rs index e881c7c16b..5eb559e0e0 100644 --- a/runtimes/spiritnet/src/lib.rs +++ b/runtimes/spiritnet/src/lib.rs @@ -102,7 +102,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("kilt-spiritnet"), impl_name: create_runtime_str!("kilt-spiritnet"), authoring_version: 1, - spec_version: 19, + spec_version: 20, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, @@ -364,14 +364,17 @@ parameter_types! { /// We only allow one delegation per round. pub const MaxDelegationsPerRound: u32 = 1; /// Maximum 25 delegators per collator at launch, might be increased later + #[derive(Debug, PartialEq)] pub const MaxDelegatorsPerCollator: u32 = 25; /// Maximum 1 collator per delegator at launch, will be increased later + #[derive(Debug, PartialEq)] pub const MaxCollatorsPerDelegator: u32 = 1; /// Minimum stake required to be reserved to be a collator is 10_000 pub const MinCollatorStake: Balance = 10_000 * KILT; /// Minimum stake required to be reserved to be a delegator is 1000 pub const MinDelegatorStake: Balance = 1000 * KILT; /// Maximum number of collator candidates + #[derive(Debug, PartialEq)] pub const MaxCollatorCandidates: u32 = 75; /// Maximum number of concurrent requests to unlock unstaked balance pub const MaxUnstakeRequests: u32 = 10; diff --git a/runtimes/spiritnet/src/weights/kilt_launch.rs b/runtimes/spiritnet/src/weights/kilt_launch.rs index c6970233df..e9a8c93e9f 100644 --- a/runtimes/spiritnet/src/weights/kilt_launch.rs +++ b/runtimes/spiritnet/src/weights/kilt_launch.rs @@ -19,13 +19,13 @@ //! Autogenerated weights for kilt_launch //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-22, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! DATE: 2021-08-11, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("spiritnet-dev"), DB CACHE: 128 // Executed Command: // /home/willi/mashnet-node/target/release/kilt-parachain // benchmark -// --chain=dev +// --chain=spiritnet-dev // --execution=wasm // --wasm-execution=Compiled // --heap-pages=4096 @@ -50,46 +50,46 @@ use sp_std::marker::PhantomData; pub struct WeightInfo(PhantomData); impl kilt_launch::WeightInfo for WeightInfo { fn change_transfer_account() -> Weight { - (4_017_000_u64) + (4_168_000_u64) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn force_unlock(n: u32, ) -> Weight { - (20_199_000_u64) - // Standard Error: 129_000 - .saturating_add((45_058_000_u64).saturating_mul(n as Weight)) + (23_761_000_u64) + // Standard Error: 80_000 + .saturating_add((42_480_000_u64).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } fn locked_transfer() -> Weight { - (208_410_000_u64) + (183_684_000_u64) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } fn migrate_genesis_account_vesting() -> Weight { - (220_042_000_u64) + (210_053_000_u64) .saturating_add(T::DbWeight::get().reads(9_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } fn migrate_genesis_account_locking() -> Weight { - (226_475_000_u64) + (220_813_000_u64) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } fn migrate_multiple_genesis_accounts_vesting(n: u32, ) -> Weight { - (32_383_000_u64) - // Standard Error: 366_000 - .saturating_add((151_532_000_u64).saturating_mul(n as Weight)) + (65_896_000_u64) + // Standard Error: 214_000 + .saturating_add((143_552_000_u64).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(3_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(n as Weight))) } fn migrate_multiple_genesis_accounts_locking(n: u32, ) -> Weight { - (84_731_000_u64) - // Standard Error: 273_000 - .saturating_add((152_555_000_u64).saturating_mul(n as Weight)) + (79_825_000_u64) + // Standard Error: 212_000 + .saturating_add((145_386_000_u64).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n as Weight))) .saturating_add(T::DbWeight::get().writes(4_u64)) diff --git a/runtimes/spiritnet/src/weights/parachain_staking.rs b/runtimes/spiritnet/src/weights/parachain_staking.rs index 6ae47a5e13..a8906df122 100644 --- a/runtimes/spiritnet/src/weights/parachain_staking.rs +++ b/runtimes/spiritnet/src/weights/parachain_staking.rs @@ -19,7 +19,7 @@ //! Autogenerated weights for parachain_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-07-09, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! DATE: 2021-08-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("spiritnet-dev"), DB CACHE: 128 // Executed Command: diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index c10a871ed0..6c04345d61 100644 --- a/runtimes/standalone/src/lib.rs +++ b/runtimes/standalone/src/lib.rs @@ -109,7 +109,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("mashnet-node"), impl_name: create_runtime_str!("mashnet-node"), authoring_version: 4, - spec_version: 19, + spec_version: 20, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, @@ -329,16 +329,25 @@ impl pallet_sudo::Config for Runtime { type Call = Call; } +parameter_types! { + // TODO: Find reasonable number + pub const MaxDelegatedAttestations: u32 = 1000; +} + impl attestation::Config for Runtime { type EnsureOrigin = EnsureSigned<::DelegationEntityId>; type Event = Event; type WeightInfo = (); + type MaxDelegatedAttestations = MaxDelegatedAttestations; } parameter_types! { pub const MaxSignatureByteLength: u16 = 64; pub const MaxParentChecks: u32 = 5; pub const MaxRevocations: u32 = 5; + // TODO: Find reasonable number + #[derive(Clone)] + pub const MaxChildren: u32 = 1000; } impl delegation::Config for Runtime { @@ -350,6 +359,7 @@ impl delegation::Config for Runtime { type MaxSignatureByteLength = MaxSignatureByteLength; type MaxParentChecks = MaxParentChecks; type MaxRevocations = MaxRevocations; + type MaxChildren = MaxChildren; type WeightInfo = (); } @@ -363,8 +373,14 @@ impl ctype::Config for Runtime { parameter_types! { pub const MaxNewKeyAgreementKeys: u32 = 10u32; pub const MaxVerificationKeysToRevoke: u32 = 10u32; + #[derive(Debug, Clone, PartialEq)] pub const MaxUrlLength: u32 = 200u32; - pub const MaxUrlsEndpointCounts: u32 = 3u32; + // TODO: Find reasonable numbers + pub const MaxPublicKeysPerDid: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxTotalKeyAgreementKeys: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxEndpointUrlsCount: u32 = 3u32; } impl did::Config for Runtime { @@ -377,9 +393,11 @@ impl did::Config for Runtime { #[cfg(feature = "runtime-benchmarks")] type EnsureOrigin = EnsureSigned; type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type MaxPublicKeysPerDid = MaxPublicKeysPerDid; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; - type MaxEndpointUrlsCount = MaxUrlsEndpointCounts; + type MaxEndpointUrlsCount = MaxEndpointUrlsCount; type WeightInfo = (); }