From 913d46b23d2c2600432e398ddd89944a63e26c0f Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 20 Jul 2021 17:30:23 +0200 Subject: [PATCH 01/37] wip: use bounded vec in staking --- pallets/parachain-staking/src/benchmarking.rs | 12 +- pallets/parachain-staking/src/lib.rs | 168 +++-- pallets/parachain-staking/src/migrations.rs | 18 +- pallets/parachain-staking/src/mock.rs | 4 + pallets/parachain-staking/src/set.rs | 281 ++++--- pallets/parachain-staking/src/tests.rs | 698 +++++++++++------- pallets/parachain-staking/src/types.rs | 42 +- runtimes/peregrine/src/lib.rs | 3 + runtimes/spiritnet/src/lib.rs | 3 + 9 files changed, 765 insertions(+), 464 deletions(-) diff --git a/pallets/parachain-staking/src/benchmarking.rs b/pallets/parachain-staking/src/benchmarking.rs index 1e4d46c7aa..eca73796e2 100644 --- a/pallets/parachain-staking/src/benchmarking.rs +++ b/pallets/parachain-staking/src/benchmarking.rs @@ -58,7 +58,7 @@ fn setup_collator_candidates( } CandidatePool::::get() - .into_vec() + .into_bounded_vec() .drain(..) .map(|c| c.owner) .collect() @@ -401,7 +401,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 +435,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 +471,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 +507,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 +605,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/lib.rs b/pallets/parachain-staking/src/lib.rs index d74739573a..447b136e3e 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -183,6 +183,7 @@ pub mod pallet { Currency, EstimateNextSessionRotation, Get, Imbalance, LockIdentifier, LockableCurrency, ReservableCurrency, WithdrawReasons, }, + BoundedVec, }; use frame_system::pallet_prelude::*; use kilt_primitives::constants::BLOCKS_PER_YEAR; @@ -202,6 +203,7 @@ pub mod pallet { StakeOf, TotalStake, }, }; + use sp_std::{convert::TryInto, fmt::Debug}; /// Kilt-specific lock for staking rewards. pub(crate) const STAKING_ID: LockIdentifier = *b"kiltpstk"; @@ -262,11 +264,11 @@ pub mod pallet { /// to be one. type MaxDelegationsPerRound: Get; /// Maximum number of delegators a single collator can have. - type MaxDelegatorsPerCollator: Get; + type MaxDelegatorsPerCollator: Get + Debug + PartialEq; /// Maximum number of collators a single delegator can delegate. - type MaxCollatorsPerDelegator: Get; + type MaxCollatorsPerDelegator: Get + Debug + PartialEq; /// Maximum size of the collator candidates set. - type MaxCollatorCandidates: Get; + type MaxCollatorCandidates: Get + Debug + PartialEq; /// Minimum stake required for any account to be elected as validator /// for a round. type MinCollatorStake: Get>; @@ -330,7 +332,7 @@ pub mod pallet { /// 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 @@ -554,21 +556,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 +592,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] @@ -1029,20 +1042,22 @@ 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 + let insert_candidate = candidates + .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); @@ -1225,14 +1240,17 @@ 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 + let insert_candidate = candidates + .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 +1313,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 +1375,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); @@ -1426,16 +1444,24 @@ 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 excess + let insert_delegator = state + .delegators + .insert(delegation.clone()) + .map_err(|_| Error::::TooManyDelegators)?; // should never fail but let's be safe - ensure!(state.delegators.insert(delegation.clone()), Error::::DelegatorExists); + ensure!(insert_delegator, Error::::DelegatorExists); // update state and potentially kick a delegator with less staked amount - state = if (state.delegators.len().saturated_into::()) > T::MaxDelegatorsPerCollator::get() { + state = if num_delegations_pre_insertion == T::MaxDelegatorsPerCollator::get() { let (new_state, replaced_delegation) = Self::do_update_delegator(delegation.clone(), state)?; Self::deposit_event(Event::DelegationReplaced( delegation.owner, @@ -1455,7 +1481,7 @@ 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 @@ -1541,23 +1567,34 @@ 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); + + // throws if delegation insertion exceeds bounded vec limit which we will handle + // below in Self::do_update_delegator 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.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() { + state = if num_delegations_pre_insertion == T::MaxDelegatorsPerCollator::get() { let (new_state, replaced_delegation) = Self::do_update_delegator(delegation.clone(), state)?; Self::deposit_event(Event::DelegationReplaced( delegation.owner, @@ -1577,7 +1614,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 +1782,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 +1860,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 +1949,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 + .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 +2036,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 +2140,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 +2164,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 @@ -2143,24 +2186,27 @@ pub mod pallet { /// # fn do_update_delegator( stake: Stake>, - mut state: Collator>, - ) -> Result<(CollatorOf, StakeOf), DispatchError> { + mut state: Collator, T::MaxDelegatorsPerCollator>, + ) -> Result<(CollatorOf, StakeOf), DispatchError> { // add stake & sort by amount - let mut delegators: Vec>> = state.delegators.into(); + let delegators: Vec>> = state.delegators.into_bounded_vec().into_inner(); // check whether stake is at last place - match delegators.pop() { + // FIXME: Combine storage clearing with check of insertion which already + // replaces the lowest staked delegator + match delegators.clone().last() { 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); + state.delegators = + OrderedSet::from_sorted_set(delegators.try_into().expect("Did not extend size of Delegators")); // update storage of kicked delegator Self::kick_delegator(&stake_to_remove, &state.id)?; - Ok((state, stake_to_remove)) + Ok((state, stake_to_remove.clone())) } _ => Err(Error::::TooManyDelegators.into()), } @@ -2300,7 +2346,7 @@ 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) { // iterate over delegators for stake in state.delegators.into_iter() { // prepare unstaking of delegator @@ -2480,8 +2526,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!() // } } @@ -2586,7 +2632,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..2e329146ab 100644 --- a/pallets/parachain-staking/src/migrations.rs +++ b/pallets/parachain-staking/src/migrations.rs @@ -116,18 +116,22 @@ pub mod v4 { let mut n = 1u64; // for each candidate: sort delegators from greatest to lowest - CollatorState::::translate_values(|mut state: CollatorOf| { + // FIXME: Revert back to old type and move type to deprecated + 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) - }); + DelegatorState::::translate_values( + // FIXME: Revert back to old type and move type to deprecated + |mut state: Delegator| { + state.delegations.sort_greatest_to_lowest(); + n = n.saturating_add(1u64); + Some(state) + }, + ); StorageVersion::::put(Releases::V4); log::info!("Completed staking migration to Releases::V4"); @@ -138,7 +142,7 @@ pub mod v4 { pub fn post_migrate() -> Result<(), &'static str> { let mut candidates = CandidatePool::::get(); candidates.sort_greatest_to_lowest(); - assert_eq!(CandidatePool::::get(), candidates); + // assert_eq!(CandidatePool::::get(), candidates); assert_eq!(StorageVersion::::get(), Releases::V4); Ok(()) } diff --git a/pallets/parachain-staking/src/mock.rs b/pallets/parachain-staking/src/mock.rs index 63a0f7506a..583d566275 100644 --- a/pallets/parachain-staking/src/mock.rs +++ b/pallets/parachain-staking/src/mock.rs @@ -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; diff --git a/pallets/parachain-staking/src/set.rs b/pallets/parachain-staking/src/set.rs index 7551ea5625..153982c57e 100644 --- a/pallets/parachain-staking/src/set.rs +++ b/pallets/parachain-staking/src/set.rs @@ -16,72 +16,77 @@ // 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(pub 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`. + /// Create 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. /// + /// 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 { + pub fn 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. /// + /// Throws if the maximum size of the bounded vec would be exceeded + /// upon insertion. + /// /// Returns the old value if existing. - pub fn upsert(&mut self, value: T) -> Option { + pub fn 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) } } } @@ -178,7 +183,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 +196,47 @@ 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 + /// Sort from greatest to lowest. + /// + /// 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. pub fn sort_greatest_to_lowest(&mut self) { - self.0.sort_by(|a, b| b.cmp(a)); + let mut sorted_v = self.0.clone().into_inner(); + sorted_v.sort_by(|a, b| b.cmp(a)); + self.0 = sorted_v.try_into().expect("Did not extend size of bounded vec"); } } -impl From> for OrderedSet { - fn from(v: Vec) -> Self { - Self::from(v) +// impl DerefMut for BoundedVec { +// fn deref_mut(&mut self) -> &mut Self::Target { +// &mut self.0 +// } +// } + +#[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 Index for OrderedSet { +impl> From> for OrderedSet { + fn from(bv: BoundedVec) -> Self { + Self::from(bv) + } +} + +impl> Index for OrderedSet { type Output = T; fn index(&self, index: usize) -> &Self::Output { @@ -216,7 +244,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 +252,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 +260,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 +275,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 +296,114 @@ 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)] + 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.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.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.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.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_eq!(set.contains(&5), false); - assert!(set.contains(&1)); + assert_eq!(set.contains(&1), true); - assert!(set.contains(&3)); + assert_eq!(set.contains(&3), true); } #[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 exceeding_max_size_should_fail() { + let mut set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4, 5].try_into().unwrap()); + let inserted = set.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 +416,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.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 }) + 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 }) + 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..bea0ad2d0e 100644 --- a/pallets/parachain-staking/src/tests.rs +++ b/pallets/parachain-staking/src/tests.rs @@ -18,9 +18,9 @@ //! Unit testing -use std::{collections::BTreeMap, iter}; +use std::{collections::BTreeMap, convert::TryInto, iter}; -use frame_support::{assert_noop, assert_ok, traits::EstimateNextSessionRotation}; +use frame_support::{assert_noop, assert_ok, 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 +100,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 +113,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 +136,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 +215,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 +345,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 +358,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 +411,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 +423,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 +434,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 +456,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 +494,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 +506,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 +514,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 +523,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 +614,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 +623,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 +636,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 +740,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 +753,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 +857,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 +912,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,7 +934,7 @@ 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, @@ -912,7 +989,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![ @@ -1124,7 +1201,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 +1213,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 +1820,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 +1836,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.insert(impossible_bond), Ok(true)); >::insert(&1u64, state); let authors: Vec> = vec![Some(1u64), Some(1u64), Some(1u64), Some(1u64)]; @@ -2444,9 +2521,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,13 +2534,13 @@ 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))); @@ -2598,14 +2678,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 +2706,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), @@ -2748,7 +2846,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 +2856,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 +2913,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 +3093,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 +3211,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..8c95f0655c 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,22 +206,27 @@ 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, - }]), + delegations: OrderedSet::from( + vec![Stake { + owner: collator, + amount, + }] + .try_into() + .expect("At least one collator per delegator should be enabled"), + ), total: amount, } } @@ -227,13 +235,13 @@ where /// /// 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.insert(stake)? { self.total = self.total.saturating_add(amt); - true + Ok(true) } else { - false + Ok(false) } } @@ -374,5 +382,5 @@ impl Default for Releases { 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 4673a03ee7..503a666964 100644 --- a/runtimes/peregrine/src/lib.rs +++ b/runtimes/peregrine/src/lib.rs @@ -741,14 +741,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/spiritnet/src/lib.rs b/runtimes/spiritnet/src/lib.rs index a36be7b449..5958b7feae 100644 --- a/runtimes/spiritnet/src/lib.rs +++ b/runtimes/spiritnet/src/lib.rs @@ -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; From 29f8e78768fa0cec2af92960bde03b96598ea525 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 28 Jul 2021 15:27:52 +0200 Subject: [PATCH 02/37] fix: add try_insert_replace --- pallets/parachain-staking/src/lib.rs | 50 +++++++++--------- pallets/parachain-staking/src/set.rs | 70 +++++++++++++++++++------- pallets/parachain-staking/src/tests.rs | 7 +-- 3 files changed, 82 insertions(+), 45 deletions(-) diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 447b136e3e..bdce229dc8 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -1452,11 +1452,12 @@ pub mod pallet { amount, }; - // attempt to insert delegator and check for excess + // attempt to insert delegator and check for uniqueness, excess is handled below let insert_delegator = state .delegators + // we handle TooManyDelegators below .insert(delegation.clone()) - .map_err(|_| Error::::TooManyDelegators)?; + .unwrap_or(true); // should never fail but let's be safe ensure!(insert_delegator, Error::::DelegatorExists); @@ -2188,28 +2189,29 @@ pub mod pallet { stake: Stake>, mut state: Collator, T::MaxDelegatorsPerCollator>, ) -> Result<(CollatorOf, StakeOf), DispatchError> { - // add stake & sort by amount - let delegators: Vec>> = state.delegators.into_bounded_vec().into_inner(); - - // check whether stake is at last place - // FIXME: Combine storage clearing with check of insertion which already - // replaces the lowest staked delegator - match delegators.clone().last() { - 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.try_into().expect("Did not extend size of Delegators")); - - // update storage of kicked delegator - Self::kick_delegator(&stake_to_remove, &state.id)?; - - Ok((state, stake_to_remove.clone())) - } - _ => Err(Error::::TooManyDelegators.into()), - } + // 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)?; + + Ok((state, stake_to_remove)) } /// Either set or increase the BalanceLock of target account to diff --git a/pallets/parachain-staking/src/set.rs b/pallets/parachain-staking/src/set.rs index 153982c57e..6192093f1c 100644 --- a/pallets/parachain-staking/src/set.rs +++ b/pallets/parachain-staking/src/set.rs @@ -36,7 +36,7 @@ impl> OrderedSet { Self(BoundedVec::default()) } - /// Create an ordered set from a `BoundedVec`. + /// Creates an ordered set from a `BoundedVec`. /// /// The vector will be sorted reversily (from greatest to lowest) and /// deduped first. @@ -55,11 +55,11 @@ impl> OrderedSet { 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. + /// Returns true if the item is unique in the set, otherwise returns false. pub fn insert(&mut self, value: T) -> Result { match self.linear_search(&value) { Ok(_) => Ok(false), @@ -70,12 +70,35 @@ impl> OrderedSet { } } - /// 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. + /// + /// 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. + /// Returns the old value if existing or None if the value did not exist + /// before. pub fn upsert(&mut self, value: T) -> Result, ()> { match self.linear_search(&value) { Ok(i) => { @@ -91,9 +114,9 @@ impl> OrderedSet { } } - /// 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)), @@ -101,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, @@ -132,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 @@ -201,7 +224,7 @@ impl> OrderedSet { self.0 } - /// Sort from greatest to lowest. + /// Sorts from greatest to lowest. /// /// NOTE: BoundedVec does not implement DerefMut because it would allow for /// unchecked extension of the inner vector. Thus, we have to work with a @@ -213,12 +236,6 @@ impl> OrderedSet { } } -// impl DerefMut for BoundedVec { -// fn deref_mut(&mut self) -> &mut Self::Target { -// &mut self.0 -// } -// } - #[cfg(feature = "std")] impl fmt::Debug for OrderedSet where @@ -304,7 +321,7 @@ mod tests { parameter_types! { #[derive(PartialEq, RuntimeDebug)] pub const Eight: u32 = 8; - #[derive(PartialEq, RuntimeDebug)] + #[derive(PartialEq, RuntimeDebug, Clone)] pub const Five: u32 = 5; } @@ -383,6 +400,23 @@ mod tests { 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.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.clone().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()); diff --git a/pallets/parachain-staking/src/tests.rs b/pallets/parachain-staking/src/tests.rs index bea0ad2d0e..c61381c461 100644 --- a/pallets/parachain-staking/src/tests.rs +++ b/pallets/parachain-staking/src/tests.rs @@ -1923,8 +1923,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 ); }); @@ -2508,8 +2509,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)), From ca92b10bf4524dd560003cffaadf5aaec4b77551 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 28 Jul 2021 15:34:40 +0200 Subject: [PATCH 03/37] fix: staking benchmarks --- pallets/parachain-staking/src/benchmarking.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/parachain-staking/src/benchmarking.rs b/pallets/parachain-staking/src/benchmarking.rs index eca73796e2..733dcc5272 100644 --- a/pallets/parachain-staking/src/benchmarking.rs +++ b/pallets/parachain-staking/src/benchmarking.rs @@ -59,6 +59,8 @@ fn setup_collator_candidates( CandidatePool::::get() .into_bounded_vec() + .into_inner() + .clone() .drain(..) .map(|c| c.owner) .collect() From 7882dc776927a2f1d29347036858b5d77b28b930 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 28 Jul 2021 17:22:45 +0200 Subject: [PATCH 04/37] fix: migrations by adding deprecated --- pallets/parachain-staking/src/deprecated.rs | 83 +++++++++++++++++++++ pallets/parachain-staking/src/lib.rs | 1 + pallets/parachain-staking/src/migrations.rs | 13 ++-- 3 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 pallets/parachain-staking/src/deprecated.rs diff --git a/pallets/parachain-staking/src/deprecated.rs b/pallets/parachain-staking/src/deprecated.rs new file mode 100644 index 0000000000..7a58e4d9de --- /dev/null +++ b/pallets/parachain-staking/src/deprecated.rs @@ -0,0 +1,83 @@ +// 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 + +/// Deprecated types used in versions 1 to 4 (Vec instead of BoundedVec). +use crate::Config; + +pub(crate) mod v1_v4 { + use crate::types::{AccountIdOf, BalanceOf, CollatorStatus, Stake}; + use frame_support::dispatch::fmt::Debug; + #[cfg(feature = "std")] + use serde::{Deserialize, Serialize}; + use sp_runtime::{ + codec::{Decode, Encode}, + RuntimeDebug, + }; + use sp_std::prelude::*; + + use super::*; + + #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] + #[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode, Default, Clone)] + pub struct OrderedSet(Vec); + impl OrderedSet { + pub(crate) fn sort_greatest_to_lowest(&mut self) { + self.0.sort_by(|a, b| b.cmp(a)); + } + } + + #[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)] + pub struct Collator + where + AccountId: Eq + Ord + Debug, + Balance: Eq + Ord + Debug, + { + pub(crate) id: AccountId, + pub(crate) stake: Balance, + pub(crate) delegators: OrderedSet>, + pub(crate) total: Balance, + pub(crate) state: CollatorStatus, + } + pub(crate) type CollatorOf = Collator, BalanceOf>; + + #[derive(Encode, Decode, RuntimeDebug, PartialEq)] + pub struct Delegator { + pub(crate) delegations: OrderedSet>, + pub(crate) total: Balance, + } + + pub(crate) mod storage { + use frame_support::{decl_module, decl_storage}; + use sp_std::prelude::*; + + use super::*; + + decl_module! { + pub struct OldPallet for enum Call where origin: T::Origin {} + } + + decl_storage! { + pub(crate) trait Store for OldPallet as ParachainStaking { + pub(crate) DelegatorState get(fn delegator_state): map hasher(twox_64_concat) T::AccountId => Option>>; + pub(crate) CollatorState get(fn collator_state): map hasher(twox_64_concat) T::AccountId => Option>>; + pub(crate) SelectedCandidates get(fn selected_candidates): Vec; + pub(crate) CandidatePool get(fn candidate_pool): OrderedSet>>; + } + } + } +} diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index bdce229dc8..228aa8735e 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -162,6 +162,7 @@ pub(crate) mod mock; #[cfg(test)] pub(crate) mod tests; +mod deprecated; mod inflation; pub mod migrations; mod set; diff --git a/pallets/parachain-staking/src/migrations.rs b/pallets/parachain-staking/src/migrations.rs index 2e329146ab..7103e13f37 100644 --- a/pallets/parachain-staking/src/migrations.rs +++ b/pallets/parachain-staking/src/migrations.rs @@ -101,7 +101,11 @@ pub mod v3 { pub mod v4 { use super::*; - use crate::types::{CollatorOf, Delegator}; + use crate::deprecated::v1_v4::{ + storage::{CandidatePool, CollatorState, DelegatorState}, + CollatorOf, Delegator, + }; + use frame_support::{StoragePrefixedMap, StorageValue}; pub fn pre_migrate() -> Result<(), &'static str> { assert_eq!(StorageVersion::::get(), Releases::V3_0_0); @@ -116,8 +120,7 @@ pub mod v4 { let mut n = 1u64; // for each candidate: sort delegators from greatest to lowest - // FIXME: Revert back to old type and move type to deprecated - CollatorState::::translate_values(|mut state: CollatorOf| { + CollatorState::::translate_values(|mut state: CollatorOf| { state.delegators.sort_greatest_to_lowest(); n = n.saturating_add(1u64); Some(state) @@ -126,7 +129,7 @@ pub mod v4 { // for each delegator: sort delegations from greatest to lowest DelegatorState::::translate_values( // FIXME: Revert back to old type and move type to deprecated - |mut state: Delegator| { + |mut state: Delegator| { state.delegations.sort_greatest_to_lowest(); n = n.saturating_add(1u64); Some(state) @@ -142,7 +145,7 @@ pub mod v4 { pub fn post_migrate() -> Result<(), &'static str> { let mut candidates = CandidatePool::::get(); candidates.sort_greatest_to_lowest(); - // assert_eq!(CandidatePool::::get(), candidates); + assert_eq!(CandidatePool::::get(), candidates); assert_eq!(StorageVersion::::get(), Releases::V4); Ok(()) } From 6ad596109e521c1f2b7a20c506a2353689ff6a68 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 28 Jul 2021 17:33:35 +0200 Subject: [PATCH 05/37] fix: clippy fix: clippy --- pallets/parachain-staking/src/benchmarking.rs | 1 - pallets/parachain-staking/src/lib.rs | 46 +++++++++---------- pallets/parachain-staking/src/set.rs | 11 ++--- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/pallets/parachain-staking/src/benchmarking.rs b/pallets/parachain-staking/src/benchmarking.rs index 733dcc5272..73d172b2f5 100644 --- a/pallets/parachain-staking/src/benchmarking.rs +++ b/pallets/parachain-staking/src/benchmarking.rs @@ -60,7 +60,6 @@ fn setup_collator_candidates( CandidatePool::::get() .into_bounded_vec() .into_inner() - .clone() .drain(..) .map(|c| c.owner) .collect() diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 228aa8735e..ff8b0fc4ab 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -1410,6 +1410,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 @@ -1456,7 +1459,7 @@ pub mod pallet { // attempt to insert delegator and check for uniqueness, excess is handled below let insert_delegator = state .delegators - // we handle TooManyDelegators below + // we handle TooManyDelegators error below in do_update_delegator .insert(delegation.clone()) .unwrap_or(true); // should never fail but let's be safe @@ -1464,16 +1467,7 @@ pub mod pallet { // update state and potentially kick a delegator with less staked amount state = if num_delegations_pre_insertion == 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 + Self::do_update_delegator(delegation, state)? } else { state.total = state.total.saturating_add(amount); state @@ -1529,6 +1523,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 @@ -1597,16 +1594,7 @@ pub mod pallet { // update state and potentially kick a delegator with less staked amount state = if num_delegations_pre_insertion == 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 + Self::do_update_delegator(delegation, state)? } else { state.total = state.total.saturating_add(amount); state @@ -2181,6 +2169,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`. @@ -2189,7 +2180,7 @@ pub mod pallet { fn do_update_delegator( stake: Stake>, mut state: Collator, T::MaxDelegatorsPerCollator>, - ) -> Result<(CollatorOf, StakeOf), DispatchError> { + ) -> Result, DispatchError> { // attempt to replace the last element of the set let stake_to_remove = state .delegators @@ -2212,7 +2203,16 @@ pub mod pallet { // update storage of kicked delegator Self::kick_delegator(&stake_to_remove, &state.id)?; - Ok((state, stake_to_remove)) + 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 diff --git a/pallets/parachain-staking/src/set.rs b/pallets/parachain-staking/src/set.rs index 6192093f1c..e9d4c62ad8 100644 --- a/pallets/parachain-staking/src/set.rs +++ b/pallets/parachain-staking/src/set.rs @@ -385,12 +385,9 @@ mod tests { #[test] fn contains() { let set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4].try_into().unwrap()); - - assert_eq!(set.contains(&5), false); - - assert_eq!(set.contains(&1), true); - - assert_eq!(set.contains(&3), true); + assert!(!set.contains(&5)); + assert!(set.contains(&1)); + assert!(set.contains(&3)); } #[test] @@ -414,7 +411,7 @@ mod tests { assert_eq!(set.try_insert_replace(10), Err(false)); assert_eq!(set.try_insert_replace(11), Ok(6)); - assert_eq!(set.clone().into_bounded_vec().into_inner(), vec![11, 10, 9, 8, 7]); + assert_eq!(set.into_bounded_vec().into_inner(), vec![11, 10, 9, 8, 7]); } #[test] From 8b1d5b5cd72ddcf983acacb6253352961b4a916e Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 29 Jul 2021 11:13:47 +0200 Subject: [PATCH 06/37] refactor: apply migration structure from #226 --- pallets/parachain-staking/src/lib.rs | 37 +-- pallets/parachain-staking/src/migrations.rs | 302 ++++++++++++------ .../parachain-staking/src/migrations/v2.rs | 59 ++++ .../parachain-staking/src/migrations/v3.rs | 46 +++ .../parachain-staking/src/migrations/v4.rs | 69 ++++ .../parachain-staking/src/migrations/v5.rs | 71 ++++ pallets/parachain-staking/src/mock.rs | 14 +- pallets/parachain-staking/src/types.rs | 18 -- 8 files changed, 466 insertions(+), 150 deletions(-) create mode 100644 pallets/parachain-staking/src/migrations/v2.rs create mode 100644 pallets/parachain-staking/src/migrations/v3.rs create mode 100644 pallets/parachain-staking/src/migrations/v4.rs create mode 100644 pallets/parachain-staking/src/migrations/v5.rs diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index ff8b0fc4ab..b4f83a59c1 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -198,10 +198,11 @@ pub mod pallet { use sp_std::{collections::btree_map::BTreeMap, 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}; @@ -488,40 +489,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() } } @@ -530,7 +507,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] diff --git a/pallets/parachain-staking/src/migrations.rs b/pallets/parachain-staking/src/migrations.rs index 7103e13f37..1ea62fb477 100644 --- a/pallets/parachain-staking/src/migrations.rs +++ b/pallets/parachain-staking/src/migrations.rs @@ -16,137 +16,237 @@ // 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}, +use frame_support::{dispatch::Weight, ensure, traits::Get}; +use sp_runtime::{ + codec::{Decode, Encode}, + traits::Zero, }; -use frame_support::{dispatch::Weight, traits::Get}; -use kilt_primitives::constants::MAX_COLLATOR_STAKE; -use sp_runtime::traits::Zero; - -pub mod v2 { +use sp_std::marker::PhantomData; + +use crate::*; + +mod v2; +mod v3; +mod v4; +mod v5; + +/// 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 + V5, // Vec -> BoundedVec, BTreeMap -> BoundedBTreeMap +} - 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::V5 } +} - 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 => v5::pre_migrate::(), + Self::V5 => Err("Already on latest version v5."), + } + } - 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 => v5::migrate::(), + Self::V5 => 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 => v5::post_migrate::(), + Self::V5 => Err("Migration from v5 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), + StakingStorageVersion::V3_0_0 => Some(StakingStorageVersion::V4), + // Migration happens naturally, no need to point to the latest version + StakingStorageVersion::V4 => None, + StakingStorageVersion::V5 => None, + } } - pub fn migrate() -> Weight { - log::info!("Migrating staking to Releases::V3_0_0"); + /// 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." + ); - // update rewards per block - InflationConfig::::mutate(|inflation| *inflation = InflationInfo::from(INFLATION_CONFIG)); + // 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. - StorageVersion::::put(Releases::V3_0_0); - log::info!("Completed staking migration to Releases::V3_0_0"); + Ok(()) + } - T::DbWeight::get().reads_writes(1, 2) + /// 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 fn post_migrate() -> Result<(), &'static str> { - assert_eq!(InflationConfig::::get(), InflationInfo::from(INFLATION_CONFIG)); - assert_eq!(StorageVersion::::get(), Releases::V3_0_0); + /// 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." + ); + Ok(()) } } -pub mod v4 { +// Tests for the entire storage migrator. +#[cfg(test)] +mod tests { use super::*; - use crate::deprecated::v1_v4::{ - storage::{CandidatePool, CollatorState, DelegatorState}, - CollatorOf, Delegator, - }; - use frame_support::{StoragePrefixedMap, StorageValue}; - - 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"); + 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." + ); - // sort candidates from greatest to lowest - CandidatePool::::mutate(|candidates| candidates.sort_greatest_to_lowest()); - let mut n = 1u64; + StakingStorageMigrator::::migrate(); - // 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) + #[cfg(feature = "try-runtime")] + assert!( + StakingStorageMigrator::::post_migrate().is_ok(), + "Storage post-migrate from v1 should not fail." + ); }); + } - // for each delegator: sort delegations from greatest to lowest - DelegatorState::::translate_values( - // FIXME: Revert back to old type and move type to deprecated - |mut state: Delegator| { - state.delegations.sort_greatest_to_lowest(); - n = n.saturating_add(1u64); - Some(state) - }, - ); + #[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")] + assert!( + StakingStorageMigrator::::pre_migrate().is_ok(), + "Storage pre-migrate from default version should not fail." + ); - StorageVersion::::put(Releases::V4); - log::info!("Completed staking migration to Releases::V4"); + StakingStorageMigrator::::migrate(); - 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(()) + #[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..aab4f55b0c --- /dev/null +++ b/pallets/parachain-staking/src/migrations/v4.rs @@ -0,0 +1,69 @@ +// 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::{ + deprecated::v1_v4::{ + storage::{CandidatePool, CollatorState, DelegatorState}, + CollatorOf, Delegator, + }, + migrations::StakingStorageVersion, + pallet::*, +}; +use frame_support::{dispatch::Weight, traits::Get, StoragePrefixedMap, StorageValue}; + +#[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(), candidates); + assert_eq!(StorageVersion::::get(), StakingStorageVersion::V4); + Ok(()) +} diff --git a/pallets/parachain-staking/src/migrations/v5.rs b/pallets/parachain-staking/src/migrations/v5.rs new file mode 100644 index 0000000000..0805bcc5ee --- /dev/null +++ b/pallets/parachain-staking/src/migrations/v5.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::{ + deprecated::v1_v4::{ + storage::{CandidatePool, CollatorState, DelegatorState}, + CollatorOf, Delegator, + }, + migrations::StakingStorageVersion, + pallet::*, +}; +use frame_support::{dispatch::Weight, traits::Get, StoragePrefixedMap, StorageValue}; + +// FIXME: Replace v4 migration with actual one + +#[cfg(feature = "try-runtime")] +pub(crate) fn pre_migrate() -> Result<(), &'static str> { + assert_eq!(StorageVersion::::get(), StakingStorageVersion::V4); + 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::V5); + log::info!("Completed staking migration to StakingStorageVersion::V5"); + + 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(), candidates); + assert_eq!(StorageVersion::::get(), StakingStorageVersion::V5); + Ok(()) +} diff --git a/pallets/parachain-staking/src/mock.rs b/pallets/parachain-staking/src/mock.rs index 583d566275..30d804aa53 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}, @@ -210,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 { @@ -225,6 +227,7 @@ impl Default for ExtBuilder { Perquintill::from_percent(40), Perquintill::from_percent(10), ), + storage_version: StakingStorageVersion::default(), } } } @@ -269,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::() @@ -325,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/types.rs b/pallets/parachain-staking/src/types.rs index 8c95f0655c..d9c72fffe3 100644 --- a/pallets/parachain-staking/src/types.rs +++ b/pallets/parachain-staking/src/types.rs @@ -362,24 +362,6 @@ 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, S>; From 1571513dd090d296e374899ce2db145cf6b4f6d9 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 29 Jul 2021 17:49:25 +0200 Subject: [PATCH 07/37] chore: add staking migration to v5 --- pallets/parachain-staking/src/deprecated.rs | 4 + .../parachain-staking/src/migrations/v5.rs | 213 ++++++++++++++++-- 2 files changed, 193 insertions(+), 24 deletions(-) diff --git a/pallets/parachain-staking/src/deprecated.rs b/pallets/parachain-staking/src/deprecated.rs index 7a58e4d9de..5abb2c29d4 100644 --- a/pallets/parachain-staking/src/deprecated.rs +++ b/pallets/parachain-staking/src/deprecated.rs @@ -36,6 +36,10 @@ pub(crate) mod v1_v4 { #[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode, Default, Clone)] pub struct OrderedSet(Vec); impl OrderedSet { + pub(crate) fn into_vec(self) -> Vec { + self.0 + } + pub(crate) fn sort_greatest_to_lowest(&mut self) { self.0.sort_by(|a, b| b.cmp(a)); } diff --git a/pallets/parachain-staking/src/migrations/v5.rs b/pallets/parachain-staking/src/migrations/v5.rs index 0805bcc5ee..9b755f6056 100644 --- a/pallets/parachain-staking/src/migrations/v5.rs +++ b/pallets/parachain-staking/src/migrations/v5.rs @@ -18,54 +18,219 @@ use crate::{ deprecated::v1_v4::{ - storage::{CandidatePool, CollatorState, DelegatorState}, - CollatorOf, Delegator, + storage::{ + CandidatePool as CandidatePoolV4, CollatorState as CollatorStateV4, DelegatorState as DelegatorStateV4, + SelectedCandidates as SelectedCandidatesV4, + }, + CollatorOf as CollatorOfV4, Delegator as DelegatorV4, OrderedSet as OrderedSetV4, }, migrations::StakingStorageVersion, pallet::*, + set::OrderedSet, + types::{BalanceOf, Collator, Delegator, StakeOf}, + CandidatePool, SelectedCandidates, }; -use frame_support::{dispatch::Weight, traits::Get, StoragePrefixedMap, StorageValue}; - -// FIXME: Replace v4 migration with actual one +use frame_support::{dispatch::Weight, traits::Get, BoundedVec, StoragePrefixedMap, StorageValue}; +use sp_runtime::{traits::Zero, SaturatedConversion}; +use sp_std::convert::TryFrom; #[cfg(feature = "try-runtime")] pub(crate) fn pre_migrate() -> Result<(), &'static str> { assert_eq!(StorageVersion::::get(), StakingStorageVersion::V4); + + // candidate pool + let candidates = check_migrate_candidate_pool::(); + assert!(candidates.is_ok()); + assert!(!candidates.unwrap().len().is_zero()); + + // selected candidates + let collators = check_migrate_selected_candidates::(); + assert!(collators.is_ok()); + assert!(!collators.unwrap().len().is_zero()); + + // collator state + assert!(CollatorStateV4::::iter_values().all(|old: CollatorOfV4| { + migrate_ordered_set::::MaxDelegatorsPerCollator>(old.delegators).is_ok() + })); + + // delegator state + assert!( + DelegatorStateV4::::iter_values().all(|old: DelegatorV4>| { + migrate_ordered_set::::MaxCollatorsPerDelegator>(old.delegations).is_ok() + }) + ); Ok(()) } -pub(crate) fn migrate() -> Weight { - log::info!("Migrating staking to StakingStorageVersion::V4"); +// TODO: Docs +pub(crate) fn migrate_ordered_set>( + old_set: OrderedSetV4>, +) -> Result, S>, ()> { + let bv = BoundedVec::, S>::try_from(old_set.into_vec())?; + Ok(OrderedSet::, S>::from(bv)) +} + +// TODO: Docs +fn check_migrate_candidate_pool() -> Result, ::MaxCollatorCandidates>, ()> +{ + // if runtime testing, check whether inner vector has been untouched + #[cfg(feature = "try-runtime")] + { + assert_eq!( + CandidatePoolV4::::get().into_vec(), + migrate_ordered_set::::MaxCollatorCandidates>(CandidatePoolV4::::get())? + .into_bounded_vec() + .into_inner() + ); + } + let candidates = migrate_ordered_set::::MaxCollatorCandidates>(CandidatePoolV4::::get())?; + Ok(candidates) +} - // sort candidates from greatest to lowest - CandidatePool::::mutate(|candidates| candidates.sort_greatest_to_lowest()); - let mut n = 1u64; +// TODO: Docs +fn check_migrate_selected_candidates( +) -> Result::MaxCollatorCandidates>, ()> { + let candidates = + BoundedVec::::MaxCollatorCandidates>::try_from(SelectedCandidatesV4::::get())?; + // if runtime testing, check whether inner vector has been untouched + #[cfg(feature = "try-runtime")] + { + assert_eq!(SelectedCandidatesV4::::get(), candidates.clone().into_inner()); + } + Ok(candidates) +} - // 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) +// TODO: Docs +fn migrate_collator_state() -> u64 { + CollatorState::::translate_values(|old: Option>| { + old.map( + |CollatorOfV4:: { + id, + stake, + total, + state, + delegators, + }| Collator::, ::MaxDelegatorsPerCollator> { + id, + stake, + total, + state, + delegators: migrate_ordered_set::::MaxDelegatorsPerCollator>(delegators) + .expect("Exceeding MaxDelegatorsPerCollator bound has been checked in V4 already!"), + }, + ) }); + CollatorState::::iter().count().saturated_into() +} - // 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) +// TODO: Docs +fn migrate_delegator_state() -> u64 { + DelegatorState::::translate_values(|old: Option>>| { + old.map( + |o| Delegator::, ::MaxCollatorsPerDelegator> { + total: o.total, + delegations: migrate_ordered_set::::MaxCollatorsPerDelegator>(o.delegations) + .expect("Exceeding MaxCollatorsPerDelegator bound has been checked in V4 already!"), + }, + ) }); + DelegatorState::::iter().count().saturated_into() +} + +pub(crate) fn migrate() -> Weight { + log::info!("Migrating staking to StakingStorageVersion::V5"); + + // migrate candidates + CandidatePool::::put(check_migrate_candidate_pool::().expect("Should have thrown in pre_migrate")); + SelectedCandidates::::put(check_migrate_selected_candidates::().expect("Should have thrown in pre_migrate")); + + // migrate collator state + let num_collator_states = migrate_collator_state::(); + + // migrate delegator state + let num_delegator_states = migrate_delegator_state::(); StorageVersion::::put(StakingStorageVersion::V5); log::info!("Completed staking migration to StakingStorageVersion::V5"); - T::DbWeight::get().reads_writes(n, n) + T::DbWeight::get().reads_writes( + 2u64.saturating_add(num_collator_states) + .saturating_add(num_delegator_states), + 3u64.saturating_add(num_collator_states) + .saturating_add(num_delegator_states), + ) } #[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(), candidates); + assert!(!CandidatePool::::get().len().is_zero()); + assert!(!SelectedCandidates::::get().len().is_zero()); assert_eq!(StorageVersion::::get(), StakingStorageVersion::V5); + log::info!("Staking storage version migrated from v4 to v5"); Ok(()) } + +// Tests for the v1 storage migrator. +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + mock::{ExtBuilder, Test}, + types::Stake, + }; + + #[test] + fn fail_version_higher() { + ExtBuilder::default() + .with_balances(vec![(1, 100)]) + .with_collators(vec![(1, 100)]) + .with_storage_version(StakingStorageVersion::V5) + .build() + .execute_with(|| { + #[cfg(feature = "try-runtime")] + assert!(pre_migrate::().is_err(), "Pre-migration for v5 should fail."); + }); + } + + #[test] + fn v5_migration_works() { + ExtBuilder::default() + .with_balances(vec![ + (1, 100), + (2, 100), + (3, 100), + (4, 100), + (5, 100), + (6, 100), + (7, 100), + ]) + .with_collators(vec![(1, 100), (2, 100), (3, 100)]) + .with_delegators(vec![(4, 1, 100), (5, 1, 100), (6, 1, 100), (7, 2, 100)]) + .with_storage_version(StakingStorageVersion::V4) + .build() + .execute_with(|| { + assert!(!CandidatePool::::get().is_empty()); + #[cfg(feature = "try-runtime")] + assert!(pre_migrate::().is_ok(), "Pre-migration for v5 should not fail."); + + migrate::(); + + #[cfg(feature = "try-runtime")] + assert!(post_migrate::().is_ok(), "Post-migration for v5 should not fail."); + + // FIXME: Fails because the mock already sets up with the new + // types. Would need to add a mock just for this migration. + // Seems overkill. assert_eq!( + // CandidatePool::::get(), + // OrderedSet::, ::MaxCollatorCandidates>::from_sorted_set( BoundedVec: + // :try_from(vec![ Stake { owner: 1, amount: 400 }, + // Stake { owner: 2, amount: 200 }, + // Stake { owner: 3, amount: 100 }, + // ]) + // .unwrap() + // ) + // ); + }); + } +} From e720d19ca4cc3896c9c6553d453cfafc0aa136b0 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 30 Jul 2021 10:32:48 +0200 Subject: [PATCH 08/37] chore: migrate to BoundedBTreeMap in staking --- pallets/parachain-staking/src/lib.rs | 70 ++++++++++++------------ pallets/parachain-staking/src/tests.rs | 75 +++++++++++++------------- 2 files changed, 73 insertions(+), 72 deletions(-) diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index b4f83a59c1..76a2d2004a 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -180,6 +180,7 @@ pub mod pallet { use frame_support::{ assert_ok, pallet_prelude::*, + storage::bounded_btree_map::BoundedBTreeMap, traits::{ Currency, EstimateNextSessionRotation, Get, Imbalance, LockIdentifier, LockableCurrency, ReservableCurrency, WithdrawReasons, @@ -195,7 +196,7 @@ 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, @@ -583,8 +584,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] @@ -956,7 +962,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(); @@ -1168,7 +1174,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)); @@ -2214,7 +2220,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 @@ -2228,7 +2235,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 { @@ -2238,7 +2247,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 @@ -2275,7 +2285,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); @@ -2291,29 +2301,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. @@ -2326,11 +2320,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) { @@ -2343,7 +2340,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() @@ -2360,6 +2357,7 @@ pub mod pallet { .map(pallet_session::Pallet::::disable_index); >::remove(&collator); + Ok(()) } /// Withdraw all staked currency which was unstaked at least @@ -2383,12 +2381,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 { diff --git a/pallets/parachain-staking/src/tests.rs b/pallets/parachain-staking/src/tests.rs index c61381c461..86ca3c068b 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, convert::TryInto, iter}; +use std::{convert::TryInto, iter}; -use frame_support::{assert_noop, assert_ok, traits::EstimateNextSessionRotation, BoundedVec}; +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}; @@ -1061,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![]); @@ -2147,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)]) @@ -2156,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, @@ -2175,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 @@ -2204,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)]) @@ -2213,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, @@ -2232,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()]); @@ -2261,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() @@ -2272,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, @@ -2290,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 @@ -2322,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() @@ -2347,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, @@ -2369,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); @@ -2385,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); @@ -2411,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()]); @@ -2441,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()]); @@ -2547,8 +2550,8 @@ fn candidate_leaves() { 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); From b8b7f944867c7d1ae2f9c7c5b6cc9775347f3286 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 2 Aug 2021 15:12:28 +0200 Subject: [PATCH 09/37] fix: remove v5 migration --- pallets/parachain-staking/src/deprecated.rs | 4 - pallets/parachain-staking/src/migrations.rs | 44 ++-- .../parachain-staking/src/migrations/v5.rs | 236 ------------------ 3 files changed, 20 insertions(+), 264 deletions(-) delete mode 100644 pallets/parachain-staking/src/migrations/v5.rs diff --git a/pallets/parachain-staking/src/deprecated.rs b/pallets/parachain-staking/src/deprecated.rs index 5abb2c29d4..7a58e4d9de 100644 --- a/pallets/parachain-staking/src/deprecated.rs +++ b/pallets/parachain-staking/src/deprecated.rs @@ -36,10 +36,6 @@ pub(crate) mod v1_v4 { #[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode, Default, Clone)] pub struct OrderedSet(Vec); impl OrderedSet { - pub(crate) fn into_vec(self) -> Vec { - self.0 - } - pub(crate) fn sort_greatest_to_lowest(&mut self) { self.0.sort_by(|a, b| b.cmp(a)); } diff --git a/pallets/parachain-staking/src/migrations.rs b/pallets/parachain-staking/src/migrations.rs index 1ea62fb477..cac7816f1f 100644 --- a/pallets/parachain-staking/src/migrations.rs +++ b/pallets/parachain-staking/src/migrations.rs @@ -28,7 +28,6 @@ use crate::*; mod v2; mod v3; mod v4; -mod v5; /// A trait that allows version migrators to access the underlying pallet's /// context, e.g., its Config trait. @@ -53,14 +52,13 @@ pub enum StakingStorageVersion { V2_0_0, // New Reward calculation, MaxCollatorCandidateStake V3_0_0, // Update InflationConfig V4, // Sort CandidatePool and parachain-stakings by amount - V5, // Vec -> BoundedVec, BTreeMap -> BoundedBTreeMap } #[cfg(feature = "try-runtime")] impl StakingStorageVersion { /// The latest storage version. fn latest() -> Self { - Self::V5 + Self::V4 } } @@ -85,8 +83,7 @@ impl VersionMigratorTrait for StakingStorageVersion { Self::V1_0_0 => v2::pre_migrate::(), Self::V2_0_0 => v3::pre_migrate::(), Self::V3_0_0 => v4::pre_migrate::(), - Self::V4 => v5::pre_migrate::(), - Self::V5 => Err("Already on latest version v5."), + Self::V4 => Err("Already on latest version v4."), } } @@ -96,8 +93,7 @@ impl VersionMigratorTrait for StakingStorageVersion { Self::V1_0_0 => v2::migrate::(), Self::V2_0_0 => v3::migrate::(), Self::V3_0_0 => v4::migrate::(), - Self::V4 => v5::migrate::(), - Self::V5 => Weight::zero(), + Self::V4 => Weight::zero(), } } @@ -109,8 +105,7 @@ impl VersionMigratorTrait for StakingStorageVersion { Self::V1_0_0 => v2::post_migrate::(), Self::V2_0_0 => v3::post_migrate::(), Self::V3_0_0 => v4::post_migrate::(), - Self::V4 => v5::post_migrate::(), - Self::V5 => Err("Migration from v5 should have never happened in the first place."), + Self::V4 => Err("Migration from v4 should have never happened in the first place."), } } } @@ -129,10 +124,9 @@ impl StakingStorageMigrator { match current { StakingStorageVersion::V1_0_0 => Some(StakingStorageVersion::V2_0_0), StakingStorageVersion::V2_0_0 => Some(StakingStorageVersion::V3_0_0), - StakingStorageVersion::V3_0_0 => Some(StakingStorageVersion::V4), // Migration happens naturally, no need to point to the latest version + StakingStorageVersion::V3_0_0 => None, StakingStorageVersion::V4 => None, - StakingStorageVersion::V5 => None, } } @@ -234,19 +228,21 @@ mod tests { .with_collators(vec![(1, 100), (2, 100)]) .build(); ext.execute_with(|| { - #[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." - ); + 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/v5.rs b/pallets/parachain-staking/src/migrations/v5.rs deleted file mode 100644 index 9b755f6056..0000000000 --- a/pallets/parachain-staking/src/migrations/v5.rs +++ /dev/null @@ -1,236 +0,0 @@ -// 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::{ - deprecated::v1_v4::{ - storage::{ - CandidatePool as CandidatePoolV4, CollatorState as CollatorStateV4, DelegatorState as DelegatorStateV4, - SelectedCandidates as SelectedCandidatesV4, - }, - CollatorOf as CollatorOfV4, Delegator as DelegatorV4, OrderedSet as OrderedSetV4, - }, - migrations::StakingStorageVersion, - pallet::*, - set::OrderedSet, - types::{BalanceOf, Collator, Delegator, StakeOf}, - CandidatePool, SelectedCandidates, -}; -use frame_support::{dispatch::Weight, traits::Get, BoundedVec, StoragePrefixedMap, StorageValue}; -use sp_runtime::{traits::Zero, SaturatedConversion}; -use sp_std::convert::TryFrom; - -#[cfg(feature = "try-runtime")] -pub(crate) fn pre_migrate() -> Result<(), &'static str> { - assert_eq!(StorageVersion::::get(), StakingStorageVersion::V4); - - // candidate pool - let candidates = check_migrate_candidate_pool::(); - assert!(candidates.is_ok()); - assert!(!candidates.unwrap().len().is_zero()); - - // selected candidates - let collators = check_migrate_selected_candidates::(); - assert!(collators.is_ok()); - assert!(!collators.unwrap().len().is_zero()); - - // collator state - assert!(CollatorStateV4::::iter_values().all(|old: CollatorOfV4| { - migrate_ordered_set::::MaxDelegatorsPerCollator>(old.delegators).is_ok() - })); - - // delegator state - assert!( - DelegatorStateV4::::iter_values().all(|old: DelegatorV4>| { - migrate_ordered_set::::MaxCollatorsPerDelegator>(old.delegations).is_ok() - }) - ); - Ok(()) -} - -// TODO: Docs -pub(crate) fn migrate_ordered_set>( - old_set: OrderedSetV4>, -) -> Result, S>, ()> { - let bv = BoundedVec::, S>::try_from(old_set.into_vec())?; - Ok(OrderedSet::, S>::from(bv)) -} - -// TODO: Docs -fn check_migrate_candidate_pool() -> Result, ::MaxCollatorCandidates>, ()> -{ - // if runtime testing, check whether inner vector has been untouched - #[cfg(feature = "try-runtime")] - { - assert_eq!( - CandidatePoolV4::::get().into_vec(), - migrate_ordered_set::::MaxCollatorCandidates>(CandidatePoolV4::::get())? - .into_bounded_vec() - .into_inner() - ); - } - let candidates = migrate_ordered_set::::MaxCollatorCandidates>(CandidatePoolV4::::get())?; - Ok(candidates) -} - -// TODO: Docs -fn check_migrate_selected_candidates( -) -> Result::MaxCollatorCandidates>, ()> { - let candidates = - BoundedVec::::MaxCollatorCandidates>::try_from(SelectedCandidatesV4::::get())?; - // if runtime testing, check whether inner vector has been untouched - #[cfg(feature = "try-runtime")] - { - assert_eq!(SelectedCandidatesV4::::get(), candidates.clone().into_inner()); - } - Ok(candidates) -} - -// TODO: Docs -fn migrate_collator_state() -> u64 { - CollatorState::::translate_values(|old: Option>| { - old.map( - |CollatorOfV4:: { - id, - stake, - total, - state, - delegators, - }| Collator::, ::MaxDelegatorsPerCollator> { - id, - stake, - total, - state, - delegators: migrate_ordered_set::::MaxDelegatorsPerCollator>(delegators) - .expect("Exceeding MaxDelegatorsPerCollator bound has been checked in V4 already!"), - }, - ) - }); - CollatorState::::iter().count().saturated_into() -} - -// TODO: Docs -fn migrate_delegator_state() -> u64 { - DelegatorState::::translate_values(|old: Option>>| { - old.map( - |o| Delegator::, ::MaxCollatorsPerDelegator> { - total: o.total, - delegations: migrate_ordered_set::::MaxCollatorsPerDelegator>(o.delegations) - .expect("Exceeding MaxCollatorsPerDelegator bound has been checked in V4 already!"), - }, - ) - }); - DelegatorState::::iter().count().saturated_into() -} - -pub(crate) fn migrate() -> Weight { - log::info!("Migrating staking to StakingStorageVersion::V5"); - - // migrate candidates - CandidatePool::::put(check_migrate_candidate_pool::().expect("Should have thrown in pre_migrate")); - SelectedCandidates::::put(check_migrate_selected_candidates::().expect("Should have thrown in pre_migrate")); - - // migrate collator state - let num_collator_states = migrate_collator_state::(); - - // migrate delegator state - let num_delegator_states = migrate_delegator_state::(); - - StorageVersion::::put(StakingStorageVersion::V5); - log::info!("Completed staking migration to StakingStorageVersion::V5"); - - T::DbWeight::get().reads_writes( - 2u64.saturating_add(num_collator_states) - .saturating_add(num_delegator_states), - 3u64.saturating_add(num_collator_states) - .saturating_add(num_delegator_states), - ) -} - -#[cfg(feature = "try-runtime")] -pub(crate) fn post_migrate() -> Result<(), &'static str> { - assert!(!CandidatePool::::get().len().is_zero()); - assert!(!SelectedCandidates::::get().len().is_zero()); - assert_eq!(StorageVersion::::get(), StakingStorageVersion::V5); - log::info!("Staking storage version migrated from v4 to v5"); - Ok(()) -} - -// Tests for the v1 storage migrator. -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - mock::{ExtBuilder, Test}, - types::Stake, - }; - - #[test] - fn fail_version_higher() { - ExtBuilder::default() - .with_balances(vec![(1, 100)]) - .with_collators(vec![(1, 100)]) - .with_storage_version(StakingStorageVersion::V5) - .build() - .execute_with(|| { - #[cfg(feature = "try-runtime")] - assert!(pre_migrate::().is_err(), "Pre-migration for v5 should fail."); - }); - } - - #[test] - fn v5_migration_works() { - ExtBuilder::default() - .with_balances(vec![ - (1, 100), - (2, 100), - (3, 100), - (4, 100), - (5, 100), - (6, 100), - (7, 100), - ]) - .with_collators(vec![(1, 100), (2, 100), (3, 100)]) - .with_delegators(vec![(4, 1, 100), (5, 1, 100), (6, 1, 100), (7, 2, 100)]) - .with_storage_version(StakingStorageVersion::V4) - .build() - .execute_with(|| { - assert!(!CandidatePool::::get().is_empty()); - #[cfg(feature = "try-runtime")] - assert!(pre_migrate::().is_ok(), "Pre-migration for v5 should not fail."); - - migrate::(); - - #[cfg(feature = "try-runtime")] - assert!(post_migrate::().is_ok(), "Post-migration for v5 should not fail."); - - // FIXME: Fails because the mock already sets up with the new - // types. Would need to add a mock just for this migration. - // Seems overkill. assert_eq!( - // CandidatePool::::get(), - // OrderedSet::, ::MaxCollatorCandidates>::from_sorted_set( BoundedVec: - // :try_from(vec![ Stake { owner: 1, amount: 400 }, - // Stake { owner: 2, amount: 200 }, - // Stake { owner: 3, amount: 100 }, - // ]) - // .unwrap() - // ) - // ); - }); - } -} From f3f859d55ebef5aadadd04809b50a3d64a1d8cb9 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 3 Aug 2021 10:23:51 +0200 Subject: [PATCH 10/37] chore: migrate UnlockingAt to BoundedVec --- pallets/kilt-launch/src/benchmarking.rs | 6 ++--- pallets/kilt-launch/src/lib.rs | 26 ++++++++++++++------- pallets/kilt-launch/src/mock.rs | 6 +++-- pallets/kilt-launch/src/tests.rs | 9 ++++--- pallets/parachain-staking/src/migrations.rs | 1 + 5 files changed, 32 insertions(+), 16 deletions(-) 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/lib.rs b/pallets/kilt-launch/src/lib.rs index 5c626df6fa..791a151eba 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::TryFrom; 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 @@ -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::::ExceedsMaxClaims)?; max_add_amount }; @@ -810,12 +811,21 @@ 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.as_ref() { + let filtered: Vec = bv + .clone() + .into_inner() + .into_iter() + .filter(|acc_id| acc_id != source) + .collect(); + *maybe_bv = Some( + BoundedVec::::try_from(filtered) + .map_err(|_| Error::::ExceedsMaxClaims)?, + ); + } + 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..39d178e3a0 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 diff --git a/pallets/parachain-staking/src/migrations.rs b/pallets/parachain-staking/src/migrations.rs index cac7816f1f..e94f0245ba 100644 --- a/pallets/parachain-staking/src/migrations.rs +++ b/pallets/parachain-staking/src/migrations.rs @@ -228,6 +228,7 @@ mod tests { .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!( From e4b85f5dec03cc42201eb38a81149ca8a2865b7c Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 3 Aug 2021 12:11:41 +0200 Subject: [PATCH 11/37] chore: use BoundedVec in DelegatedAttestations --- pallets/attestation/src/lib.rs | 20 +++++++++++++++++--- pallets/attestation/src/mock.rs | 18 +++++++++++++++--- runtimes/peregrine/src/lib.rs | 6 ++++++ runtimes/standalone/src/lib.rs | 6 ++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/pallets/attestation/src/lib.rs b/pallets/attestation/src/lib.rs index 78ca160f63..0fc83b9f6e 100644 --- a/pallets/attestation/src/lib.rs +++ b/pallets/attestation/src/lib.rs @@ -94,7 +94,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 +114,9 @@ pub mod pallet { type EnsureOrigin: EnsureOrigin, ::Origin>; type Event: From> + IsType<::Event>; type WeightInfo: WeightInfo; + /// Maximum number for delegated attestations required for bounded vec. + #[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] @@ -243,7 +255,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..59c9145d02 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}; @@ -114,10 +114,16 @@ impl delegation::Config for Test { 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 +233,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 +256,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/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index 503a666964..0e91450cb8 100644 --- a/runtimes/peregrine/src/lib.rs +++ b/runtimes/peregrine/src/lib.rs @@ -651,10 +651,16 @@ 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! { diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index ff16c6bd31..fd3ae9aa06 100644 --- a/runtimes/standalone/src/lib.rs +++ b/runtimes/standalone/src/lib.rs @@ -329,10 +329,16 @@ 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! { From 1c350d525ecd71553b12d16982b778cc57939d9e Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 3 Aug 2021 12:27:23 +0200 Subject: [PATCH 12/37] refactor: align exceeded errors --- pallets/kilt-launch/src/lib.rs | 8 ++++---- pallets/kilt-launch/src/tests.rs | 2 +- pallets/parachain-staking/src/lib.rs | 8 ++++---- pallets/parachain-staking/src/tests.rs | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pallets/kilt-launch/src/lib.rs b/pallets/kilt-launch/src/lib.rs index 791a151eba..8315458c37 100644 --- a/pallets/kilt-launch/src/lib.rs +++ b/pallets/kilt-launch/src/lib.rs @@ -342,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, @@ -521,7 +521,7 @@ pub mod pallet { ensure!( sources.len() < T::MaxClaims::get().saturated_into::(), - Error::::ExceedsMaxClaims + Error::::MaxClaimsExceeded ); let mut post_weight: Weight = 0; @@ -787,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` - >::try_append(unlock_block, &target).map_err(|_| Error::::ExceedsMaxClaims)?; + >::try_append(unlock_block, &target).map_err(|_| Error::::MaxClaimsExceeded)?; max_add_amount }; @@ -821,7 +821,7 @@ pub mod pallet { .collect(); *maybe_bv = Some( BoundedVec::::try_from(filtered) - .map_err(|_| Error::::ExceedsMaxClaims)?, + .map_err(|_| Error::::MaxClaimsExceeded)?, ); } Ok(()) diff --git a/pallets/kilt-launch/src/tests.rs b/pallets/kilt-launch/src/tests.rs index 39d178e3a0..f4ea3b4f22 100644 --- a/pallets/kilt-launch/src/tests.rs +++ b/pallets/kilt-launch/src/tests.rs @@ -573,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/lib.rs b/pallets/parachain-staking/src/lib.rs index 76a2d2004a..415ebbda49 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -331,7 +331,7 @@ 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. /// @@ -354,7 +354,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, @@ -1541,7 +1541,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 @@ -2488,7 +2488,7 @@ pub mod pallet { ensure!( T::MaxDelegationsPerRound::get() > counter, - Error::::ExceededDelegationsPerRound + Error::::DelegationsPerRoundExceeded ); Ok(DelegationCounter { diff --git a/pallets/parachain-staking/src/tests.rs b/pallets/parachain-staking/src/tests.rs index 86ca3c068b..465b113427 100644 --- a/pallets/parachain-staking/src/tests.rs +++ b/pallets/parachain-staking/src/tests.rs @@ -940,7 +940,7 @@ fn multiple_delegations() { 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![]); @@ -2794,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 @@ -2802,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 @@ -2836,7 +2836,7 @@ fn exceed_delegations_per_round() { ); assert_noop!( StakePallet::join_delegators(Origin::signed(6), 1, 10), - Error::::ExceededDelegationsPerRound + Error::::DelegationsPerRoundExceeded ); }); } From a555fa8455f4aab38f848b4abf18deeb2c23d48d Mon Sep 17 00:00:00 2001 From: Antonio Date: Tue, 3 Aug 2021 16:37:56 +0200 Subject: [PATCH 13/37] feat: delegation pallet storage refactor (#226) * feat: initial commit * feat: pallet compiling * wip: fixing test cases * wip: refactoring test cases * test: unit tests passing again * benchmark tests passing * test: attestation unit tests passing * chore: clippy fixes * chore: fmt fixes * bench: re-execute benchmarks for delegation and attestation + temporarily remove benchmarks from peregrine runtime * fix: adjust pre-condition for an attestation unit test * wip: add initial support for delegation storage migrations * delegation storage migrator compiling * wip: storage migrator working, now writing unit tests for it * test: unit tests passing * chore: clippy hints * chore: further clippy fixes * chore: fmt * wip: adjusting last things before possible to review * chore: clippy + fmt * fix: address part of PR review comments * fix: more comments from PR review * wip: change vector of versions to enum * test: unit tests refactor for the new storage migrator version * chore: refactor * test: unit tests passing again * chore: move deprecated type to deprecated.rs * chore: refactor import/export * doc: refine documentation * chore: fmt + clippy * test: add TODO to improve post_migration tests * feat: remove test feature from traits * test: add checks during migration in try-runtime * bench: add spiritnet benchmarks for delegation and attestation * feat: additional logs for count of migrated nodes * chore: fmt * chore: removed useless file * chore: bump runtime version * fix: PR comments * fix: re-introduce root_id in delegation creation hash * chore: capitalize storage version enum * chore: move migrations in their own module * chore: move migrations.rs out of the migrations folder * fix: add check for parent revocation status when creating a delegation * chore: fmt * feat: remove revoke_hierarchy extrinsic * bench: add peregrine benchmarks * bench: re-run delegation and attestation default benchmarks * chore: fmt --- Cargo.lock | 1 + pallets/attestation/src/default_weights.rs | 47 +- pallets/attestation/src/lib.rs | 13 +- pallets/attestation/src/tests.rs | 197 ++- pallets/ctype/src/lib.rs | 4 +- pallets/delegation/Cargo.toml | 1 + pallets/delegation/src/benchmarking.rs | 115 +- pallets/delegation/src/default_weights.rs | 110 +- .../delegation/src/delegation_hierarchy.rs | 129 +- pallets/delegation/src/deprecated.rs | 103 ++ pallets/delegation/src/lib.rs | 416 +++--- pallets/delegation/src/migrations.rs | 223 +++ pallets/delegation/src/migrations/v1.rs | 522 +++++++ pallets/delegation/src/mock.rs | 193 +-- pallets/delegation/src/tests.rs | 1284 ++++++++--------- runtimes/peregrine/src/lib.rs | 2 +- runtimes/peregrine/src/weights/attestation.rs | 40 +- runtimes/peregrine/src/weights/delegation.rs | 76 +- runtimes/spiritnet/src/lib.rs | 2 +- runtimes/standalone/src/lib.rs | 2 +- 20 files changed, 2108 insertions(+), 1372 deletions(-) create mode 100644 pallets/delegation/src/deprecated.rs create mode 100644 pallets/delegation/src/migrations.rs create mode 100644 pallets/delegation/src/migrations/v1.rs diff --git a/Cargo.lock b/Cargo.lock index 131445d772..03b943864a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1809,6 +1809,7 @@ version = "0.24.0" dependencies = [ "bitflags", "ctype", + "env_logger 0.8.4", "frame-benchmarking", "frame-support", "frame-system", diff --git a/pallets/attestation/src/default_weights.rs b/pallets/attestation/src/default_weights.rs index a8fd991570..271f0e2371 100644 --- a/pallets/attestation/src/default_weights.rs +++ b/pallets/attestation/src/default_weights.rs @@ -19,29 +19,24 @@ //! Autogenerated weights for attestation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! DATE: 2021-07-21, 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: -// ./kilt-parachain +// target/release/kilt-parachain // benchmark -// --chain -// dev -// --execution -// wasm -// --wasm-execution -// compiled -// --pallet -// attestation -// --extrinsic -// * -// --steps -// 1 -// --repeat -// 10 +// --chain=dev +// --execution=wasm +// --wasm-execution=Compiled // --heap-pages=4096 -// --output=../../pallets/attestation/src/default_weights.rs -// --template=../../.maintain/weight-template.hbs +// --extrinsic=* +// --pallet=attestation +// --steps=1 +// --repeat=20 +// --template +// .maintain/weight-template.hbs +// --output +// pallets/attestation/src/default_weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -61,14 +56,14 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn add() -> Weight { - (37_981_000_u64) + (38_091_000_u64) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn revoke(d: u32, ) -> Weight { - (23_806_000_u64) - // Standard Error: 20_000 - .saturating_add((4_670_000_u64).saturating_mul(d as Weight)) + (25_042_000_u64) + // Standard Error: 28_000 + .saturating_add((4_866_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)) @@ -78,14 +73,14 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { fn add() -> Weight { - (37_981_000_u64) + (38_091_000_u64) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } fn revoke(d: u32, ) -> Weight { - (23_806_000_u64) - // Standard Error: 20_000 - .saturating_add((4_670_000_u64).saturating_mul(d as Weight)) + (25_042_000_u64) + // Standard Error: 28_000 + .saturating_add((4_866_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 0fc83b9f6e..087d05cf01 100644 --- a/pallets/attestation/src/lib.rs +++ b/pallets/attestation/src/lib.rs @@ -236,21 +236,22 @@ pub mod pallet { // Check for validity of the delegation node if specified. if let Some(delegation_id) = delegation_id { - let delegation = >::get(delegation_id) + let delegation = >::get(delegation_id) .ok_or(delegation::Error::::DelegationNotFound)?; - ensure!(!delegation.revoked, Error::::DelegationRevoked); + ensure!(!delegation.details.revoked, Error::::DelegationRevoked); - ensure!(delegation.owner == attester, Error::::NotDelegatedToAttester); + ensure!(delegation.details.owner == attester, Error::::NotDelegatedToAttester); ensure!( - (delegation.permissions & delegation::Permissions::ATTEST) == delegation::Permissions::ATTEST, + (delegation.details.permissions & delegation::Permissions::ATTEST) + == delegation::Permissions::ATTEST, Error::::DelegationUnauthorizedToAttest ); // Check if the CType of the delegation is matching the CType of the attestation - let root = - >::get(delegation.root_id).ok_or(delegation::Error::::RootNotFound)?; + let root = >::get(delegation.hierarchy_root_id) + .ok_or(delegation::Error::::HierarchyNotFound)?; ensure!(root.ctype_hash == ctype_hash, Error::::CTypeMismatch); // If the attestation is based on a delegation, store separately diff --git a/pallets/attestation/src/tests.rs b/pallets/attestation/src/tests.rs index 4afe8ef452..c333f203ed 100644 --- a/pallets/attestation/src/tests.rs +++ b/pallets/attestation/src/tests.rs @@ -61,15 +61,16 @@ fn attest_with_delegation_successful() { let attester_keypair = get_alice_ed25519(); let attester = get_ed25519_account(attester_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(attester.clone()), + + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attester.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attester.clone(), Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; + delegation_node.details.permissions = delegation::Permissions::ATTEST; let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -79,9 +80,8 @@ fn attest_with_delegation_successful() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, attester.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -196,16 +196,16 @@ fn delegation_revoked_attest_error() { let attester_keypair = get_alice_ed25519(); let attester = get_ed25519_account(attester_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(attester.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attester.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attester.clone(), Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; - delegation_node.revoked = true; + delegation_node.details.permissions = delegation::Permissions::ATTEST; + delegation_node.details.revoked = true; let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -215,9 +215,8 @@ fn delegation_revoked_attest_error() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, attester.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -240,15 +239,15 @@ fn not_delegation_owner_attest_error() { let alternative_owner_keypair = get_bob_ed25519(); let alternative_owner = get_ed25519_account(alternative_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(alternative_owner.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, alternative_owner), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, alternative_owner, Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; + delegation_node.details.permissions = delegation::Permissions::ATTEST; let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -258,9 +257,8 @@ fn not_delegation_owner_attest_error() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, attester.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -281,13 +279,14 @@ fn unauthorised_permissions_attest_error() { let attester_keypair = get_alice_ed25519(); let attester = get_ed25519_account(attester_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(attester.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); + // Delegation node does not have permissions to attest. let (delegation_id, delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attester.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attester.clone(), Some(hierarchy_root_id)), ); let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -298,9 +297,8 @@ fn unauthorised_permissions_attest_error() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, attester.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -321,16 +319,20 @@ fn root_not_present_attest_error() { let attester_keypair = get_alice_ed25519(); let attester = get_ed25519_account(attester_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(attester.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); - let alternative_root_id = delegation_mock::get_delegation_root_id(false); + let alternative_hierarchy_root_id = delegation_mock::get_delegation_hierarchy_id(false); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attester.clone()), + delegation_mock::generate_base_delegation_node( + hierarchy_root_id, + attester.clone(), + Some(alternative_hierarchy_root_id), + ), ); - delegation_node.permissions = delegation::Permissions::ATTEST; + delegation_node.details.permissions = delegation::Permissions::ATTEST; let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -340,9 +342,12 @@ fn root_not_present_attest_error() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(alternative_root_id, root_node)]) + .with_delegation_hierarchies(vec![( + alternative_hierarchy_root_id, + hierarchy_details, + attester.clone(), + )]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(alternative_root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -353,7 +358,7 @@ fn root_not_present_attest_error() { operation.ctype_hash, operation.delegation_id ), - delegation::Error::::RootNotFound + delegation::Error::::HierarchyNotFound ); }); } @@ -364,16 +369,16 @@ fn root_ctype_mismatch_attest_error() { let attester = get_ed25519_account(attester_keypair.public()); let claim_hash = get_claim_hash(true); let alternative_ctype_hash = ctype_mock::get_ctype_hash(false); - let (root_id, mut root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(attester.clone()), + let (hierarchy_root_id, mut hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); - root_node.ctype_hash = alternative_ctype_hash; + hierarchy_details.ctype_hash = alternative_ctype_hash; let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attester.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attester.clone(), Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; + delegation_node.details.permissions = delegation::Permissions::ATTEST; let mut attestation = generate_base_attestation(attester.clone()); attestation.delegation_id = Some(delegation_id); @@ -383,9 +388,8 @@ fn root_ctype_mismatch_attest_error() { .with_ctypes(vec![(operation.ctype_hash, attester.clone())]) .build(None); let mut ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, attester.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -442,15 +446,15 @@ fn revoke_with_delegation_successful() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; + delegation_node.details.permissions = delegation::Permissions::ATTEST; // Attestation owned by a different user, but delegation owned by the user // submitting the operation. let mut attestation = generate_base_attestation(attestation_owner); @@ -464,9 +468,8 @@ fn revoke_with_delegation_successful() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) @@ -495,18 +498,18 @@ fn revoke_with_parent_delegation_successful() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (parent_id, mut parent_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - parent_node.permissions = delegation::Permissions::ATTEST; + parent_node.details.permissions = delegation::Permissions::ATTEST; let (delegation_id, delegation_node) = ( delegation_mock::get_delegation_id(false), - delegation_mock::generate_base_delegation_node(root_id, attestation_owner.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attestation_owner.clone(), Some(parent_id)), ); let mut attestation = generate_base_attestation(attestation_owner); attestation.delegation_id = Some(delegation_id); @@ -520,9 +523,8 @@ fn revoke_with_parent_delegation_successful() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![parent_id]), (parent_id, vec![delegation_id])]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) @@ -550,18 +552,18 @@ fn revoke_parent_delegation_no_attestation_permissions_successful() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (parent_id, mut parent_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - parent_node.permissions = delegation::Permissions::DELEGATE; + parent_node.details.permissions = delegation::Permissions::DELEGATE; let (delegation_id, delegation_node) = ( delegation_mock::get_delegation_id(false), - delegation_mock::generate_base_delegation_node(root_id, attestation_owner.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attestation_owner.clone(), Some(parent_id)), ); let mut attestation = generate_base_attestation(attestation_owner); attestation.delegation_id = Some(delegation_id); @@ -575,9 +577,8 @@ fn revoke_parent_delegation_no_attestation_permissions_successful() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![parent_id]), (parent_id, vec![delegation_id])]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) @@ -605,20 +606,20 @@ fn revoke_parent_delegation_with_direct_delegation_revoked_successful() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (parent_id, mut parent_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - parent_node.permissions = delegation::Permissions::ATTEST; + parent_node.details.permissions = delegation::Permissions::ATTEST; let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(false), - delegation_mock::generate_base_delegation_node(root_id, attestation_owner.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attestation_owner.clone(), Some(parent_id)), ); - delegation_node.revoked = true; + delegation_node.details.revoked = true; let mut attestation = generate_base_attestation(attestation_owner); attestation.delegation_id = Some(delegation_id); @@ -631,9 +632,8 @@ fn revoke_parent_delegation_with_direct_delegation_revoked_successful() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![parent_id]), (parent_id, vec![delegation_id])]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) @@ -752,20 +752,19 @@ fn max_parent_lookups_revoke_error() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); let (delegation_id, mut delegation_node) = ( - delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, attestation_owner.clone()), + delegation_mock::get_delegation_id(false), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, attestation_owner.clone(), Some(parent_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; - delegation_node.parent = Some(parent_delegation_id); + delegation_node.details.permissions = delegation::Permissions::ATTEST; let mut attestation = generate_base_attestation(attestation_owner); attestation.delegation_id = Some(delegation_id); @@ -776,15 +775,8 @@ fn max_parent_lookups_revoke_error() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) @@ -810,16 +802,16 @@ fn revoked_delegation_revoke_error() { let attestation_owner = get_ed25519_account(attestation_owner_keypair.public()); let claim_hash = get_claim_hash(true); - let (root_id, root_node) = ( - delegation_mock::get_delegation_root_id(true), - delegation_mock::generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + delegation_mock::get_delegation_hierarchy_id(true), + delegation_mock::generate_base_delegation_hierarchy_details(), ); let (delegation_id, mut delegation_node) = ( delegation_mock::get_delegation_id(true), - delegation_mock::generate_base_delegation_node(root_id, revoker.clone()), + delegation_mock::generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - delegation_node.permissions = delegation::Permissions::ATTEST; - delegation_node.revoked = true; + delegation_node.details.permissions = delegation::Permissions::ATTEST; + delegation_node.details.revoked = true; let mut attestation = generate_base_attestation(attestation_owner); attestation.delegation_id = Some(delegation_id); @@ -829,9 +821,8 @@ fn revoked_delegation_revoke_error() { .with_ctypes(vec![(attestation.ctype_hash, revoker.clone())]) .build(None); let ext = delegation_mock::ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); let mut ext = ExtBuilder::default() .with_attestations(vec![(operation.claim_hash, attestation)]) diff --git a/pallets/ctype/src/lib.rs b/pallets/ctype/src/lib.rs index a45c79991b..285579adb0 100644 --- a/pallets/ctype/src/lib.rs +++ b/pallets/ctype/src/lib.rs @@ -115,8 +115,8 @@ pub mod pallet { #[pallet::call] impl Pallet { - /// Create a new CType from the given unique CType hashand associates it - /// with its creator. + /// Create a new CType from the given unique CType hash and associates + /// it with its creator. /// /// A CType with the same hash must not be stored on chain. /// diff --git a/pallets/delegation/Cargo.toml b/pallets/delegation/Cargo.toml index 06a551e0e1..4b2e647ac7 100644 --- a/pallets/delegation/Cargo.toml +++ b/pallets/delegation/Cargo.toml @@ -14,6 +14,7 @@ substrate-wasm-builder-runner = {version = "3.0.0"} [dev-dependencies] ctype = {features = ["mock"], path = "../ctype", version = "0.24.0"} +env_logger = {version = "0.8.4"} kilt-primitives = {default-features = false, path = "../../primitives"} serde = {version = "1.0.101"} sp-core = {branch = "polkadot-v0.9.8", default-features = false, git = "https://github.com/paritytech/substrate", version = "3.0.0"} diff --git a/pallets/delegation/src/benchmarking.rs b/pallets/delegation/src/benchmarking.rs index 1836759089..62a00badd6 100644 --- a/pallets/delegation/src/benchmarking.rs +++ b/pallets/delegation/src/benchmarking.rs @@ -23,7 +23,7 @@ use frame_system::RawOrigin; use sp_core::{offchain::KeyTypeId, sr25519}; use sp_io::crypto::sr25519_generate; use sp_runtime::MultiSignature; -use sp_std::{num::NonZeroU32, vec::Vec}; +use sp_std::{collections::btree_set::BTreeSet, num::NonZeroU32, vec::Vec}; use crate::*; @@ -45,20 +45,10 @@ where hash.into() } -/// sets parent to `None` if it is the root -fn parent_id_check( - root_id: T::DelegationNodeId, - parent_id: T::DelegationNodeId, -) -> Option { - if parent_id == root_id { - None - } else { - Some(parent_id) - } -} - /// add ctype to storage and root delegation -fn add_root_delegation(number: u32) -> Result<(DelegationTriplet, T::Hash), DispatchErrorWithPostInfo> +fn add_delegation_hierarchy( + number: u32, +) -> Result<(DelegationTriplet, T::Hash), DispatchErrorWithPostInfo> where T::AccountId: From, T::DelegationNodeId: From, @@ -66,16 +56,20 @@ where let root_public = sr25519_generate(KeyTypeId(*b"aura"), None); let root_acc: T::AccountId = root_public.into(); let ctype_hash = ::default(); - let root_id = generate_delegation_id::(number); + let hierarchy_root_id = generate_delegation_id::(number); ctype::Pallet::::add(RawOrigin::Signed(root_acc.clone()).into(), ctype_hash)?; - Pallet::::create_root(RawOrigin::Signed(root_acc.clone()).into(), root_id, ctype_hash)?; + Pallet::::create_hierarchy( + RawOrigin::Signed(root_acc.clone()).into(), + hierarchy_root_id, + ctype_hash, + )?; Ok(( DelegationTriplet:: { public: root_public, acc: root_acc, - delegation_id: root_id, + delegation_id: hierarchy_root_id, }, ctype_hash, )) @@ -107,11 +101,10 @@ where let delegation_acc_id: T::AccountId = delegation_acc_public.into(); let delegation_id = generate_delegation_id::(level * children_per_level.get() + c); - // only set parent if not root - let parent = parent_id_check::(root_id, parent_id); - // delegate signs delegation to parent - let hash: Vec = Pallet::::calculate_hash(&delegation_id, &root_id, &parent, &permissions).encode(); + let hash: Vec = + Pallet::::calculate_delegation_creation_hash(&delegation_id, &root_id, &parent_id, &permissions) + .encode(); let sig = sp_io::crypto::sr25519_sign(KeyTypeId(*b"aura"), &delegation_acc_public, hash.as_ref()) .ok_or("Error while building signature of delegation.")?; @@ -119,8 +112,7 @@ where let _ = Pallet::::add_delegation( RawOrigin::Signed(parent_acc_id.clone()).into(), delegation_id, - root_id, - parent, + parent_id, delegation_acc_id.clone().into(), permissions, MultiSignature::from(sig).encode(), @@ -169,58 +161,40 @@ where DelegationTriplet:: { public: root_public, acc: root_acc, - delegation_id: root_id, + delegation_id: hierarchy_id, }, _, - ) = add_root_delegation::(0)?; + ) = add_delegation_hierarchy::(0)?; // iterate levels and start with parent == root let (leaf_acc_public, _, leaf_id) = add_children::( - root_id, - root_id, + hierarchy_id, + hierarchy_id, root_public, root_acc, permissions, levels, children_per_level, )?; - Ok((root_public, root_id, leaf_acc_public, leaf_id)) + Ok((root_public, hierarchy_id, leaf_acc_public, leaf_id)) } benchmarks! { where_clause { where T: core::fmt::Debug, T::AccountId: From + Into, T::DelegationNodeId: From, ::Origin: From::DelegationEntityId>> } - create_root { + create_hierarchy { let caller: T::AccountId = account("caller", 0, SEED); let ctype = ::default(); let delegation = generate_delegation_id::(0); ctype::Pallet::::add(RawOrigin::Signed(caller.clone()).into(), ctype)?; }: _(RawOrigin::Signed(caller), delegation, ctype) verify { - assert!(Roots::::contains_key(delegation)); - } - - revoke_root { - let r in 1 .. T::MaxRevocations::get(); - let (root_acc, root_id, leaf_acc, leaf_id) = setup_delegations::(r, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; - let root_acc_id: T::AccountId = root_acc.into(); - }: _(RawOrigin::Signed(root_acc_id.clone()), root_id, r) - verify { - assert!(Roots::::contains_key(root_id)); - let root_delegation = Roots::::get(root_id).ok_or("Missing root delegation")?; - assert_eq!(root_delegation.owner, root_acc_id.into()); - assert!(root_delegation.revoked); - - assert!(Delegations::::contains_key(leaf_id)); - let leaf_delegation = Delegations::::get(leaf_id).ok_or("Missing leaf delegation")?; - assert_eq!(leaf_delegation.root_id, root_id); - assert_eq!(leaf_delegation.owner, T::AccountId::from(leaf_acc).into()); - assert!(leaf_delegation.revoked); + assert!(DelegationHierarchies::::contains_key(delegation)); } add_delegation { // do setup - let (_, root_id, leaf_acc, leaf_id) = setup_delegations::(1, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; + let (_, hierarchy_id, leaf_acc, leaf_id) = setup_delegations::(1, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; // add one more delegation let delegate_acc_public = sr25519_generate( @@ -228,17 +202,17 @@ benchmarks! { None ); let delegation_id = generate_delegation_id::(u32::MAX); - let parent_id = parent_id_check::(root_id, leaf_id); + let parent_id = leaf_id; let perm: Permissions = Permissions::ATTEST | Permissions::DELEGATE; - let hash_root = Pallet::::calculate_hash(&delegation_id, &root_id, &parent_id, &perm); + let hash_root = Pallet::::calculate_delegation_creation_hash(&delegation_id, &hierarchy_id, &parent_id, &perm); let sig = sp_io::crypto::sr25519_sign(KeyTypeId(*b"aura"), &delegate_acc_public, hash_root.as_ref()).ok_or("Error while building signature of delegation.")?; let delegate_acc_id: T::AccountId = delegate_acc_public.into(); let leaf_acc_id: T::AccountId = leaf_acc.into(); - }: _(RawOrigin::Signed(leaf_acc_id), delegation_id, root_id, parent_id, delegate_acc_id.into(), perm, MultiSignature::from(sig).encode()) + }: _(RawOrigin::Signed(leaf_acc_id), delegation_id, parent_id, delegate_acc_id.into(), perm, MultiSignature::from(sig).encode()) verify { - assert!(Delegations::::contains_key(delegation_id)); + assert!(DelegationNodes::::contains_key(delegation_id)); } // worst case #1: revoke a child of the root delegation @@ -247,21 +221,22 @@ benchmarks! { revoke_delegation_root_child { let r in 1 .. T::MaxRevocations::get(); let c in 1 .. T::MaxParentChecks::get(); - let (_, root_id, leaf_acc, leaf_id) = setup_delegations::(r, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; - let children: Vec = Children::::get(root_id).unwrap_or_default(); - let child_id: T::DelegationNodeId = *children.get(0).ok_or("Root should have children")?; - let child_delegation = Delegations::::get(child_id).ok_or("Child of root should have delegation id")?; - }: revoke_delegation(RawOrigin::Signed(child_delegation.owner.clone()), child_id, c, r) + 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 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) verify { - assert!(Delegations::::contains_key(child_id)); - let DelegationNode:: { revoked, .. } = Delegations::::get(leaf_id).ok_or("Child of root should have delegation id")?; - assert!(revoked); - - assert!(Delegations::::contains_key(leaf_id)); - let leaf_delegation = Delegations::::get(leaf_id).ok_or("Missing leaf delegation")?; - assert_eq!(leaf_delegation.root_id, root_id); - assert_eq!(leaf_delegation.owner, T::AccountId::from(leaf_acc).into()); - assert!(leaf_delegation.revoked); + assert!(DelegationNodes::::contains_key(child_id)); + let DelegationNode:: { details, .. } = DelegationNodes::::get(leaf_id).ok_or("Child of root should have delegation id")?; + assert!(details.revoked); + + assert!(DelegationNodes::::contains_key(leaf_id)); + let leaf_delegation = DelegationNodes::::get(leaf_id).ok_or("Missing leaf delegation")?; + assert_eq!(leaf_delegation.hierarchy_root_id, hierarchy_id); + assert_eq!(leaf_delegation.details.owner, T::AccountId::from(leaf_acc).into()); + assert!(leaf_delegation.details.revoked); } // TODO: Might want to add variant iterating over children instead of depth at some later point @@ -274,9 +249,9 @@ benchmarks! { let (root_acc, _, _, leaf_id) = setup_delegations::(c, ONE_CHILD_PER_LEVEL.expect(">0"), Permissions::DELEGATE)?; }: revoke_delegation(RawOrigin::Signed(T::AccountId::from(root_acc).into()), leaf_id, c, r) verify { - assert!(Delegations::::contains_key(leaf_id)); - let DelegationNode:: { revoked, .. } = Delegations::::get(leaf_id).ok_or("Child of root should have delegation id")?; - assert!(revoked); + assert!(DelegationNodes::::contains_key(leaf_id)); + let DelegationNode:: { details, .. } = DelegationNodes::::get(leaf_id).ok_or("Child of root should have delegation id")?; + assert!(details.revoked); } // TODO: Might want to add variant iterating over children instead of depth at some later point } diff --git a/pallets/delegation/src/default_weights.rs b/pallets/delegation/src/default_weights.rs index a5f96986d2..6bee212825 100644 --- a/pallets/delegation/src/default_weights.rs +++ b/pallets/delegation/src/default_weights.rs @@ -19,29 +19,24 @@ //! Autogenerated weights for delegation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-11, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ +//! DATE: 2021-07-21, 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: -// ./kilt-parachain +// target/release/kilt-parachain // benchmark -// --chain -// dev -// --execution -// wasm -// --wasm-execution -// compiled -// --pallet -// delegation -// --extrinsic -// * -// --steps -// 1 -// --repeat -// 10 +// --chain=dev +// --execution=wasm +// --wasm-execution=Compiled // --heap-pages=4096 -// --output=../../pallets/delegation/src/default_weights.rs -// --template=../../.maintain/weight-template.hbs +// --extrinsic=* +// --pallet=delegation +// --steps=1 +// --repeat=20 +// --template +// .maintain/weight-template.hbs +// --output +// pallets/delegation/src/default_weights.rs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -53,8 +48,7 @@ use sp_std::marker::PhantomData; /// Weight functions needed for delegation. pub trait WeightInfo { - fn create_root() -> Weight; - fn revoke_root(r: u32, ) -> Weight; + fn create_hierarchy() -> Weight; fn add_delegation() -> Weight; fn revoke_delegation_root_child(r: u32, c: u32, ) -> Weight; fn revoke_delegation_leaf(r: u32, c: u32, ) -> Weight; @@ -63,38 +57,30 @@ pub trait WeightInfo { /// Weights for delegation using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - fn create_root() -> Weight { - (22_442_000_u64) + fn create_hierarchy() -> Weight { + (24_797_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - fn revoke_root(r: u32, ) -> Weight { - (24_418_000_u64) - // Standard Error: 29_000 - .saturating_add((17_591_000_u64).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(2_u64)) } fn add_delegation() -> Weight { - (83_497_000_u64) - .saturating_add(T::DbWeight::get().reads(4_u64)) + (80_841_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 { - (11_210_000_u64) - // Standard Error: 55_000 - .saturating_add((17_485_000_u64).saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(r as Weight))) + (17_804_000_u64) + // Standard Error: 94_000 + .saturating_add((17_445_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 { - (27_413_000_u64) - // Standard Error: 30_000 - .saturating_add((111_000_u64).saturating_mul(r as Weight)) - // Standard Error: 30_000 - .saturating_add((4_692_000_u64).saturating_mul(c as 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)) .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)) @@ -103,38 +89,30 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - fn create_root() -> Weight { - (22_442_000_u64) + fn create_hierarchy() -> Weight { + (24_797_000_u64) .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - fn revoke_root(r: u32, ) -> Weight { - (24_418_000_u64) - // Standard Error: 29_000 - .saturating_add((17_591_000_u64).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } fn add_delegation() -> Weight { - (83_497_000_u64) - .saturating_add(RocksDbWeight::get().reads(4_u64)) + (80_841_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 { - (11_210_000_u64) - // Standard Error: 55_000 - .saturating_add((17_485_000_u64).saturating_mul(r as Weight)) - .saturating_add(RocksDbWeight::get().reads((2_u64).saturating_mul(r as Weight))) + (17_804_000_u64) + // Standard Error: 94_000 + .saturating_add((17_445_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 { - (27_413_000_u64) - // Standard Error: 30_000 - .saturating_add((111_000_u64).saturating_mul(r as Weight)) - // Standard Error: 30_000 - .saturating_add((4_692_000_u64).saturating_mul(c as 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)) .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 b0eee43d48..1f55ed5833 100644 --- a/pallets/delegation/src/delegation_hierarchy.rs +++ b/pallets/delegation/src/delegation_hierarchy.rs @@ -18,6 +18,8 @@ use bitflags::bitflags; use codec::{Decode, Encode}; +use ctype::CtypeHashOf; +use sp_std::collections::btree_set::BTreeSet; use crate::*; @@ -52,87 +54,88 @@ impl Default for Permissions { } } -/// A node representing a delegation hierarchy root. +/// A node in a delegation hierarchy. +/// +/// 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)] -pub struct DelegationRoot { - /// The hash of the CType that delegated attesters within this trust - /// hierarchy can attest. - pub ctype_hash: CtypeHashOf, - /// The identifier of the root owner. - pub owner: DelegatorIdOf, - /// The flag indicating whether the root has been revoked or not. - pub revoked: bool, +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>, + /// The additional information attached to the delegation node. + pub details: DelegationDetails, } -impl DelegationRoot { - pub fn new(ctype_hash: CtypeHashOf, owner: DelegatorIdOf) -> Self { - DelegationRoot { - ctype_hash, - owner, - revoked: false, +impl DelegationNode { + /// Creates a new delegation root node with the given ID and delegation + /// details. + pub fn new_root_node(id: DelegationNodeIdOf, details: DelegationDetails) -> Self { + Self { + hierarchy_root_id: id, + parent: None, + children: BTreeSet::new(), + details, } } + + /// Creates a new delegation node under the given hierarchy ID, with the + /// given parent and delegation details. + pub fn new_node( + hierarchy_root_id: DelegationNodeIdOf, + parent: DelegationNodeIdOf, + details: DelegationDetails, + ) -> Self { + Self { + hierarchy_root_id, + parent: Some(parent), + children: BTreeSet::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); + } } -/// A node representing a node in the delegation hierarchy. +/// Delegation information attached to delegation nodes. #[derive(Clone, Debug, Encode, Decode, PartialEq)] -pub struct DelegationNode { - /// The ID of the delegation hierarchy root. - pub root_id: DelegationNodeIdOf, - /// \[OPTIONAL\] The ID of the parent node. If None, the node is - /// considered a direct child of the root node. - pub parent: Option>, - /// The identifier of the owner of the delegation node, i.e., the delegate. +pub struct DelegationDetails { + /// The owner of the delegation (and its node). pub owner: DelegatorIdOf, - /// The permission flags for the operations the delegate is allowed to - /// perform. - pub permissions: Permissions, - /// The flag indicating whether the delegation has been revoked or not. + /// Status indicating whether the delegation has been revoked (true) or not + /// (false). pub revoked: bool, + /// The set of permissions associated with the delegation. + pub permissions: Permissions, } -impl DelegationNode { - /// Create a new delegation node that is a direct descendent of the - /// given root. +impl DelegationDetails { + /// Creates new delegation details including the given owner. /// - /// * root_id: the root node ID this node will be a child of - /// * owner: the identifier of the owner of the new delegation, i.e., the - /// new delegate - /// * permissions: the permission flags for the operations the delegate is - /// allowed to perform - pub fn new_root_child(root_id: DelegationNodeIdOf, owner: DelegatorIdOf, permissions: Permissions) -> Self { - DelegationNode { - root_id, + /// The default revocation status is false and all permissions are granted + /// by default. + pub fn default_with_owner(owner: DelegatorIdOf) -> Self { + Self { owner, - permissions, + permissions: Permissions::all(), revoked: false, - parent: None, } } +} - /// Creates a new delegation node that is a direct descendent of the - /// given node. - /// - /// * root_id: the root node ID this node will be a child of - /// * parent - the parent node ID this node will be a child of - /// * owner: the identifier of the owner of the new delegation, i.e., the - /// new delegate - /// * permissions: the permission flags for the operations the delegate is - /// allowed to perform - pub fn new_node_child( - root_id: DelegationNodeIdOf, - parent: DelegationNodeIdOf, - owner: DelegatorIdOf, - permissions: Permissions, - ) -> Self { - DelegationNode { - root_id, - parent: Some(parent), - owner, - permissions, - revoked: false, - } - } +/// The details associated with a delegation hierarchy. +#[derive(Clone, Debug, Encode, Decode, Eq, PartialEq, Ord, PartialOrd)] +pub struct DelegationHierarchyDetails { + /// The authorised CTYPE hash that attesters can attest using this + /// delegation hierarchy. + pub ctype_hash: CtypeHashOf, } /// The result that the delegation pallet expects from the implementer of the diff --git a/pallets/delegation/src/deprecated.rs b/pallets/delegation/src/deprecated.rs new file mode 100644 index 0000000000..0f6ea788b3 --- /dev/null +++ b/pallets/delegation/src/deprecated.rs @@ -0,0 +1,103 @@ +// 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 + +/// Deprecated types used in version 1. +pub(crate) mod v1 { + use codec::{Decode, Encode}; + + use crate::*; + + #[derive(Clone, Debug, Encode, Decode, PartialEq)] + pub struct DelegationRoot { + pub(crate) ctype_hash: CtypeHashOf, + pub(crate) owner: DelegatorIdOf, + pub(crate) revoked: bool, + } + + impl DelegationRoot { + #[cfg(test)] + pub(crate) fn new(ctype_hash: CtypeHashOf, owner: DelegatorIdOf) -> Self { + DelegationRoot { + ctype_hash, + owner, + revoked: false, + } + } + } + + #[derive(Clone, Debug, Encode, Decode, PartialEq)] + pub struct DelegationNode { + pub(crate) root_id: DelegationNodeIdOf, + pub(crate) parent: Option>, + pub(crate) owner: DelegatorIdOf, + pub(crate) permissions: Permissions, + pub(crate) revoked: bool, + } + + impl DelegationNode { + #[cfg(test)] + pub(crate) fn new_root_child( + root_id: DelegationNodeIdOf, + owner: DelegatorIdOf, + permissions: Permissions, + ) -> Self { + DelegationNode { + root_id, + owner, + permissions, + revoked: false, + parent: None, + } + } + + #[cfg(test)] + pub(crate) fn new_node_child( + root_id: DelegationNodeIdOf, + parent: DelegationNodeIdOf, + owner: DelegatorIdOf, + permissions: Permissions, + ) -> Self { + DelegationNode { + root_id, + parent: Some(parent), + owner, + permissions, + revoked: false, + } + } + } + + pub(crate) mod storage { + use frame_support::{decl_module, decl_storage}; + use sp_std::prelude::*; + + use super::*; + + decl_module! { + pub struct OldPallet for enum Call where origin: T::Origin {} + } + + decl_storage! { + trait Store for OldPallet as Delegation { + pub(crate) Roots get(fn roots): map hasher(blake2_128_concat) DelegationNodeIdOf => Option>; + pub(crate) Delegations get(fn delegations): map hasher(blake2_128_concat) DelegationNodeIdOf => Option>; + pub(crate) Children get(fn children): map hasher(blake2_128_concat) DelegationNodeIdOf => Option>>; + } + } + } +} diff --git a/pallets/delegation/src/lib.rs b/pallets/delegation/src/lib.rs index 54bef58ccc..ce3229ac82 100644 --- a/pallets/delegation/src/lib.rs +++ b/pallets/delegation/src/lib.rs @@ -75,6 +75,7 @@ pub mod default_weights; pub mod delegation_hierarchy; +pub mod migrations; #[cfg(any(feature = "mock", test))] pub mod mock; @@ -85,14 +86,19 @@ pub mod benchmarking; #[cfg(test)] mod tests; +mod deprecated; + pub use crate::{default_weights::WeightInfo, delegation_hierarchy::*, pallet::*}; use frame_support::{ensure, pallet_prelude::Weight, traits::Get}; use sp_runtime::{traits::Hash, DispatchError}; use sp_std::vec::Vec; +use migrations::*; + #[frame_support::pallet] pub mod pallet { + use super::*; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -121,7 +127,7 @@ pub mod pallet { Signature = Vec, >; type DelegationEntityId: Parameter; - type DelegationNodeId: Parameter + Copy + AsRef<[u8]>; + type DelegationNodeId: Parameter + Copy + AsRef<[u8]> + Eq + PartialEq + Ord + PartialOrd; type EnsureOrigin: EnsureOrigin, ::Origin>; type Event: From> + IsType<::Event>; #[pallet::constant] @@ -138,39 +144,51 @@ pub mod pallet { pub struct Pallet(_); #[pallet::hooks] - impl Hooks> for Pallet {} + impl Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result<(), &'static str> { + migrations::DelegationStorageMigrator::::pre_migrate() + } - /// Delegation root nodes stored on chain. - /// - /// It maps from a root node ID to the full root node. + fn on_runtime_upgrade() -> Weight { + migrations::DelegationStorageMigrator::::migrate() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade() -> Result<(), &'static str> { + migrations::DelegationStorageMigrator::::post_migrate() + } + } + + /// Contains the latest storage version deployed. #[pallet::storage] - #[pallet::getter(fn roots)] - pub type Roots = StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, DelegationRoot>; + #[pallet::getter(fn last_version_migration_used)] + pub(crate) type StorageVersion = StorageValue<_, DelegationStorageVersion, ValueQuery>; /// Delegation nodes stored on chain. /// - /// It maps from a node ID to the full delegation node. + /// It maps from a node ID to the node details. #[pallet::storage] - #[pallet::getter(fn delegations)] - pub type Delegations = StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, DelegationNode>; + #[pallet::getter(fn delegation_nodes)] + pub type DelegationNodes = StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, DelegationNode>; - /// Children delegation nodes. + /// Delegation hierarchies stored on chain. /// - /// It maps from a delegation node ID, including the root node, to the list - /// of children nodes, sorted by time of creation. + /// It maps for a (root) node ID to the hierarchy details. #[pallet::storage] - #[pallet::getter(fn children)] - pub type Children = StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, Vec>>; + #[pallet::getter(fn delegation_hierarchies)] + pub type DelegationHierarchies = + StorageMap<_, Blake2_128Concat, DelegationNodeIdOf, DelegationHierarchyDetails>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// A new root has been created. - /// \[creator ID, root node ID, CType hash\] - RootCreated(DelegatorIdOf, DelegationNodeIdOf, CtypeHashOf), - /// A root has been revoked. + /// A new hierarchy has been created. + /// \[creator ID, root node ID, CTYPE hash\] + HierarchyCreated(DelegatorIdOf, DelegationNodeIdOf, CtypeHashOf), + /// A hierarchy has been revoked. /// \[revoker ID, root node ID\] - RootRevoked(DelegatorIdOf, DelegationNodeIdOf), + HierarchyRevoked(DelegatorIdOf, DelegationNodeIdOf), /// A new delegation has been created. /// \[creator ID, root node ID, delegation node ID, parent node ID, /// delegate ID, permissions\] @@ -178,7 +196,7 @@ pub mod pallet { DelegatorIdOf, DelegationNodeIdOf, DelegationNodeIdOf, - Option>, + DelegationNodeIdOf, DelegatorIdOf, Permissions, ), @@ -198,19 +216,21 @@ pub mod pallet { DelegationNotFound, /// No delegate with the given ID stored on chain. DelegateNotFound, - /// There is already a root node with the same ID stored on chain. - RootAlreadyExists, - /// No root delegation with the given ID stored on chain. - RootNotFound, + /// There is already a hierarchy with the same ID stored on chain. + HierarchyAlreadyExists, + /// No hierarchy with the given ID stored on chain. + HierarchyNotFound, /// Max number of nodes checked without verifying the given condition. MaxSearchDepthReached, /// Max number of nodes checked without verifying the given condition. NotOwnerOfParentDelegation, /// The delegation creator is not allowed to write the delegation /// because he is not the owner of the delegation root node. - NotOwnerOfRootDelegation, + NotOwnerOfDelegationHierarchy, /// No parent delegation with the given ID stored on chain. ParentDelegationNotFound, + /// The parent delegation has previously been revoked. + ParentDelegationRevoked, /// The delegation revoker is not allowed to revoke the delegation. UnauthorizedRevocation, /// The delegation creator is not allowed to create the delegation. @@ -246,15 +266,18 @@ pub mod pallet { /// - Reads: [Origin Account], Roots, CTypes /// - Writes: Roots /// # - #[pallet::weight(::WeightInfo::create_root())] - pub fn create_root( + #[pallet::weight(::WeightInfo::create_hierarchy())] + pub fn create_hierarchy( origin: OriginFor, - root_id: DelegationNodeIdOf, + root_node_id: DelegationNodeIdOf, ctype_hash: CtypeHashOf, ) -> DispatchResult { let creator = ::EnsureOrigin::ensure_origin(origin)?; - ensure!(!>::contains_key(&root_id), Error::::RootAlreadyExists); + ensure!( + !>::contains_key(&root_node_id), + Error::::HierarchyAlreadyExists + ); ensure!( >::contains_key(&ctype_hash), @@ -262,9 +285,14 @@ pub mod pallet { ); log::debug!("insert Delegation Root"); - >::insert(&root_id, DelegationRoot::new(ctype_hash, creator.clone())); - Self::deposit_event(Event::RootCreated(creator, root_id, ctype_hash)); + Self::create_and_store_new_hierarchy( + root_node_id, + DelegationHierarchyDetails:: { ctype_hash }, + creator.clone(), + ); + + Self::deposit_event(Event::HierarchyCreated(creator, root_node_id, ctype_hash)); Ok(()) } @@ -298,16 +326,24 @@ pub mod pallet { pub fn add_delegation( origin: OriginFor, delegation_id: DelegationNodeIdOf, - root_id: DelegationNodeIdOf, - parent_id: Option>, + parent_id: DelegationNodeIdOf, delegate: DelegatorIdOf, permissions: Permissions, delegate_signature: DelegateSignatureTypeOf, ) -> DispatchResult { let delegator = ::EnsureOrigin::ensure_origin(origin)?; + ensure!( + !>::contains_key(&delegation_id), + Error::::DelegationAlreadyExists + ); + + let parent_node = >::get(&parent_id).ok_or(Error::::ParentDelegationNotFound)?; + let hierarchy_root_id = parent_node.hierarchy_root_id; + // Calculate the hash root - let hash_root = Self::calculate_hash(&delegation_id, &root_id, &parent_id, &permissions); + let hash_root = + Self::calculate_delegation_creation_hash(&delegation_id, &hierarchy_root_id, &parent_id, &permissions); // Verify that the hash root signature is correct. DelegationSignatureVerificationOf::::verify(&delegate, &hash_root.encode(), &delegate_signature) @@ -316,57 +352,38 @@ pub mod pallet { SignatureVerificationError::SignatureInvalid => Error::::InvalidDelegateSignature, })?; + // Check if the parent's delegate is the creator of this delegation node... ensure!( - !>::contains_key(&delegation_id), - Error::::DelegationAlreadyExists + parent_node.details.owner == delegator, + Error::::NotOwnerOfParentDelegation + ); + // ... and that the node has not been revoked... + ensure!(!parent_node.details.revoked, Error::::ParentDelegationRevoked); + // ... and that has permission to delegate + ensure!( + (parent_node.details.permissions & Permissions::DELEGATE) == Permissions::DELEGATE, + Error::::UnauthorizedDelegation ); - let root = >::get(&root_id).ok_or(Error::::RootNotFound)?; - - // Computes the delegation parent. Either the given parent (if allowed) or the - // root node. - let parent = if let Some(parent_id) = parent_id { - let parent_node = >::get(&parent_id).ok_or(Error::::ParentDelegationNotFound)?; - - // Check if the parent's delegate is the creator of this delegation node... - ensure!(parent_node.owner == delegator, Error::::NotOwnerOfParentDelegation); - // ... and has permission to delegate - ensure!( - (parent_node.permissions & Permissions::DELEGATE) == Permissions::DELEGATE, - Error::::UnauthorizedDelegation - ); - - log::debug!("insert Delegation with parent"); - >::insert( - &delegation_id, - DelegationNode::::new_node_child(root_id, parent_id, delegate.clone(), permissions), - ); - - // Return parent_id as the result of this if branch - parent_id - } else { - // Check if the creator of this delegation node is the creator of the root node - // (as no parent is given) - ensure!(root.owner == delegator, Error::::NotOwnerOfRootDelegation); - - log::debug!("insert Delegation without parent"); - >::insert( - &delegation_id, - DelegationNode::::new_root_child(root_id, delegate.clone(), permissions), - ); - - // Return node_id as the result of this if branch - root_id - }; - - // Regardless of the node returned as parent, add the new node as a child of - // that node - Self::add_child(delegation_id, parent); + Self::store_delegation_under_parent( + delegation_id, + DelegationNode::new_node( + hierarchy_root_id, + parent_id, + DelegationDetails { + owner: delegate.clone(), + permissions, + revoked: false, + }, + ), + parent_id, + parent_node, + ); Self::deposit_event(Event::DelegationCreated( delegator, + hierarchy_root_id, delegation_id, - root_id, parent_id, delegate, permissions, @@ -375,62 +392,8 @@ pub mod pallet { Ok(()) } - /// Revoke a delegation root and the whole delegation hierarchy below. - /// - /// Revoking a delegation root results in the whole trust hierarchy - /// 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 consistent as no child would - /// "survive" its parent. As a consequence, if the root node is revoked, - /// the whole trust hierarchy is to be considered revoked. - /// - /// The dispatch origin must be `DelegationEntityId`. - /// - /// Emits `RootRevoked` and C * `DelegationRevoked`. - /// - /// # - /// Weight: O(C) where C is the number of children of the root which is - /// bounded by `max_children`. - /// - Reads: [Origin Account], Roots, C * Delegations, C * Children. - /// - Writes: Roots, C * Delegations - /// # - #[pallet::weight(::WeightInfo::revoke_root(*max_children))] - pub fn revoke_root( - origin: OriginFor, - root_id: DelegationNodeIdOf, - max_children: u32, - ) -> DispatchResultWithPostInfo { - let invoker = ::EnsureOrigin::ensure_origin(origin)?; - - let mut root = >::get(&root_id).ok_or(Error::::RootNotFound)?; - - ensure!(root.owner == invoker, Error::::UnauthorizedRevocation); - - ensure!( - max_children <= T::MaxRevocations::get(), - Error::::MaxRevocationsTooLarge - ); - - let consumed_weight: Weight = if !root.revoked { - // Recursively revoke all children - let (_, post_weight) = Self::revoke_children(&root_id, &invoker, max_children)?; - - // If we didn't return an ExceededRevocationBounds error, we can revoke the root - // too. - root.revoked = true; - >::insert(&root_id, root); - - post_weight.saturating_add(T::DbWeight::get().writes(1)) - } else { - 0 - }; - - Self::deposit_event(Event::RootRevoked(invoker, root_id)); - - Ok(Some(consumed_weight.saturating_add(T::DbWeight::get().reads(1))).into()) - } - - /// Revoke a delegation node and all its children. + /// Revoke a delegation node (potentially a root node) and all its + /// children. /// /// Revoking a delegation node results in the trust hierarchy starting /// from the given node being revoked. Nevertheless, revocation starts @@ -462,7 +425,7 @@ pub mod pallet { let invoker = ::EnsureOrigin::ensure_origin(origin)?; ensure!( - >::contains_key(&delegation_id), + >::contains_key(&delegation_id), Error::::DelegationNotFound ); @@ -471,16 +434,22 @@ pub mod pallet { Error::::MaxParentChecksTooLarge ); - let (authorized, parent_checks) = Self::is_delegating(&invoker, &delegation_id, max_parent_checks)?; - ensure!(authorized, Error::::UnauthorizedRevocation); - ensure!( max_revocations <= T::MaxRevocations::get(), Error::::MaxRevocationsTooLarge ); - // Revoke the delegation and recursively all of its children - let (revocation_checks, _) = Self::revoke(&delegation_id, &invoker, max_revocations)?; + let (authorized, parent_checks) = Self::is_delegating(&invoker, &delegation_id, max_parent_checks)?; + ensure!(authorized, Error::::UnauthorizedRevocation); + + // Revoke the delegation and recursively all of its children (add 1 to + // max_revocations to account for the node itself) + let (revocation_checks, _) = Self::revoke(&delegation_id, &invoker, max_revocations.saturating_add(1))?; + + // If the revoked node is a root node, emit also a HierarchyRevoked event. + if DelegationHierarchies::::contains_key(&delegation_id) { + Self::deposit_event(Event::HierarchyRevoked(invoker, delegation_id)); + } // Add worst case reads from `is_delegating` Ok(Some( @@ -494,28 +463,55 @@ pub mod pallet { } impl Pallet { - /// Calculate the hash of all values of a delegation transaction. + /// Calculate the hash of all values of a delegation creation transaction. /// /// # /// Weight: O(1) /// # - fn calculate_hash( + fn calculate_delegation_creation_hash( delegation_id: &DelegationNodeIdOf, root_id: &DelegationNodeIdOf, - parent_id: &Option>, + parent_id: &DelegationNodeIdOf, permissions: &Permissions, ) -> T::Hash { - // Add all values to an u8 vector + // Add all values to an u8 vector. let mut hashed_values: Vec = delegation_id.as_ref().to_vec(); hashed_values.extend_from_slice(root_id.as_ref()); - if let Some(parent) = parent_id { - hashed_values.extend_from_slice(parent.as_ref()) - } + hashed_values.extend_from_slice(parent_id.as_ref()); hashed_values.extend_from_slice(permissions.as_u8().as_ref()); // Hash the resulting vector T::Hashing::hash(&hashed_values) } + // Creates a new root node with the given details and store the new hierarchy in + // the hierarchies storage and the new root node in the nodes storage. + fn create_and_store_new_hierarchy( + root_id: DelegationNodeIdOf, + hierarchy_details: DelegationHierarchyDetails, + hierarchy_owner: DelegatorIdOf, + ) { + let root_node = DelegationNode::new_root_node(root_id, DelegationDetails::default_with_owner(hierarchy_owner)); + >::insert(root_id, root_node); + >::insert(root_id, hierarchy_details); + } + + // Adds the given node to the storage and updates the parent node to include the + // given node as child. + // + // This function assumes that the parent node is already stored on the chain. If + // not, the behaviour of the system is undefined. + fn store_delegation_under_parent( + delegation_id: DelegationNodeIdOf, + delegation_node: DelegationNode, + parent_id: DelegationNodeIdOf, + mut parent_node: DelegationNode, + ) { + >::insert(delegation_id, delegation_node); + // Add the new node as a child of that node + parent_node.add_child(delegation_id); + >::insert(parent_id, parent_node); + } + /// Check if an identity is the owner of the given delegation node or any /// node up the hierarchy, and if the delegation has not been yet revoked. /// @@ -535,34 +531,60 @@ impl Pallet { delegation: &DelegationNodeIdOf, max_parent_checks: u32, ) -> Result<(bool, u32), DispatchError> { - let delegation_node = >::get(delegation).ok_or(Error::::DelegationNotFound)?; + let delegation_node = >::get(delegation).ok_or(Error::::DelegationNotFound)?; // Check if the given account is the owner of the delegation and that the // delegation has not been removed - if &delegation_node.owner == identity { - Ok((!delegation_node.revoked, 0u32)) - } else { - // Counter is decreased regardless of whether we are checking the parent node - // next of the root node, as the root node is as a matter of fact the top node's - // parent. + if &delegation_node.details.owner == identity { + Ok((!delegation_node.details.revoked, 0u32)) + } else if let Some(parent) = delegation_node.parent { + // Only decrease (and perhaps fail) remaining_lookups if there are more parents + // to visit let remaining_lookups = max_parent_checks .checked_sub(1) .ok_or(Error::::MaxSearchDepthReached)?; - if let Some(parent) = delegation_node.parent { - // Recursively check upwards in hierarchy - Self::is_delegating(identity, &parent, remaining_lookups) - } else { - // Return whether the given account is the owner of the root and the root has - // not been revoked - let root = >::get(delegation_node.root_id).ok_or(Error::::RootNotFound)?; - Ok(( - (&root.owner == identity) && !root.revoked, - // safe because remaining lookups is at most max_parent_checks - max_parent_checks - remaining_lookups, - )) + // Recursively check upwards in hierarchy + Self::is_delegating(identity, &parent, remaining_lookups) + } else { + // Return false and return max_parent_checks as no other check is performed + Ok((false, max_parent_checks)) + } + } + + /// Revokes all children of a delegation. + /// Returns the number of revoked delegations and the consumed weight. + /// + /// # + /// Weight: O(C) where C is the number of children of the delegation node + /// which is bounded by `max_children`. + /// - Reads: C * Children, C * Delegations + /// - Writes: C * Delegations + /// # + fn revoke_children( + delegation: &DelegationNodeIdOf, + sender: &DelegatorIdOf, + max_revocations: u32, + ) -> Result<(u32, Weight), DispatchError> { + let mut revocations: u32 = 0; + let mut consumed_weight: Weight = 0; + if let Some(delegation_node) = >::get(delegation) { + // Iterate children and revoke all nodes + for child in delegation_node.children.iter() { + let remaining_revocations = max_revocations + .checked_sub(revocations) + .ok_or(Error::::ExceededRevocationBounds)?; + + // Check whether we ran out of gas + ensure!(remaining_revocations > 0, Error::::ExceededRevocationBounds); + + Self::revoke(child, sender, remaining_revocations).map(|(r, w)| { + revocations = revocations.saturating_add(r); + consumed_weight = consumed_weight.saturating_add(w); + })?; } } + Ok((revocations, consumed_weight.saturating_add(T::DbWeight::get().reads(1)))) } /// Revoke a delegation and all of its children recursively. @@ -583,11 +605,11 @@ impl Pallet { let mut revocations: u32 = 0; let mut consumed_weight: Weight = 0; // Retrieve delegation node from storage - let mut delegation_node = >::get(*delegation).ok_or(Error::::DelegationNotFound)?; + let mut delegation_node = >::get(*delegation).ok_or(Error::::DelegationNotFound)?; consumed_weight = consumed_weight.saturating_add(T::DbWeight::get().reads(1)); // Check if already revoked - if !delegation_node.revoked { + if !delegation_node.details.revoked { // First revoke all children recursively let remaining_revocations = max_revocations .checked_sub(1) @@ -602,8 +624,8 @@ impl Pallet { ensure!(revocations < max_revocations, Error::::ExceededRevocationBounds); // Set revoked flag and store delegation node - delegation_node.revoked = true; - >::insert(*delegation, delegation_node); + delegation_node.details.revoked = true; + >::insert(*delegation, delegation_node); consumed_weight = consumed_weight.saturating_add(T::DbWeight::get().writes(1)); // Deposit event that the delegation has been revoked Self::deposit_event(Event::DelegationRevoked(sender.clone(), *delegation)); @@ -611,56 +633,4 @@ impl Pallet { } Ok((revocations, consumed_weight)) } - - /// Revokes all children of a delegation. - /// Returns the number of revoked delegations and the consumed weight. - /// - /// # - /// Weight: O(C) where C is the number of children of the delegation node - /// which is bounded by `max_children`. - /// - Reads: C * Children, C * Delegations - /// - Writes: C * Delegations - /// # - fn revoke_children( - delegation: &DelegationNodeIdOf, - sender: &DelegatorIdOf, - max_revocations: u32, - ) -> Result<(u32, Weight), DispatchError> { - let mut revocations: u32 = 0; - let mut consumed_weight: Weight = 0; - // Check if there's a child vector in the storage - if let Some(children) = >::get(delegation) { - consumed_weight = consumed_weight.saturating_add(T::DbWeight::get().reads(1)); - - // Iterate child vector and revoke all nodes - for child in children { - let remaining_revocations = max_revocations - .checked_sub(revocations) - .ok_or(Error::::ExceededRevocationBounds)?; - - // Check whether we ran out of gas - ensure!(remaining_revocations > 0, Error::::ExceededRevocationBounds); - - Self::revoke(&child, sender, remaining_revocations).map(|(r, w)| { - revocations = revocations.saturating_add(r); - consumed_weight = consumed_weight.saturating_add(w); - })?; - } - } - Ok((revocations, consumed_weight.saturating_add(T::DbWeight::get().reads(1)))) - } - - /// Add a child node into the delegation hierarchy. - /// - /// # - /// Weight: O(1) - /// - Reads: Children - /// - Writes: Children - /// # - fn add_child(child: DelegationNodeIdOf, parent: DelegationNodeIdOf) { - // Get the children vector or initialize an empty one if none - let mut children = >::get(parent).unwrap_or_default(); - children.push(child); - >::insert(parent, children); - } } diff --git a/pallets/delegation/src/migrations.rs b/pallets/delegation/src/migrations.rs new file mode 100644 index 0000000000..b4a6b447e9 --- /dev/null +++ b/pallets/delegation/src/migrations.rs @@ -0,0 +1,223 @@ +// 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 codec::{Decode, Encode}; +use sp_std::marker::PhantomData; + +use crate::*; + +mod v1; + +/// 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>; +} + +/// Storage version of the delegation pallet. +#[derive(Copy, Clone, Encode, Eq, Decode, Ord, PartialEq, PartialOrd)] +pub enum DelegationStorageVersion { + V1, + V2, +} + +#[cfg(feature = "try-runtime")] +impl DelegationStorageVersion { + /// The latest storage version. + fn latest() -> Self { + Self::V2 + } +} + +// 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 DelegationStorageVersion { + fn default() -> Self { + Self::V1 + } +} + +impl VersionMigratorTrait for DelegationStorageVersion { + // 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 => v1::pre_migrate::(), + Self::V2 => Err("Already latest v2 version."), + } + } + + // It runs the righ migration logic depending on the current storage version. + fn migrate(&self) -> Weight { + match *self { + Self::V1 => v1::migrate::(), + Self::V2 => 0u64, + } + } + + // 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 => v1::post_migrate::(), + Self::V2 => Err("Migration from v2 should have never happened in the first place."), + } + } +} + +/// The delegation 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 DelegationStorageMigrator(PhantomData); + +impl DelegationStorageMigrator { + // Contains the migration sequence logic. + fn get_next_storage_version(current: DelegationStorageVersion) -> Option { + // If the version current deployed is at least v1, there is no more migrations + // to run (other than the one from v1). + match current { + DelegationStorageVersion::V1 => None, + DelegationStorageVersion::V2 => None, + } + } + + /// 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() < DelegationStorageVersion::latest(), + "Already the latest storage version." + ); + + // 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. + + 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 + } + + /// 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() == DelegationStorageVersion::latest(), + "Not updated to the latest version." + ); + + Ok(()) + } +} + +// Tests for the entire storage migrator. +#[cfg(test)] +mod tests { + use super::*; + + use crate::mock::Test as TestRuntime; + + #[test] + fn ok_from_v1_migration() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V1) + .build(None); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + assert!( + DelegationStorageMigrator::::pre_migrate().is_ok(), + "Storage pre-migrate from v1 should not fail." + ); + + DelegationStorageMigrator::::migrate(); + + #[cfg(feature = "try-runtime")] + assert!( + DelegationStorageMigrator::::post_migrate().is_ok(), + "Storage post-migrate from v1 should not fail." + ); + }); + } + + #[test] + fn ok_from_default_migration() { + let mut ext = mock::ExtBuilder::default().build(None); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + assert!( + DelegationStorageMigrator::::pre_migrate().is_ok(), + "Storage pre-migrate from default version should not fail." + ); + + DelegationStorageMigrator::::migrate(); + + #[cfg(feature = "try-runtime")] + assert!( + DelegationStorageMigrator::::post_migrate().is_ok(), + "Storage post-migrate from default version should not fail." + ); + }); + } +} diff --git a/pallets/delegation/src/migrations/v1.rs b/pallets/delegation/src/migrations/v1.rs new file mode 100644 index 0000000000..f69a115ec7 --- /dev/null +++ b/pallets/delegation/src/migrations/v1.rs @@ -0,0 +1,522 @@ +// 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 frame_support::{IterableStorageMap, StorageMap, StoragePrefixedMap}; +use sp_runtime::traits::Zero; +use sp_std::collections::btree_map::BTreeMap; + +/// Checks whether the deployed storage version is v1. If not, it won't try +/// migrate any data. +/// +/// Since we have the default storage version to this one, it can happen +/// that new nodes will still try to perform runtime migrations. This is not +/// a problem as at the end of the day there will not be anything in the old +/// storage entries to migrate from. Hence, the "pseudo-"migration will +/// simply result in the update of the storage deployed version. +#[cfg(feature = "try-runtime")] +pub(crate) fn pre_migrate() -> Result<(), &'static str> { + ensure!( + StorageVersion::::get() == DelegationStorageVersion::V1, + "Current deployed version is not v1." + ); + + log::info!("Version storage migrating from v1 to v2"); + Ok(()) +} + +/// It migrates the old storage entries to the new ones. +/// +/// Specifically, for each entry in Roots, a new entry in +/// DelegationHierarchies + a new node in DelegationNodes is created. +/// Furthermore, nodes in Delegations are migrated to the new structure and +/// stored under DelegationNodes, with any children from the Children +/// storage entry added to the nodes under the children set. +pub(crate) fn migrate() -> Weight { + log::info!("v1 -> v2 delegation storage migrator started!"); + let mut total_weight = Weight::zero(); + + // Before being stored, the nodes are saved in a map so that after we go over + // all the nodes and the parent-child relationship in the storage, we can update + // the `parent` link of each node accordingly. Otherwise, we would need to save + // the node in the storage, and then retrieve it again to update the parent + // link. + let mut new_nodes: BTreeMap, DelegationNode> = BTreeMap::new(); + + // First iterate over the delegation roots and translate them to hierarchies. + total_weight = total_weight.saturating_add(migrate_roots::(&mut new_nodes)); + + // Then iterate over the regular delegation nodes. + total_weight = total_weight.saturating_add(migrate_nodes::(&mut new_nodes, total_weight)); + + // By now, all the children should have been correctly added to the nodes. + // We now need to modify all the nodes that are children by adding a reference + // to their parents. + total_weight = total_weight.saturating_add(finalize_children_nodes::(&mut new_nodes, total_weight)); + + StorageVersion::::set(DelegationStorageVersion::V2); + // Adds a write from StorageVersion::set() weight. + total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); + log::debug!("Total weight consumed: {}", total_weight); + log::info!("v1 -> v2 delegation storage migrator finished!"); + + total_weight +} + +fn migrate_roots(new_nodes: &mut BTreeMap, DelegationNode>) -> Weight { + let total_weight = deprecated::v1::storage::Roots::::iter().fold( + Weight::zero(), + |mut total_weight, (old_root_id, old_root_node)| { + let new_hierarchy_details = DelegationHierarchyDetails:: { + ctype_hash: old_root_node.ctype_hash, + }; + let new_root_details = DelegationDetails:: { + owner: old_root_node.owner, + // Old roots did not have any permissions. So now we give them all permissions. + permissions: Permissions::all(), + revoked: old_root_node.revoked, + }; + // In here, we already check for potential children of root nodes and ONLY + // update the children information. The parent information will be updated + // 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(); + } + // Add Children::take() weight + total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); + + DelegationHierarchies::insert(old_root_id, new_hierarchy_details); + // Adds a read from Roots::drain() and a write from + // DelegationHierarchies::insert() weights + total_weight = total_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + // Add the node to the temporary map of nodes to be added at the end. + new_nodes.insert(old_root_id, new_root_node); + + total_weight + }, + ); + + // If runtime testing, makes sure that the old number of roots is reflected in + // the new number of nodes and hierarchies migrated. + #[cfg(feature = "try-runtime")] + { + assert_eq!( + deprecated::v1::storage::Roots::::iter().count(), + DelegationHierarchies::::iter().count(), + "The # of old roots does not match the # of new delegation hierarchies." + ); + + assert_eq!( + deprecated::v1::storage::Roots::::iter().count(), + new_nodes.iter().count(), + "The # of old roots does not match the current # of new delegation nodes." + ); + + log::info!( + "{} root(s) migrated.", + deprecated::v1::storage::Roots::::iter().count() + ); + } + + // Removes the whole Roots storage. + frame_support::migration::remove_storage_prefix( + deprecated::v1::storage::Roots::::module_prefix(), + deprecated::v1::storage::Roots::::storage_prefix(), + b"", + ); + + total_weight +} + +fn migrate_nodes( + new_nodes: &mut BTreeMap, DelegationNode>, + initial_weight: Weight, +) -> Weight { + let total_weight = deprecated::v1::storage::Delegations::::iter().fold( + initial_weight, + |mut total_weight, (old_node_id, old_node)| { + let new_node_details = DelegationDetails:: { + owner: old_node.owner, + permissions: old_node.permissions, + revoked: old_node.revoked, + }; + // In the old version, a parent None indicated the node is a child of the root. + 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(); + } + // Add Children::take() weight + total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); + // Adds a read from Roots::drain() weight + total_weight = total_weight.saturating_add(T::DbWeight::get().reads(1)); + new_nodes.insert(old_node_id, new_node); + + total_weight + }, + ); + + // If runtime testing, makes sure that the old number of delegations is + // reflected in the new number of nodes that will be added to the storage. + #[cfg(feature = "try-runtime")] + { + assert_eq!( + deprecated::v1::storage::Delegations::::iter().count(), + new_nodes.iter().count().saturating_sub(DelegationHierarchies::::iter().count()), + "The # of old delegation nodes does not match the # of new delegation nodes (calculate as the total # of nodes - the # of delegation hierarchies)." + ); + + log::info!( + "{} regular node(s) migrated.", + deprecated::v1::storage::Delegations::::iter().count() + ); + } + + // Removes the whole Delegations and Children storages. + frame_support::migration::remove_storage_prefix( + deprecated::v1::storage::Delegations::::module_prefix(), + deprecated::v1::storage::Delegations::::storage_prefix(), + b"", + ); + frame_support::migration::remove_storage_prefix( + deprecated::v1::storage::Children::::module_prefix(), + deprecated::v1::storage::Children::::storage_prefix(), + b"", + ); + + total_weight +} + +fn finalize_children_nodes( + new_nodes: &mut BTreeMap, DelegationNode>, + initial_weight: Weight, +) -> Weight { + new_nodes + .clone() + .into_iter() + .fold(initial_weight, |mut total_weight, (new_node_id, new_node)| { + // Iterate over the children of every node and update their parent link. + new_node.children.iter().for_each(|child_id| { + new_nodes + .entry(*child_id) + .and_modify(|node| node.parent = Some(new_node_id)); + }); + // We can then finally insert the new delegation node in the storage as it won't + // be updated anymore during the migration. + DelegationNodes::::insert(new_node_id, new_node); + // Adds a write from DelegationNodes::insert() weight + total_weight = total_weight.saturating_add(T::DbWeight::get().writes(1)); + + total_weight + }) +} + +/// Checks whether the deployed storage version is v2 and whether any +/// parent-child link has gone missing. +#[cfg(feature = "try-runtime")] +pub(crate) fn post_migrate() -> Result<(), &'static str> { + ensure!( + StorageVersion::::get() == DelegationStorageVersion::V2, + "The version after deployment is not 2 as expected." + ); + ensure!( + verify_parent_children_integrity::(), + "Some parent-child relationship has been broken in the migration." + ); + log::info!("Version storage migrated from v1 to v2"); + Ok(()) +} + +// Verifies that for any node that has a parent, the parent includes that node +// in its children. +#[cfg(feature = "try-runtime")] +fn verify_parent_children_integrity() -> bool { + // If all's good and false is returned, returns true. + !DelegationNodes::::iter().any(|(node_id, node)| { + if let Some(parent_id) = node.parent { + if let Some(parent_node) = DelegationNodes::::get(parent_id) { + // True if the children set does not contain the parent ID + return !parent_node.children.contains(&node_id); + } else { + // If the parent node cannot be found, it is definitely an error, so return + // true. + return true; + } + } + // If all's good we keep returning false. + false + }) +} + +// Tests for the v1 storage migrator. +#[cfg(test)] +mod tests { + use sp_core::Pair; + + use super::*; + use crate::mock::Test as TestRuntime; + + #[test] + fn fail_version_higher() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V2) + .build(None); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + assert!( + pre_migrate::().is_err(), + "Pre-migration for v1 should fail." + ); + }); + } + + #[test] + fn ok_no_delegations() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V1) + .build(None); + ext.execute_with(|| { + #[cfg(feature = "try-runtime")] + assert!( + pre_migrate::().is_ok(), + "Pre-migration for v1 should not fail." + ); + + migrate::(); + + #[cfg(feature = "try-runtime")] + assert!( + post_migrate::().is_ok(), + "Post-migration for v1 should not fail." + ); + }); + } + + #[test] + fn ok_only_root() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V1) + .build(None); + ext.execute_with(|| { + let alice = mock::get_ed25519_account(mock::get_alice_ed25519().public()); + let old_root_id = mock::get_delegation_id(true); + let old_root_node = + crate::deprecated::v1::DelegationRoot::::new(ctype::mock::get_ctype_hash(true), alice); + deprecated::v1::storage::Roots::insert(old_root_id, old_root_node.clone()); + + #[cfg(feature = "try-runtime")] + assert!( + pre_migrate::().is_ok(), + "Pre-migration for v1 should not fail." + ); + + migrate::(); + + #[cfg(feature = "try-runtime")] + assert!( + post_migrate::().is_ok(), + "Post-migration for v1 should not fail." + ); + + assert_eq!(deprecated::v1::storage::Roots::::iter_values().count(), 0); + assert_eq!( + deprecated::v1::storage::Delegations::::iter_values().count(), + 0 + ); + assert_eq!( + deprecated::v1::storage::Children::::iter_values().count(), + 0 + ); + + let new_stored_hierarchy = DelegationHierarchies::::get(old_root_id) + .expect("New delegation hierarchy should exist in the storage."); + assert_eq!(new_stored_hierarchy.ctype_hash, old_root_node.ctype_hash); + let new_stored_root = DelegationNodes::::get(old_root_id) + .expect("New delegation root should exist in the storage."); + assert_eq!(new_stored_root.hierarchy_root_id, old_root_id); + assert!(new_stored_root.parent.is_none()); + assert!(new_stored_root.children.is_empty()); + assert_eq!(new_stored_root.details.owner, old_root_node.owner); + assert_eq!(new_stored_root.details.revoked, old_root_node.revoked); + }); + } + + #[test] + fn ok_root_two_children() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V1) + .build(None); + ext.execute_with(|| { + let alice = mock::get_ed25519_account(mock::get_alice_ed25519().public()); + let bob = mock::get_sr25519_account(mock::get_bob_sr25519().public()); + let old_root_id = mock::get_delegation_id(true); + let old_root_node = + deprecated::v1::DelegationRoot::::new(ctype::mock::get_ctype_hash(true), alice.clone()); + let old_node_id_1 = mock::get_delegation_id(false); + let old_node_1 = deprecated::v1::DelegationNode::::new_root_child( + old_root_id, + alice, + Permissions::DELEGATE, + ); + let old_node_id_2 = mock::get_delegation_id_2(true); + let old_node_2 = + deprecated::v1::DelegationNode::::new_root_child(old_root_id, bob, Permissions::ATTEST); + deprecated::v1::storage::Roots::insert(old_root_id, old_root_node.clone()); + deprecated::v1::storage::Delegations::insert(old_node_id_1, old_node_1.clone()); + deprecated::v1::storage::Delegations::insert(old_node_id_2, old_node_2.clone()); + deprecated::v1::storage::Children::::insert(old_root_id, vec![old_node_id_1, old_node_id_2]); + + #[cfg(feature = "try-runtime")] + assert!( + pre_migrate::().is_ok(), + "Pre-migration for v1 should not fail." + ); + + migrate::(); + + #[cfg(feature = "try-runtime")] + assert!( + post_migrate::().is_ok(), + "Post-migration for v1 should not fail." + ); + + assert_eq!(deprecated::v1::storage::Roots::::iter_values().count(), 0); + assert_eq!( + deprecated::v1::storage::Delegations::::iter_values().count(), + 0 + ); + assert_eq!( + deprecated::v1::storage::Children::::iter_values().count(), + 0 + ); + + let new_stored_hierarchy = DelegationHierarchies::::get(old_root_id) + .expect("New delegation hierarchy should exist in the storage."); + assert_eq!(new_stored_hierarchy.ctype_hash, old_root_node.ctype_hash); + let new_stored_root = DelegationNodes::::get(old_root_id) + .expect("New delegation root should exist in the storage."); + assert_eq!(new_stored_root.hierarchy_root_id, old_root_id); + assert!(new_stored_root.parent.is_none()); + assert_eq!(new_stored_root.children.len(), 2); + assert!(new_stored_root.children.contains(&old_node_id_1)); + assert!(new_stored_root.children.contains(&old_node_id_2)); + assert_eq!(new_stored_root.details.owner, old_root_node.owner); + assert_eq!(new_stored_root.details.revoked, old_root_node.revoked); + + let new_stored_node_1 = DelegationNodes::::get(old_node_id_1) + .expect("New delegation 1 should exist in the storage."); + assert_eq!(new_stored_node_1.hierarchy_root_id, old_root_id); + assert_eq!(new_stored_node_1.parent, Some(old_root_id)); + assert!(new_stored_node_1.children.is_empty()); + assert_eq!(new_stored_node_1.details.owner, old_node_1.owner); + assert_eq!(new_stored_node_1.details.revoked, old_node_1.revoked); + + let new_stored_node_2 = DelegationNodes::::get(old_node_id_2) + .expect("New delegation 2 should exist in the storage."); + assert_eq!(new_stored_node_2.hierarchy_root_id, old_root_id); + assert_eq!(new_stored_node_2.parent, Some(old_root_id)); + assert!(new_stored_node_2.children.is_empty()); + assert_eq!(new_stored_node_2.details.owner, old_node_2.owner); + assert_eq!(new_stored_node_2.details.revoked, old_node_2.revoked); + }); + } + + #[test] + fn ok_three_level_hierarchy() { + let mut ext = mock::ExtBuilder::default() + .with_storage_version(DelegationStorageVersion::V1) + .build(None); + ext.execute_with(|| { + let alice = mock::get_ed25519_account(mock::get_alice_ed25519().public()); + let bob = mock::get_sr25519_account(mock::get_bob_sr25519().public()); + let old_root_id = mock::get_delegation_id(true); + let old_root_node = + deprecated::v1::DelegationRoot::::new(ctype::mock::get_ctype_hash(true), alice.clone()); + let old_parent_id = mock::get_delegation_id(false); + let old_parent_node = + deprecated::v1::DelegationNode::::new_root_child(old_root_id, alice, Permissions::all()); + let old_node_id = mock::get_delegation_id_2(true); + let old_node = deprecated::v1::DelegationNode::::new_node_child( + old_root_id, + old_parent_id, + bob, + Permissions::ATTEST, + ); + deprecated::v1::storage::Roots::insert(old_root_id, old_root_node.clone()); + deprecated::v1::storage::Delegations::insert(old_parent_id, old_parent_node.clone()); + deprecated::v1::storage::Delegations::insert(old_node_id, old_node.clone()); + deprecated::v1::storage::Children::::insert(old_root_id, vec![old_parent_id]); + deprecated::v1::storage::Children::::insert(old_parent_id, vec![old_node_id]); + + #[cfg(feature = "try-runtime")] + assert!( + pre_migrate::().is_ok(), + "Pre-migration for v1 should not fail." + ); + + migrate::(); + + #[cfg(feature = "try-runtime")] + assert!( + post_migrate::().is_ok(), + "Post-migration for v1 should not fail." + ); + + assert_eq!(deprecated::v1::storage::Roots::::iter_values().count(), 0); + assert_eq!( + deprecated::v1::storage::Delegations::::iter_values().count(), + 0 + ); + assert_eq!( + deprecated::v1::storage::Children::::iter_values().count(), + 0 + ); + + let new_stored_hierarchy = DelegationHierarchies::::get(old_root_id) + .expect("New delegation hierarchy should exist in the storage."); + assert_eq!(new_stored_hierarchy.ctype_hash, old_root_node.ctype_hash); + let new_stored_root = DelegationNodes::::get(old_root_id) + .expect("New delegation root should exist in the storage."); + assert_eq!(new_stored_root.hierarchy_root_id, old_root_id); + assert!(new_stored_root.parent.is_none()); + assert_eq!(new_stored_root.children.len(), 1); + assert!(new_stored_root.children.contains(&old_parent_id)); + assert_eq!(new_stored_root.details.owner, old_root_node.owner); + assert_eq!(new_stored_root.details.revoked, old_root_node.revoked); + + let new_stored_parent = DelegationNodes::::get(old_parent_id) + .expect("New delegation parent should exist in the storage."); + assert_eq!(new_stored_parent.hierarchy_root_id, old_root_id); + assert_eq!(new_stored_parent.parent, Some(old_root_id)); + assert_eq!(new_stored_parent.children.len(), 1); + assert!(new_stored_parent.children.contains(&old_node_id)); + assert_eq!(new_stored_parent.details.owner, old_parent_node.owner); + assert_eq!(new_stored_parent.details.revoked, old_parent_node.revoked); + + let new_stored_node = DelegationNodes::::get(old_node_id) + .expect("New delegation node should exist in the storage."); + assert_eq!(new_stored_node.hierarchy_root_id, old_root_id); + assert_eq!(new_stored_node.parent, Some(old_parent_id)); + assert!(new_stored_node.children.is_empty()); + assert_eq!(new_stored_node.details.owner, old_node.owner); + assert_eq!(new_stored_node.details.revoked, old_node.revoked); + }); + } +} diff --git a/pallets/delegation/src/mock.rs b/pallets/delegation/src/mock.rs index 36410c3d56..4c8b77baf9 100644 --- a/pallets/delegation/src/mock.rs +++ b/pallets/delegation/src/mock.rs @@ -28,7 +28,7 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, MultiSignature, MultiSigner, }; -use sp_std::sync::Arc; +use sp_std::{collections::btree_set::BTreeSet, sync::Arc}; #[cfg(test)] use codec::Encode; @@ -143,12 +143,12 @@ const ALICE_SEED: [u8; 32] = [0u8; 32]; const BOB_SEED: [u8; 32] = [1u8; 32]; const CHARLIE_SEED: [u8; 32] = [2u8; 32]; -const DEFAULT_ROOT_ID_SEED: u64 = 1u64; -const ALTERNATIVE_ROOT_ID_SEED: u64 = 2u64; +const DEFAULT_HIERARCHY_ID_SEED: u64 = 1u64; +const ALTERNATIVE_HIERARCHY_ID_SEED: u64 = 2u64; const DEFAULT_DELEGATION_ID_SEED: u64 = 3u64; const ALTERNATIVE_DELEGATION_ID_SEED: u64 = 4u64; -const DEFAULT_DELEGATION_ID_2_SEED: u64 = 3u64; -const ALTERNATIVE_DELEGATION_ID_2_SEED: u64 = 4u64; +const DEFAULT_DELEGATION_ID_2_SEED: u64 = 5u64; +const ALTERNATIVE_DELEGATION_ID_2_SEED: u64 = 6u64; pub fn get_origin(account: TestDelegatorId) -> Origin { Origin::signed(account) @@ -186,27 +186,27 @@ pub fn get_charlie_sr25519() -> sr25519::Pair { sr25519::Pair::from_seed(&CHARLIE_SEED) } -pub fn get_delegation_root_id(default: bool) -> TestDelegationNodeId { +pub fn get_delegation_hierarchy_id(default: bool) -> TestDelegationNodeId { if default { - TestCtypeHash::from_low_u64_be(DEFAULT_ROOT_ID_SEED) + TestDelegationNodeId::from_low_u64_be(DEFAULT_HIERARCHY_ID_SEED) } else { - TestCtypeHash::from_low_u64_be(ALTERNATIVE_ROOT_ID_SEED) + TestDelegationNodeId::from_low_u64_be(ALTERNATIVE_HIERARCHY_ID_SEED) } } pub fn get_delegation_id(default: bool) -> TestDelegationNodeId { if default { - TestCtypeHash::from_low_u64_be(DEFAULT_DELEGATION_ID_SEED) + TestDelegationNodeId::from_low_u64_be(DEFAULT_DELEGATION_ID_SEED) } else { - TestCtypeHash::from_low_u64_be(ALTERNATIVE_DELEGATION_ID_SEED) + TestDelegationNodeId::from_low_u64_be(ALTERNATIVE_DELEGATION_ID_SEED) } } pub fn get_delegation_id_2(default: bool) -> TestDelegationNodeId { if default { - TestCtypeHash::from_low_u64_be(DEFAULT_DELEGATION_ID_2_SEED) + TestDelegationNodeId::from_low_u64_be(DEFAULT_DELEGATION_ID_2_SEED) } else { - TestCtypeHash::from_low_u64_be(ALTERNATIVE_DELEGATION_ID_2_SEED) + TestDelegationNodeId::from_low_u64_be(ALTERNATIVE_DELEGATION_ID_2_SEED) } } @@ -215,116 +215,133 @@ pub(crate) fn hash_to_u8(hash: T) -> Vec { hash.encode() } -pub struct DelegationRootCreationDetails { - pub root_id: TestDelegationNodeId, +pub fn generate_base_delegation_hierarchy_details() -> DelegationHierarchyDetails { + DelegationHierarchyDetails { + ctype_hash: ctype_mock::get_ctype_hash(true), + } +} + +pub fn generate_base_delegation_node( + hierarchy_id: TestDelegationNodeId, + owner: TestDelegatorId, + parent: Option, +) -> DelegationNode { + DelegationNode { + details: generate_base_delegation_details(owner), + children: BTreeSet::new(), + hierarchy_root_id: hierarchy_id, + parent, + } +} + +pub fn generate_base_delegation_details(owner: TestDelegatorId) -> DelegationDetails { + DelegationDetails { + owner, + permissions: Permissions::DELEGATE, + revoked: false, + } +} + +pub struct DelegationHierarchyCreationOperation { + pub id: TestDelegationNodeId, pub ctype_hash: TestCtypeHash, } -pub fn generate_base_delegation_root_creation_details( - root_id: TestDelegationNodeId, - root_node: DelegationRoot, -) -> DelegationRootCreationDetails { - DelegationRootCreationDetails { - ctype_hash: root_node.ctype_hash, - root_id, +pub fn generate_base_delegation_hierarchy_creation_operation( + id: TestDelegationNodeId, +) -> DelegationHierarchyCreationOperation { + DelegationHierarchyCreationOperation { + id, + ctype_hash: ctype::mock::get_ctype_hash(true), } } -pub struct DelegationCreationDetails { +pub struct DelegationCreationOperation { pub delegation_id: TestDelegationNodeId, - pub root_id: TestDelegationNodeId, - pub parent_id: Option, + pub hierarchy_id: TestDelegationNodeId, + pub parent_id: TestDelegationNodeId, pub delegate: TestDelegatorId, pub permissions: Permissions, pub delegate_signature: TestDelegateSignature, } -pub fn generate_base_delegation_creation_details( +pub fn generate_base_delegation_creation_operation( delegation_id: TestDelegationNodeId, delegate_signature: TestDelegateSignature, delegation_node: DelegationNode, -) -> DelegationCreationDetails { - DelegationCreationDetails { +) -> DelegationCreationOperation { + DelegationCreationOperation { delegation_id, - parent_id: delegation_node.parent, - root_id: delegation_node.root_id, - delegate: delegation_node.owner, + parent_id: delegation_node + .parent + .expect("Delegation node must specify a parent ID upon creation"), + hierarchy_id: delegation_node.hierarchy_root_id, + delegate: delegation_node.details.owner, delegate_signature, - permissions: delegation_node.permissions, + permissions: delegation_node.details.permissions, } } -pub struct DelegationRootRevocationDetails { - pub root_id: TestDelegationNodeId, +pub struct DelegationHierarchyRevocationOperation { + pub id: TestDelegationNodeId, pub max_children: u32, } -pub fn generate_base_delegation_root_revocation_details( - root_id: TestDelegationNodeId, -) -> DelegationRootRevocationDetails { - DelegationRootRevocationDetails { - root_id, - max_children: 0u32, - } +pub fn generate_base_delegation_hierarchy_revocation_operation( + id: TestDelegationNodeId, +) -> DelegationHierarchyRevocationOperation { + DelegationHierarchyRevocationOperation { id, max_children: 0u32 } } -pub struct DelegationRevocationDetails { +pub struct DelegationRevocationOperation { pub delegation_id: TestDelegationNodeId, pub max_parent_checks: u32, pub max_revocations: u32, } -pub fn generate_base_delegation_revocation_details(delegation_id: TestDelegationNodeId) -> DelegationRevocationDetails { - DelegationRevocationDetails { +pub fn generate_base_delegation_revocation_operation( + delegation_id: TestDelegationNodeId, +) -> DelegationRevocationOperation { + DelegationRevocationOperation { delegation_id, max_parent_checks: 0u32, max_revocations: 0u32, } } -pub fn generate_base_delegation_root(owner: TestDelegatorId) -> DelegationRoot { - DelegationRoot { - owner, - ctype_hash: ctype_mock::get_ctype_hash(true), - revoked: false, - } -} - -pub fn generate_base_delegation_node(root_id: TestDelegationNodeId, owner: TestDelegatorId) -> DelegationNode { - DelegationNode { - owner, - parent: None, - root_id, - permissions: Permissions::DELEGATE, - revoked: false, - } -} - #[derive(Clone)] pub struct ExtBuilder { ctype_builder: Option, - root_delegations_stored: Vec<(TestDelegationNodeId, DelegationRoot)>, + delegation_hierarchies_stored: Vec<( + TestDelegationNodeId, + DelegationHierarchyDetails, + DelegatorIdOf, + )>, delegations_stored: Vec<(TestDelegationNodeId, DelegationNode)>, - children_stored: Vec<(TestDelegationNodeId, Vec)>, + storage_version: DelegationStorageVersion, } impl Default for ExtBuilder { fn default() -> Self { Self { ctype_builder: None, - root_delegations_stored: vec![], + delegation_hierarchies_stored: vec![], delegations_stored: vec![], - children_stored: vec![], + storage_version: DelegationStorageVersion::default(), } } } impl ExtBuilder { - pub fn with_root_delegations( + pub fn with_delegation_hierarchies( mut self, - root_delegations: Vec<(TestDelegationNodeId, DelegationRoot)>, + delegation_hierarchies: Vec<( + TestDelegationNodeId, + DelegationHierarchyDetails, + DelegatorIdOf, + )>, ) -> Self { - self.root_delegations_stored = root_delegations; + self.delegation_hierarchies_stored = delegation_hierarchies; self } @@ -333,8 +350,8 @@ impl ExtBuilder { self } - pub fn with_children(mut self, children: Vec<(TestDelegationNodeId, Vec)>) -> Self { - self.children_stored = children; + pub fn with_storage_version(mut self, storage_version: DelegationStorageVersion) -> Self { + self.storage_version = storage_version; self } @@ -346,29 +363,41 @@ impl ExtBuilder { sp_io::TestExternalities::new(storage) }; - if !self.root_delegations_stored.is_empty() { + if !self.delegation_hierarchies_stored.is_empty() { ext.execute_with(|| { - self.root_delegations_stored.iter().for_each(|root_delegation| { - delegation::Roots::::insert(root_delegation.0, root_delegation.1.clone()); - }) + self.delegation_hierarchies_stored + .iter() + .for_each(|delegation_hierarchy| { + delegation::Pallet::create_and_store_new_hierarchy( + delegation_hierarchy.0, + delegation_hierarchy.1.clone(), + delegation_hierarchy.2.clone(), + ); + }) }); } if !self.delegations_stored.is_empty() { ext.execute_with(|| { self.delegations_stored.iter().for_each(|del| { - delegation::Delegations::::insert(del.0, del.1.clone()); + let parent_node_id = del + .1 + .parent + .expect("Delegation node that is not a root must have a parent ID specified."); + let parent_node = delegation::DelegationNodes::::get(&parent_node_id).unwrap(); + delegation::Pallet::store_delegation_under_parent( + del.0, + del.1.clone(), + parent_node_id, + parent_node, + ); }) }); } - if !self.children_stored.is_empty() { - ext.execute_with(|| { - self.children_stored.iter().for_each(|child| { - delegation::Children::::insert(child.0, child.1.clone()); - }) - }); - } + ext.execute_with(|| { + delegation::StorageVersion::::set(self.storage_version); + }); ext } diff --git a/pallets/delegation/src/tests.rs b/pallets/delegation/src/tests.rs index 9fd63a451e..3a618352e5 100644 --- a/pallets/delegation/src/tests.rs +++ b/pallets/delegation/src/tests.rs @@ -30,31 +30,37 @@ fn create_root_delegation_successful() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), - ); + let hierarchy_root_id = get_delegation_hierarchy_id(true); - let operation = generate_base_delegation_root_creation_details(root_id, root_node.clone()); + let operation = generate_base_delegation_hierarchy_creation_operation(hierarchy_root_id); let mut ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(operation.ctype_hash, creator.clone())]) .build(None); ext.execute_with(|| { - assert_ok!(Delegation::create_root( + assert_ok!(Delegation::create_hierarchy( get_origin(creator.clone()), - operation.root_id, + operation.id, operation.ctype_hash )); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); + let stored_hierarchy_details = ext.execute_with(|| { + Delegation::delegation_hierarchies(&hierarchy_root_id) + .expect("Delegation hierarchy should be present on chain.") + }); + assert_eq!(stored_hierarchy_details.ctype_hash, operation.ctype_hash); - assert_eq!(stored_delegation_root.owner, creator); - assert_eq!(stored_delegation_root.ctype_hash, operation.ctype_hash); - assert!(!stored_delegation_root.revoked); + let stored_delegation_root = ext.execute_with(|| { + Delegation::delegation_nodes(&hierarchy_root_id).expect("Delegation root should be present on chain.") + }); + + assert_eq!(stored_delegation_root.hierarchy_root_id, hierarchy_root_id); + assert_eq!(stored_delegation_root.parent, None); + assert_eq!(stored_delegation_root.children.len(), 0); + assert_eq!(stored_delegation_root.details.owner, creator); + assert!(!stored_delegation_root.details.revoked); } #[test] @@ -62,24 +68,24 @@ fn duplicate_create_root_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let operation = generate_base_delegation_root_creation_details(root_id, root_node.clone()); + let operation = generate_base_delegation_hierarchy_creation_operation(hierarchy_root_id); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(operation.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) .build(Some(ext)); ext.execute_with(|| { - assert_err!( - Delegation::create_root(get_origin(creator.clone()), operation.root_id, operation.ctype_hash), - delegation::Error::::RootAlreadyExists + assert_noop!( + Delegation::create_hierarchy(get_origin(creator.clone()), operation.id, operation.ctype_hash), + delegation::Error::::HierarchyAlreadyExists ); }); } @@ -89,19 +95,16 @@ fn ctype_not_found_create_root_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), - ); + let hierarchy_root_id = get_delegation_hierarchy_id(true); - let operation = generate_base_delegation_root_creation_details(root_id, root_node); + let operation = generate_base_delegation_hierarchy_creation_operation(hierarchy_root_id); // No CType stored, let mut ext = ExtBuilder::default().build(None); ext.execute_with(|| { - assert_err!( - Delegation::create_root(get_origin(creator.clone()), operation.root_id, operation.ctype_hash), + assert_noop!( + Delegation::create_hierarchy(get_origin(creator.clone()), operation.id, operation.ctype_hash), ctype::Error::::CTypeNotFound ); }); @@ -110,45 +113,44 @@ fn ctype_not_found_create_root_delegation_error() { // submit_delegation_creation_operation() #[test] -fn create_delegation_no_parent_successful() { +fn create_delegation_direct_root_successful() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); let (delegation_id, delegation_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(hierarchy_root_id)), ); - let delegation_info = Delegation::calculate_hash( + let delegation_info = Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &hierarchy_root_id, + &delegation_node.details.permissions, ); let delegate_signature = delegate_keypair.sign(&hash_to_u8(delegation_info)); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) .build(Some(ext)); ext.execute_with(|| { assert_ok!(Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, operation.delegate.clone(), operation.permissions, @@ -157,21 +159,22 @@ fn create_delegation_no_parent_successful() { }); let stored_delegation = ext.execute_with(|| { - Delegation::delegations(&operation.delegation_id).expect("Delegation should be present on chain.") + Delegation::delegation_nodes(&operation.delegation_id).expect("Delegation should be present on chain.") }); - assert_eq!(stored_delegation.root_id, operation.root_id); - assert_eq!(stored_delegation.parent, operation.parent_id); - assert_eq!(stored_delegation.owner, operation.delegate); - assert_eq!(stored_delegation.permissions, operation.permissions); - assert!(!stored_delegation.revoked); + assert_eq!(stored_delegation.hierarchy_root_id, operation.hierarchy_id); + assert_eq!(stored_delegation.parent, Some(operation.parent_id)); + assert!(stored_delegation.children.is_empty()); + assert_eq!(stored_delegation.details.owner, operation.delegate); + assert_eq!(stored_delegation.details.permissions, operation.permissions); + assert!(!stored_delegation.details.revoked); // Verify that the root has the new delegation among its children - let stored_root_children = ext.execute_with(|| { - Delegation::children(&operation.root_id).expect("Delegation root children should be present on chain.") + let stored_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.hierarchy_id).expect("Delegation root should be present on chain.") }); - assert_eq!(stored_root_children, vec![operation.delegation_id]); + assert!(stored_root.children.contains(&operation.delegation_id)); } #[test] @@ -181,418 +184,423 @@ fn create_delegation_with_parent_successful() { let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, creator.clone()), + generate_base_delegation_node(hierarchy_root_id, creator.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegation_info = Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, - ))); + &hierarchy_root_id, + &parent_id, + &delegation_node.details.permissions, + ); + + let delegate_signature = delegate_keypair.sign(&hash_to_u8(delegation_info)); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![(parent_delegation_id, parent_delegation_node)]) - .with_children(vec![(root_id, vec![(parent_delegation_id)])]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .with_delegations(vec![(parent_id, parent_node)]) .build(Some(ext)); ext.execute_with(|| { assert_ok!(Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, - delegate.clone(), + operation.delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), )); }); let stored_delegation = ext.execute_with(|| { - Delegation::delegations(&operation.delegation_id).expect("Delegation should be present on chain.") + Delegation::delegation_nodes(&operation.delegation_id).expect("Delegation should be present on chain.") }); - assert_eq!(stored_delegation.root_id, operation.root_id); - assert_eq!(stored_delegation.parent, operation.parent_id); - assert_eq!(stored_delegation.owner, operation.delegate); - assert_eq!(stored_delegation.permissions, operation.permissions); - assert!(!stored_delegation.revoked); + assert_eq!(stored_delegation.hierarchy_root_id, operation.hierarchy_id); + assert_eq!(stored_delegation.parent, Some(operation.parent_id)); + assert!(stored_delegation.children.is_empty()); + assert_eq!(stored_delegation.details.owner, operation.delegate); + assert_eq!(stored_delegation.details.permissions, operation.permissions); + assert!(!stored_delegation.details.revoked); // Verify that the parent has the new delegation among its children - let stored_parent_children = ext.execute_with(|| { - Delegation::children(&operation.parent_id.unwrap()) - .expect("Delegation parent children should be present on chain.") + let stored_parent = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.parent_id).expect("Delegation parent should be present on chain.") }); - assert_eq!(stored_parent_children, vec![delegation_id]); + assert!(stored_parent.children.contains(&operation.delegation_id)); } #[test] -fn invalid_delegate_signature_create_delegation_error() { +fn create_delegation_direct_root_revoked_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let alternative_keypair = get_alice_sr25519(); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); let (delegation_id, delegation_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(hierarchy_root_id)), ); - let delegate_signature = alternative_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegation_info = Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, - ))); + &hierarchy_root_id, + &hierarchy_root_id, + &delegation_node.details.permissions, + ); + + let delegate_signature = delegate_keypair.sign(&hash_to_u8(delegation_info)); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) .build(Some(ext)); ext.execute_with(|| { - assert_err!( + let _ = Delegation::revoke_delegation( + get_origin(creator.clone()), + operation.hierarchy_id, + 0u32, + MaxRevocations::get(), + ); + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, - delegate.clone(), + delegate, operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::InvalidDelegateSignature + delegation::Error::::ParentDelegationRevoked ); }); } #[test] -fn duplicate_delegation_create_delegation_error() { +fn create_delegation_with_parent_revoked_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (delegation_id, delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, creator.clone(), Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(parent_id)), ); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegation_info = Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, - ))); + &hierarchy_root_id, + &parent_id, + &delegation_node.details.permissions, + ); + + let delegate_signature = delegate_keypair.sign(&hash_to_u8(delegation_info)); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node.clone()); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .with_delegations(vec![(parent_id, parent_node)]) .build(Some(ext)); ext.execute_with(|| { - assert_err!( + let _ = Delegation::revoke_delegation( + get_origin(creator.clone()), + operation.parent_id, + MaxRevocations::get(), + MaxParentChecks::get(), + ); + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, - delegate.clone(), + delegate, operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::DelegationAlreadyExists + delegation::Error::::ParentDelegationRevoked ); }); } #[test] -fn root_not_existing_create_delegation_error() { +fn invalid_delegate_signature_create_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); + let alternative_keypair = get_alice_sr25519(); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); let (delegation_id, delegation_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(hierarchy_root_id)), ); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegate_signature = alternative_keypair.sign(&hash_to_u8(Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &hierarchy_root_id, + &delegation_node.details.permissions, ))); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); - // No delegations added to the pallet storage - let mut ext = ExtBuilder::default().build(Some(ext)); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .build(Some(ext)); ext.execute_with(|| { - assert_err!( + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::RootNotFound + delegation::Error::::InvalidDelegateSignature ); }); } #[test] -fn parent_not_existing_create_delegation_error() { +fn duplicate_delegation_create_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let alternative_parent_id = get_delegation_id(false); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(hierarchy_root_id)), ); - delegation_node.parent = Some(alternative_parent_id); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &hierarchy_root_id, + &delegation_node.details.permissions, ))); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node.clone()); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .with_delegations(vec![(delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { - assert_err!( + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::ParentDelegationNotFound + delegation::Error::::DelegationAlreadyExists ); }); } #[test] -fn not_owner_of_parent_create_delegation_error() { +fn parent_not_existing_create_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let alternative_owner_keypair = get_charlie_ed25519(); - let alternative_owner = get_ed25519_account(alternative_owner_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, alternative_owner), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( - get_delegation_id(false), - generate_base_delegation_node(root_id, delegate.clone()), - ); - delegation_node.parent = Some(parent_delegation_id); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &hierarchy_root_id, + &delegation_node.details.permissions, ))); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![(parent_delegation_id, parent_delegation_node)]) - .with_children(vec![(root_id, vec![parent_delegation_id])]) - .build(Some(ext)); + // No delegations added to the pallet storage + let mut ext = ExtBuilder::default().build(Some(ext)); ext.execute_with(|| { - assert_err!( + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::NotOwnerOfParentDelegation + delegation::Error::::ParentDelegationNotFound ); }); } #[test] -fn unauthorised_delegation_create_delegation_error() { +fn not_owner_of_parent_create_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); + let alternative_owner_keypair = get_charlie_ed25519(); + let alternative_owner = get_ed25519_account(alternative_owner_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(creator.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, mut parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, creator.clone()), + generate_base_delegation_node(hierarchy_root_id, alternative_owner, Some(hierarchy_root_id)), ); - parent_delegation_node.permissions = delegation::Permissions::ATTEST; - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &parent_id, + &delegation_node.details.permissions, ))); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![(parent_delegation_id, parent_delegation_node)]) - .with_children(vec![(root_id, vec![parent_delegation_id])]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .with_delegations(vec![(parent_id, parent_node)]) .build(Some(ext)); ext.execute_with(|| { - assert_err!( + assert_noop!( Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::UnauthorizedDelegation + delegation::Error::::NotOwnerOfParentDelegation ); }); } #[test] -fn not_owner_of_root_create_delegation_error() { +fn unauthorised_delegation_create_delegation_error() { let creator_keypair = get_alice_ed25519(); let creator = get_ed25519_account(creator_keypair.public()); - let alternative_owner_keypair = get_charlie_ed25519(); - let alternative_owner = get_ed25519_account(alternative_owner_keypair.public()); let delegate_keypair = get_bob_sr25519(); let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(alternative_owner), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (delegation_id, delegation_node) = ( + let (parent_id, mut parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, creator.clone(), Some(hierarchy_root_id)), + ); + parent_node.details.permissions = delegation::Permissions::ATTEST; + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(parent_id)), ); - let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_hash( + let delegate_signature = delegate_keypair.sign(&hash_to_u8(Delegation::calculate_delegation_creation_hash( &delegation_id, - &delegation_node.root_id, - &delegation_node.parent, - &delegation_node.permissions, + &hierarchy_root_id, + &parent_id, + &delegation_node.details.permissions, ))); let operation = - generate_base_delegation_creation_details(delegation_id, delegate_signature.into(), delegation_node); + generate_base_delegation_creation_operation(delegation_id, delegate_signature.into(), delegation_node); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, creator.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, creator.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, creator.clone())]) + .with_delegations(vec![(parent_id, parent_node)]) .build(Some(ext)); ext.execute_with(|| { @@ -600,218 +608,220 @@ fn not_owner_of_root_create_delegation_error() { Delegation::add_delegation( get_origin(creator.clone()), operation.delegation_id, - operation.root_id, operation.parent_id, delegate.clone(), operation.permissions, operation.delegate_signature.clone().encode(), ), - delegation::Error::::NotOwnerOfRootDelegation + delegation::Error::::UnauthorizedDelegation ); }); } // submit_delegation_root_revocation_operation() + #[test] fn empty_revoke_root_successful() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let mut operation = generate_base_delegation_root_revocation_details(root_id); - operation.max_children = 2u32; + let operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .build(Some(ext)); ext.execute_with(|| { - assert_ok!(Delegation::revoke_root( + assert_ok!(Delegation::revoke_delegation( get_origin(revoker.clone()), - operation.root_id, + operation.id, + 0u32, operation.max_children )); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); - assert!(stored_delegation_root.revoked); + let stored_delegation_hierarchy_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.id).expect("Delegation root should be present on chain.") + }); + + assert!(stored_delegation_hierarchy_root.details.revoked); } #[test] fn list_hierarchy_revoke_root_successful() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let delegate_keypair = get_bob_ed25519(); - let delegate = get_ed25519_account(delegate_keypair.public()); + let delegate_keypair = get_bob_sr25519(); + let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, revoker.clone()), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let mut operation = generate_base_delegation_root_revocation_details(root_id); + let mut operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); operation.max_children = 2u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - // Root -> Parent -> Delegation - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { - assert_ok!(Delegation::revoke_root( + assert_ok!(Delegation::revoke_delegation( get_origin(revoker.clone()), - operation.root_id, + operation.id, + 0u32, operation.max_children )); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); - assert!(stored_delegation_root.revoked); + let stored_delegation_hierarchy_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.id).expect("Delegation root should be present on chain.") + }); + assert!(stored_delegation_hierarchy_root.details.revoked); let stored_parent_delegation = ext.execute_with(|| { - Delegation::delegations(&parent_delegation_id).expect("Parent delegation should be present on chain.") + Delegation::delegation_nodes(&parent_id).expect("Parent delegation should be present on chain.") }); - assert!(stored_parent_delegation.revoked); + assert!(stored_parent_delegation.details.revoked); - let stored_delegation = - ext.execute_with(|| Delegation::delegations(&delegation_id).expect("Delegation should be present on chain.")); - assert!(stored_delegation.revoked); + let stored_delegation = ext + .execute_with(|| Delegation::delegation_nodes(&delegation_id).expect("Delegation should be present on chain.")); + assert!(stored_delegation.details.revoked); } #[test] fn tree_hierarchy_revoke_root_successful() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let delegate_keypair = get_bob_ed25519(); - let delegate = get_ed25519_account(delegate_keypair.public()); + let delegate_keypair = get_bob_sr25519(); + let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (delegation_id_1, delegation_node_1) = ( + let (delegation1_id, delegation1_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, revoker.clone()), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - let (delegation_id_2, delegation_node_2) = ( + let (delegation2_id, delegation2_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(hierarchy_root_id)), ); - let mut operation = generate_base_delegation_root_revocation_details(root_id); + let mut operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); operation.max_children = 2u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - // Root -> Delegation 1 && Delegation 2 - (root_id, vec![delegation_id_1, delegation_id_2]), + (delegation1_id, delegation1_node), + (delegation2_id, delegation2_node), ]) .build(Some(ext)); ext.execute_with(|| { - assert_ok!(Delegation::revoke_root( + assert_ok!(Delegation::revoke_delegation( get_origin(revoker.clone()), - operation.root_id, + operation.id, + 0u32, operation.max_children )); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); - assert!(stored_delegation_root.revoked); + let stored_delegation_hierarchy_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.id).expect("Delegation root should be present on chain.") + }); + assert!(stored_delegation_hierarchy_root.details.revoked); - let stored_delegation_1 = ext - .execute_with(|| Delegation::delegations(&delegation_id_1).expect("Delegation 1 should be present on chain.")); - assert!(stored_delegation_1.revoked); + let stored_delegation_1 = ext.execute_with(|| { + Delegation::delegation_nodes(&delegation1_id).expect("Delegation 1 should be present on chain.") + }); + assert!(stored_delegation_1.details.revoked); - let stored_delegation_2 = ext - .execute_with(|| Delegation::delegations(&delegation_id_2).expect("Delegation 2 should be present on chain.")); - assert!(stored_delegation_2.revoked); + let stored_delegation_2 = ext.execute_with(|| { + Delegation::delegation_nodes(&delegation2_id).expect("Delegation 2 should be present on chain.") + }); + assert!(stored_delegation_2.details.revoked); } #[test] -fn greater_max_revocations_revoke_root_successful() { +fn max_max_revocations_revoke_successful() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let delegate_keypair = get_alice_ed25519(); - let delegate = get_ed25519_account(delegate_keypair.public()); + let delegate_keypair = get_bob_sr25519(); + let delegate = get_sr25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - let mut operation = generate_base_delegation_root_revocation_details(root_id); + let mut operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); operation.max_children = MaxRevocations::get(); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![ - // Root -> Delegation - (root_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { - assert_ok!(Delegation::revoke_root( + assert_ok!(Delegation::revoke_delegation( get_origin(revoker.clone()), - operation.root_id, + operation.id, + 0u32, operation.max_children )); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); - assert!(stored_delegation_root.revoked); + let stored_delegation_hierarchy_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.id).expect("Delegation root should be present on chain.") + }); + assert!(stored_delegation_hierarchy_root.details.revoked); + + let stored_parent_delegation = ext.execute_with(|| { + Delegation::delegation_nodes(&parent_id).expect("Parent delegation should be present on chain.") + }); + assert!(stored_parent_delegation.details.revoked); - let stored_delegation = - ext.execute_with(|| Delegation::delegations(&delegation_id).expect("Delegation should be present on chain.")); - assert!(stored_delegation.revoked); + let stored_delegation = ext + .execute_with(|| Delegation::delegation_nodes(&delegation_id).expect("Delegation should be present on chain.")); + assert!(stored_delegation.details.revoked); } #[test] @@ -819,16 +829,16 @@ fn root_not_found_revoke_root_error() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let root_id = get_delegation_root_id(true); + let hierarchy_root_id = get_delegation_hierarchy_id(true); - let operation = generate_base_delegation_root_revocation_details(root_id); + let operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); let mut ext = ExtBuilder::default().build(None); ext.execute_with(|| { assert_noop!( - Delegation::revoke_root(get_origin(revoker.clone()), operation.root_id, operation.max_children), - delegation::Error::::RootNotFound + Delegation::revoke_delegation(get_origin(revoker.clone()), operation.id, 0u32, operation.max_children), + delegation::Error::::DelegationNotFound ); }); } @@ -840,23 +850,23 @@ fn different_root_creator_revoke_root_error() { let alternative_revoker_keypair = get_charlie_ed25519(); let alternative_revoker = get_ed25519_account(alternative_revoker_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(alternative_revoker), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let operation = generate_base_delegation_root_revocation_details(root_id); + let operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, alternative_revoker)]) .build(Some(ext)); ext.execute_with(|| { assert_noop!( - Delegation::revoke_root(get_origin(revoker.clone()), operation.root_id, operation.max_children), + Delegation::revoke_delegation(get_origin(revoker.clone()), operation.id, 0u32, operation.max_children), delegation::Error::::UnauthorizedRevocation ); }); @@ -869,33 +879,29 @@ fn too_small_max_revocations_revoke_root_error() { let delegate_keypair = get_alice_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(hierarchy_root_id)), ); - let mut operation = generate_base_delegation_root_revocation_details(root_id); + let mut operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); operation.max_children = 0u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![ - // Root -> Delegation - (root_id, vec![delegation_id]), - ]) .build(Some(ext)); ext.execute_with(|| { assert_noop!( - Delegation::revoke_root(get_origin(revoker.clone()), operation.root_id, operation.max_children), + Delegation::revoke_delegation(get_origin(revoker.clone()), operation.id, 0u32, operation.max_children), delegation::Error::::ExceededRevocationBounds ); }); @@ -908,42 +914,35 @@ fn exact_children_max_revocations_revoke_root_error() { let delegate_keypair = get_alice_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (delegation_id_1, delegation_node_1) = ( + let (delegation1_id, delegation1_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(hierarchy_root_id)), ); - let (delegation_id_2, mut delegation_node_2) = ( + let (delegation2_id, delegation2_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate.clone()), + generate_base_delegation_node(hierarchy_root_id, delegate.clone(), Some(delegation1_id)), ); - delegation_node_2.parent = Some(delegation_id_1); - let (delegation_id_3, mut delegation_node_3) = ( - get_delegation_root_id(false), - generate_base_delegation_node(root_id, delegate), + let (delegation3_id, delegation3_node) = ( + get_delegation_id_2(true), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(delegation1_id)), ); - delegation_node_3.parent = Some(delegation_id_1); - let mut operation = generate_base_delegation_root_revocation_details(root_id); + let mut operation = generate_base_delegation_hierarchy_revocation_operation(hierarchy_root_id); operation.max_children = 2u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - (delegation_id_3, delegation_node_3), - ]) - .with_children(vec![ - // Root -> Delegation 1 -> Delegation 2 && Delegation 3 - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2, delegation_id_3]), + (delegation1_id, delegation1_node), + (delegation2_id, delegation2_node), + (delegation3_id, delegation3_node), ]) .build(Some(ext)); @@ -951,28 +950,32 @@ fn exact_children_max_revocations_revoke_root_error() { // assert_err and not asser_noop becase the storage is indeed changed, even tho // partially assert_err!( - Delegation::revoke_root(get_origin(revoker.clone()), operation.root_id, operation.max_children), + Delegation::revoke_delegation(get_origin(revoker.clone()), operation.id, 0u32, operation.max_children), delegation::Error::::ExceededRevocationBounds ); }); - let stored_delegation_root = ext - .execute_with(|| Delegation::roots(&operation.root_id).expect("Delegation root should be present on chain.")); - assert!(!stored_delegation_root.revoked); + let stored_delegation_root = ext.execute_with(|| { + Delegation::delegation_nodes(&operation.id).expect("Delegation root should be present on chain.") + }); + assert!(!stored_delegation_root.details.revoked); - let stored_delegation_1 = ext - .execute_with(|| Delegation::delegations(&delegation_id_1).expect("Delegation 1 should be present on chain.")); - assert!(!stored_delegation_1.revoked); + let stored_delegation_1 = ext.execute_with(|| { + Delegation::delegation_nodes(&delegation1_id).expect("Delegation 1 should be present on chain.") + }); + assert!(!stored_delegation_1.details.revoked); // Only this leaf should have been revoked as it is the first child of // delegation_1 - let stored_delegation_2 = ext - .execute_with(|| Delegation::delegations(&delegation_id_2).expect("Delegation 2 should be present on chain.")); - assert!(stored_delegation_2.revoked); + let stored_delegation_2 = ext.execute_with(|| { + Delegation::delegation_nodes(&delegation2_id).expect("Delegation 2 should be present on chain.") + }); + assert!(stored_delegation_2.details.revoked); - let stored_delegation_3 = ext - .execute_with(|| Delegation::delegations(&delegation_id_3).expect("Delegation 3 should be present on chain.")); - assert!(!stored_delegation_3.revoked); + let stored_delegation_3 = ext.execute_with(|| { + Delegation::delegation_nodes(&delegation3_id).expect("Delegation 3 should be present on chain.") + }); + assert!(!stored_delegation_3.details.revoked); } // submit_delegation_revocation_operation() @@ -984,37 +987,28 @@ fn direct_owner_revoke_delegation_successful() { let delegate_keypair = get_alice_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, revoker.clone()), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let mut operation = generate_base_delegation_revocation_details(parent_delegation_id); + let mut operation = generate_base_delegation_revocation_operation(parent_id); operation.max_revocations = 2u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); - // Root -> Parent -> Child let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { @@ -1027,14 +1021,14 @@ fn direct_owner_revoke_delegation_successful() { }); let stored_parent_delegation = ext.execute_with(|| { - Delegation::delegations(&parent_delegation_id).expect("Parent delegation should be present on chain.") + Delegation::delegation_nodes(&parent_id).expect("Parent delegation should be present on chain.") }); - assert!(stored_parent_delegation.revoked); + assert!(stored_parent_delegation.details.revoked); let stored_child_delegation = ext.execute_with(|| { - Delegation::delegations(&delegation_id).expect("Child delegation should be present on chain.") + Delegation::delegation_nodes(&delegation_id).expect("Child delegation should be present on chain.") }); - assert!(stored_child_delegation.revoked); + assert!(stored_child_delegation.details.revoked); } #[test] @@ -1044,37 +1038,29 @@ fn parent_owner_revoke_delegation_successful() { let delegate_keypair = get_alice_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, revoker.clone()), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let mut operation = generate_base_delegation_revocation_details(delegation_id); + let mut operation = generate_base_delegation_revocation_operation(delegation_id); operation.max_parent_checks = 1u32; operation.max_revocations = 1u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { @@ -1087,14 +1073,14 @@ fn parent_owner_revoke_delegation_successful() { }); let stored_parent_delegation = ext.execute_with(|| { - Delegation::delegations(&parent_delegation_id).expect("Parent delegation should be present on chain.") + Delegation::delegation_nodes(&parent_id).expect("Parent delegation should be present on chain.") }); - assert!(!stored_parent_delegation.revoked); + assert!(!stored_parent_delegation.details.revoked); let stored_child_delegation = ext.execute_with(|| { - Delegation::delegations(&delegation_id).expect("Child delegation should be present on chain.") + Delegation::delegation_nodes(&delegation_id).expect("Child delegation should be present on chain.") }); - assert!(stored_child_delegation.revoked); + assert!(stored_child_delegation.details.revoked); } #[test] @@ -1102,19 +1088,19 @@ fn delegation_not_found_revoke_delegation_error() { let revoker_keypair = get_alice_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let delegation_id = get_delegation_id(true); + let delegation_id = get_delegation_id(false); - let operation = generate_base_delegation_revocation_details(delegation_id); + let operation = generate_base_delegation_revocation_operation(delegation_id); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) .build(Some(ext)); ext.execute_with(|| { @@ -1137,22 +1123,24 @@ fn not_delegating_revoke_delegation_error() { let revoker_keypair = get_bob_ed25519(); let revoker = get_ed25519_account(revoker_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(owner.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, owner.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, delegation_node) = (get_delegation_id(false), generate_base_delegation_node(root_id, owner)); - let mut operation = generate_base_delegation_revocation_details(delegation_id); + let mut operation = generate_base_delegation_revocation_operation(delegation_id); operation.max_parent_checks = MaxParentChecks::get(); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, owner)]) .with_delegations(vec![(delegation_id, delegation_node)]) - .with_children(vec![(root_id, vec![delegation_id])]) .build(Some(ext)); ext.execute_with(|| { @@ -1177,36 +1165,28 @@ fn parent_too_far_revoke_delegation_error() { let delegate_keypair = get_bob_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(owner.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, intermediate.clone()), + generate_base_delegation_node(hierarchy_root_id, intermediate.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let mut operation = generate_base_delegation_revocation_details(delegation_id); + let mut operation = generate_base_delegation_revocation_operation(delegation_id); operation.max_parent_checks = 0u32; let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, owner)]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, owner.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, owner)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { @@ -1229,36 +1209,27 @@ fn too_many_revocations_revoke_delegation_error() { let delegate_keypair = get_bob_ed25519(); let delegate = get_ed25519_account(delegate_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(revoker.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); - let (parent_delegation_id, parent_delegation_node) = ( + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, revoker.clone()), + generate_base_delegation_node(hierarchy_root_id, revoker.clone(), Some(hierarchy_root_id)), ); - let (delegation_id, mut delegation_node) = ( + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, delegate), + generate_base_delegation_node(hierarchy_root_id, delegate, Some(parent_id)), ); - delegation_node.parent = Some(parent_delegation_id); - let mut operation = generate_base_delegation_revocation_details(delegation_id); - operation.max_parent_checks = 1u32; + let operation = generate_base_delegation_revocation_operation(parent_id); let ext = ctype_mock::ExtBuilder::default() - .with_ctypes(vec![(root_node.ctype_hash, revoker.clone())]) + .with_ctypes(vec![(hierarchy_details.ctype_hash, revoker.clone())]) .build(None); let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (parent_delegation_id, parent_delegation_node), - (delegation_id, delegation_node), - ]) - .with_children(vec![ - (root_id, vec![parent_delegation_id]), - (parent_delegation_id, vec![delegation_id]), - ]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, revoker.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) .build(Some(ext)); ext.execute_with(|| { @@ -1285,33 +1256,33 @@ fn is_delegating_direct_not_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - let (delegation_id_2, mut delegation_node_2) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, user_3.clone()), + generate_base_delegation_node(hierarchy_root_id, user_3.clone(), Some(parent_id)), ); - delegation_node_2.parent = Some(delegation_id_1); let max_parent_checks = 0u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_3, &delegation_id_2, max_parent_checks), + Delegation::is_delegating(&user_3, &delegation_id, max_parent_checks), Ok((true, max_parent_checks)) ); }); @@ -1326,33 +1297,33 @@ fn is_delegating_direct_not_revoked_max_parent_checks_value() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - let (delegation_id_2, mut delegation_node_2) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, user_3.clone()), + generate_base_delegation_node(hierarchy_root_id, user_3.clone(), Some(parent_id)), ); - delegation_node_2.parent = Some(delegation_id_1); let max_parent_checks = u32::MAX; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_3, &delegation_id_2, max_parent_checks), + Delegation::is_delegating(&user_3, &delegation_id, max_parent_checks), Ok((true, 0u32)) ); }); @@ -1367,35 +1338,35 @@ fn is_delegating_direct_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - let (delegation_id_2, mut delegation_node_2) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, mut delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, user_3.clone()), + generate_base_delegation_node(hierarchy_root_id, user_3.clone(), Some(parent_id)), ); - delegation_node_2.parent = Some(delegation_id_1); - delegation_node_2.revoked = true; + delegation_node.details.revoked = true; let max_parent_checks = 0u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_3, &delegation_id_2, max_parent_checks), - Ok((false, max_parent_checks)) + Delegation::is_delegating(&user_3, &delegation_id, max_parent_checks), + Ok((false, 0)) ); }); } @@ -1409,35 +1380,35 @@ fn is_delegating_direct_revoked_max_parent_checks_value() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - let (delegation_id_2, mut delegation_node_2) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, mut delegation_node) = ( get_delegation_id(false), - generate_base_delegation_node(root_id, user_3.clone()), + generate_base_delegation_node(hierarchy_root_id, user_3.clone(), Some(parent_id)), ); - delegation_node_2.parent = Some(delegation_id_1); - delegation_node_2.revoked = true; + delegation_node.details.revoked = true; let max_parent_checks = u32::MAX; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_3, &delegation_id_2, max_parent_checks), - Ok((false, 0u32)) + Delegation::is_delegating(&user_3, &delegation_id, max_parent_checks), + Ok((false, 0)) ); }); } @@ -1451,33 +1422,33 @@ fn is_delegating_max_parent_not_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, delegation_node_1) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, user_2.clone()), + generate_base_delegation_node(hierarchy_root_id, user_2.clone(), Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, user_3, Some(parent_id)), ); - let (delegation_id_2, mut delegation_node_2) = - (get_delegation_id(false), generate_base_delegation_node(root_id, user_3)); - delegation_node_2.parent = Some(delegation_id_1); let max_parent_checks = 1u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_2, &delegation_id_2, max_parent_checks), + Delegation::is_delegating(&user_2, &delegation_id, max_parent_checks), Ok((true, max_parent_checks - 1)) ); }); @@ -1492,34 +1463,34 @@ fn is_delegating_max_parent_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = (get_delegation_root_id(true), generate_base_delegation_root(user_1)); - let (delegation_id_1, mut delegation_node_1) = ( + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, mut parent_node) = ( get_delegation_id(true), - generate_base_delegation_node(root_id, user_2.clone()), + generate_base_delegation_node(hierarchy_root_id, user_2.clone(), Some(hierarchy_root_id)), + ); + parent_node.details.revoked = true; + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, user_3, Some(parent_id)), ); - delegation_node_1.revoked = true; - let (delegation_id_2, mut delegation_node_2) = - (get_delegation_id(false), generate_base_delegation_node(root_id, user_3)); - delegation_node_2.parent = Some(delegation_id_1); let max_parent_checks = 2u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1)]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_2, &delegation_id_2, max_parent_checks), + Delegation::is_delegating(&user_2, &delegation_id, max_parent_checks), Ok((false, max_parent_checks - 2)) ); }); @@ -1534,35 +1505,34 @@ fn is_delegating_root_owner_not_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(user_1.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, user_3, Some(parent_id)), ); - let (delegation_id_1, delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - let (delegation_id_2, mut delegation_node_2) = - (get_delegation_id(false), generate_base_delegation_node(root_id, user_3)); - delegation_node_2.parent = Some(delegation_id_1); let max_parent_checks = 2u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_eq!( - Delegation::is_delegating(&user_1, &delegation_id_2, max_parent_checks), - Ok((true, max_parent_checks - 1)) + Delegation::is_delegating(&user_1, &delegation_id, max_parent_checks), + Ok((true, max_parent_checks - 2)) ); }); } @@ -1576,37 +1546,36 @@ fn is_delegating_root_owner_revoked() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, mut root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(user_1.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, user_3, Some(parent_id)), ); - root_node.revoked = true; - let (delegation_id_1, mut delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - delegation_node_1.revoked = true; - let (delegation_id_2, mut delegation_node_2) = - (get_delegation_id(false), generate_base_delegation_node(root_id, user_3)); - delegation_node_2.parent = Some(delegation_id_1); - let max_parent_checks = u32::MAX; + let max_parent_checks = 2u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { + // First revoke the hierarchy, then test is_delegating. + let _ = Delegation::revoke_delegation(get_origin(user_1.clone()), hierarchy_root_id, 0u32, 2); assert_eq!( - Delegation::is_delegating(&user_1, &delegation_id_2, max_parent_checks), - Ok((false, 1u32)) + Delegation::is_delegating(&user_1, &delegation_id, max_parent_checks), + Ok((false, 0u32)) ); }); } @@ -1616,9 +1585,9 @@ fn is_delegating_delegation_not_found() { let user_1_keypair = get_alice_ed25519(); let user_1 = get_ed25519_account(user_1_keypair.public()); - let (root_id, root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(user_1.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), ); let delegation_id = get_delegation_id(true); @@ -1626,7 +1595,7 @@ fn is_delegating_delegation_not_found() { // Root -> Delegation 1 let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1.clone())]) .build(None); ext.execute_with(|| { @@ -1646,37 +1615,34 @@ fn is_delegating_root_after_max_limit() { let user_3_keypair = get_charlie_ed25519(); let user_3 = get_ed25519_account(user_3_keypair.public()); - let (root_id, mut root_node) = ( - get_delegation_root_id(true), - generate_base_delegation_root(user_1.clone()), + let (hierarchy_root_id, hierarchy_details) = ( + get_delegation_hierarchy_id(true), + generate_base_delegation_hierarchy_details(), + ); + let (parent_id, parent_node) = ( + get_delegation_id(true), + generate_base_delegation_node(hierarchy_root_id, user_2, Some(hierarchy_root_id)), + ); + let (delegation_id, delegation_node) = ( + get_delegation_id(false), + generate_base_delegation_node(hierarchy_root_id, user_3, Some(parent_id)), ); - root_node.revoked = true; - let (delegation_id_1, mut delegation_node_1) = - (get_delegation_id(true), generate_base_delegation_node(root_id, user_2)); - delegation_node_1.revoked = true; - let (delegation_id_2, mut delegation_node_2) = - (get_delegation_id(false), generate_base_delegation_node(root_id, user_3)); - delegation_node_2.parent = Some(delegation_id_1); // 1 less than needed let max_parent_checks = 1u32; - // Root -> Delegation 1 -> Delegation 2 - let mut ext = ExtBuilder::default() - .with_root_delegations(vec![(root_id, root_node)]) - .with_delegations(vec![ - (delegation_id_1, delegation_node_1), - (delegation_id_2, delegation_node_2), - ]) - .with_children(vec![ - (root_id, vec![delegation_id_1]), - (delegation_id_1, vec![delegation_id_2]), - ]) + // Root -> Parent -> Delegation + let ext = ctype_mock::ExtBuilder::default() + .with_ctypes(vec![(hierarchy_details.ctype_hash, user_1.clone())]) .build(None); + let mut ext = ExtBuilder::default() + .with_delegation_hierarchies(vec![(hierarchy_root_id, hierarchy_details, user_1.clone())]) + .with_delegations(vec![(parent_id, parent_node), (delegation_id, delegation_node)]) + .build(Some(ext)); ext.execute_with(|| { assert_noop!( - Delegation::is_delegating(&user_1, &delegation_id_2, max_parent_checks), + Delegation::is_delegating(&user_1, &delegation_id, max_parent_checks), delegation::Error::::MaxSearchDepthReached ); }); diff --git a/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index 0e91450cb8..54aa4bc36b 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: 16, + spec_version: 17, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, diff --git a/runtimes/peregrine/src/weights/attestation.rs b/runtimes/peregrine/src/weights/attestation.rs index 1d409b375d..ca84370d96 100644 --- a/runtimes/peregrine/src/weights/attestation.rs +++ b/runtimes/peregrine/src/weights/attestation.rs @@ -19,30 +19,22 @@ //! Autogenerated weights for attestation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-17, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-07-21, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// ./target/release/kilt-parachain +// target/release/kilt-parachain // benchmark -// --chain -// dev -// --heap-pages -// 4096 -// --extrinsic -// * -// --pallet -// attestation -// --steps -// 1 -// --repeat -// 20 -// --execution -// wasm -// --wasm-execution -// Compiled +// --chain=dev +// --execution=wasm +// --wasm-execution=Compiled +// --heap-pages=4096 +// --extrinsic=* +// --pallet=attestation +// --steps=1 +// --repeat=20 // --output -// runtimes/parachain/src/weights/attestation.rs +// runtimes/peregrine/src/weights/attestation.rs // --template // .maintain/runtime-weight-template.hbs @@ -58,16 +50,16 @@ use sp_std::marker::PhantomData; pub struct WeightInfo(PhantomData); impl attestation::WeightInfo for WeightInfo { fn add() -> Weight { - 67_947_000_u64 + (68_138_000_u64) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } fn revoke(d: u32, ) -> Weight { - 44_056_000_u64 - // Standard Error: 30_000 - .saturating_add(8_178_000_u64.saturating_mul(d as Weight)) + (46_806_000_u64) + // Standard Error: 134_000 + .saturating_add((8_122_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().reads((1_u64).saturating_mul(d as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) } } \ No newline at end of file diff --git a/runtimes/peregrine/src/weights/delegation.rs b/runtimes/peregrine/src/weights/delegation.rs index 358cf251e3..f77437b42c 100644 --- a/runtimes/peregrine/src/weights/delegation.rs +++ b/runtimes/peregrine/src/weights/delegation.rs @@ -19,30 +19,22 @@ //! Autogenerated weights for delegation //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-06-17, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2021-07-21, STEPS: `[1, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: -// ./target/release/kilt-parachain +// target/release/kilt-parachain // benchmark -// --chain -// dev -// --heap-pages -// 4096 -// --extrinsic -// * -// --pallet -// delegation -// --steps -// 1 -// --repeat -// 20 -// --execution -// wasm -// --wasm-execution -// Compiled +// --chain=dev +// --execution=wasm +// --wasm-execution=Compiled +// --heap-pages=4096 +// --extrinsic=* +// --pallet=delegation +// --steps=1 +// --repeat=20 // --output -// runtimes/parachain/src/weights/delegation.rs +// runtimes/peregrine/src/weights/delegation.rs // --template // .maintain/runtime-weight-template.hbs @@ -57,40 +49,34 @@ use sp_std::marker::PhantomData; /// Weights for delegation using the recommended hardware. pub struct WeightInfo(PhantomData); impl delegation::WeightInfo for WeightInfo { - fn create_root() -> Weight { - 45_635_000_u64 + fn create_hierarchy() -> Weight { + (48_641_000_u64) .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - fn revoke_root(r: u32, ) -> Weight { - 48_761_000_u64 - // Standard Error: 311_000 - .saturating_add(31_784_000_u64.saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().reads(2_u64.saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64.saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(2_u64)) } fn add_delegation() -> Weight { - 142_316_000_u64 - .saturating_add(T::DbWeight::get().reads(4_u64)) + (130_555_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 { - 21_746_000_u64 - // Standard Error: 60_000 - .saturating_add(32_601_000_u64.saturating_mul(r as Weight)) - .saturating_add(T::DbWeight::get().reads(2_u64.saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1_u64.saturating_mul(r as Weight))) + 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)) + .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 { - 52_521_000_u64 - // Standard Error: 45_000 - .saturating_add(93_000_u64.saturating_mul(r as Weight)) - // Standard Error: 45_000 - .saturating_add(8_110_000_u64.saturating_mul(c as Weight)) + (58_402_000_u64) + // Standard Error: 307_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)) .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().reads((1_u64).saturating_mul(c as Weight))) .saturating_add(T::DbWeight::get().writes(1_u64)) } } \ No newline at end of file diff --git a/runtimes/spiritnet/src/lib.rs b/runtimes/spiritnet/src/lib.rs index 5958b7feae..c35c6181b9 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: 16, + spec_version: 17, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index fd3ae9aa06..cb45c4c18e 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: 16, + spec_version: 17, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, From 64d46bcc54b4d004c1566218f99386998b34b2a7 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 3 Aug 2021 14:05:56 +0200 Subject: [PATCH 14/37] chore: convert BTreeSet to bounded version in delegations --- pallets/attestation/src/mock.rs | 3 +++ pallets/delegation/src/benchmarking.rs | 6 ++--- .../delegation/src/delegation_hierarchy.rs | 17 +++++++------ pallets/delegation/src/lib.rs | 25 +++++++++++++++---- pallets/delegation/src/migrations/v1.rs | 14 ++++++++--- pallets/delegation/src/mock.rs | 12 ++++++--- runtimes/peregrine/src/lib.rs | 4 +++ runtimes/standalone/src/lib.rs | 4 +++ 8 files changed, 62 insertions(+), 23 deletions(-) diff --git a/pallets/attestation/src/mock.rs b/pallets/attestation/src/mock.rs index 59c9145d02..7505899792 100644 --- a/pallets/attestation/src/mock.rs +++ b/pallets/attestation/src/mock.rs @@ -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,6 +113,7 @@ impl delegation::Config for Test { type MaxSignatureByteLength = MaxSignatureByteLength; type MaxParentChecks = MaxParentChecks; type MaxRevocations = MaxRevocations; + type MaxChildren = MaxChildren; type WeightInfo = (); } 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/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/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index 54aa4bc36b..f4ca4f2d62 100644 --- a/runtimes/peregrine/src/lib.rs +++ b/runtimes/peregrine/src/lib.rs @@ -667,6 +667,9 @@ 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 { @@ -678,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; } diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index cb45c4c18e..c6fbcc7f0c 100644 --- a/runtimes/standalone/src/lib.rs +++ b/runtimes/standalone/src/lib.rs @@ -345,6 +345,9 @@ 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 { @@ -356,6 +359,7 @@ impl delegation::Config for Runtime { type MaxSignatureByteLength = MaxSignatureByteLength; type MaxParentChecks = MaxParentChecks; type MaxRevocations = MaxRevocations; + type MaxChildren = MaxChildren; type WeightInfo = (); } From e7a526ad44917936be19cfc7d92495287877c91a Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 3 Aug 2021 15:06:58 +0200 Subject: [PATCH 15/37] refactor: add missing const declarations --- pallets/attestation/src/lib.rs | 4 +++- pallets/did/src/lib.rs | 8 ++++++++ pallets/parachain-staking/src/lib.rs | 30 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/pallets/attestation/src/lib.rs b/pallets/attestation/src/lib.rs index 087d05cf01..b9eda60cc1 100644 --- a/pallets/attestation/src/lib.rs +++ b/pallets/attestation/src/lib.rs @@ -114,7 +114,9 @@ pub mod pallet { type EnsureOrigin: EnsureOrigin, ::Origin>; type Event: From> + IsType<::Event>; type WeightInfo: WeightInfo; - /// Maximum number for delegated attestations required for bounded vec. + + /// The maximum number of delegated attestations which can be made by + /// the same delegation. #[pallet::constant] type MaxDelegatedAttestations: Get; } diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index 0bdfa3bc33..b4035145da 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -165,26 +165,34 @@ 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>>; + /// Overarching event type. type Event: From> + IsType<::Event>; + /// Maximum number of key agreement keys that can be added in a creation /// or update operation. #[pallet::constant] type MaxNewKeyAgreementKeys: Get; + /// 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; + /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 415ebbda49..1bdb89828c 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -229,6 +229,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 @@ -242,49 +243,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. + #[pallet::constant] type MaxDelegatorsPerCollator: Get + Debug + PartialEq; + /// Maximum number of collators a single delegator can delegate. + #[pallet::constant] type MaxCollatorsPerDelegator: Get + Debug + PartialEq; + /// Maximum size of the collator candidates set. + #[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; } From ac73fb776b22910ce5df3d676b8dfd296fcc4577 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 3 Aug 2021 17:24:21 +0200 Subject: [PATCH 16/37] wip: migrate did pallet to bounded --- pallets/did/src/did_details.rs | 169 +++++++++++++++++++-------------- pallets/did/src/errors.rs | 21 ++++ pallets/did/src/lib.rs | 37 +++++++- 3 files changed, 154 insertions(+), 73 deletions(-) diff --git a/pallets/did/src/did_details.rs b/pallets/did/src/did_details.rs index 259aa0336d..6cd6050495 100644 --- a/pallets/did/src/did_details.rs +++ b/pallets/did/src/did_details.rs @@ -17,12 +17,10 @@ // 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}; 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::*; @@ -222,14 +220,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. authentication_key: KeyIdOf, /// The set of the key agreement key IDs, which can be used to encrypt /// data addressed to the DID subject. - key_agreement_keys: BTreeSet>, + key_agreement_keys: BoundedBTreeSet, T::MaxTotalKeyAgreementKeys>, /// \[OPTIONAL\] The ID of the delegation key, used to verify the /// signatures of the delegations created by the DID subject. delegation_key: Option>, @@ -245,7 +243,7 @@ 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. - public_keys: BTreeMap, DidPublicKeyDetails>, + public_keys: BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDidKeyIdentifier>, /// \[OPTIONAL\] The URL pointing to the service endpoints the DID /// subject publicly exposes. pub endpoint_url: Option, @@ -260,25 +258,28 @@ impl DidDetails { /// i.e., an authentication key and the block creation time. /// /// The tx counter is set by default 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 = + BoundedBTreeMap::, DidPublicKeyDetails, T::MaxPublicKeysPerDidKeyIdentifier>::new(); 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::MaxPublicKeysPerDidKeyIdentifierExceeded)?; + Ok(Self { authentication_key: authentication_key_id, - key_agreement_keys: BTreeSet::new(), + key_agreement_keys: BoundedBTreeSet::, T::MaxTotalKeyAgreementKeys>::new(), attestation_key: None, delegation_key: None, endpoint_url: None, public_keys, last_tx_counter: 0u64, - } + }) } /// Update the DID authentication key. @@ -290,7 +291,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; @@ -298,13 +299,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::MaxPublicKeysPerDidKeyIdentifierExceeded)?; + Ok(()) } /// Add new key agreement keys to the DID. @@ -312,20 +316,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: BoundedBTreeSet, 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::MaxPublicKeysPerDidKeyIdentifierExceeded)?; + self.key_agreement_keys + .try_insert(new_key_agreement_id) + .map_err(|_| StorageError::MaxTotalKeyAgreementKeysExceeded)?; } + Ok(()) } /// Update the DID attestation key. @@ -333,16 +342,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::MaxPublicKeysPerDidKeyIdentifierExceeded)?; + Ok(()) } /// Delete the DID attestation key. @@ -359,20 +375,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::MaxPublicKeysPerDidKeyIdentifierExceeded)?; + Ok(()) } /// Delete the DID delegation key. @@ -444,7 +467,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 } @@ -456,7 +479,9 @@ impl DidDetails { &self.delegation_key } - pub fn get_public_keys(&self) -> &BTreeMap, DidPublicKeyDetails> { + pub fn get_public_keys( + &self, + ) -> &BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDidKeyIdentifier> { &self.public_keys } @@ -503,7 +528,7 @@ impl DidDetails { } impl TryFrom<(DidCreationOperation, DidVerificationKey)> for DidDetails { - type Error = InputError; + type Error = DidError; fn try_from(new_details: (DidCreationOperation, DidVerificationKey)) -> Result { let (op, new_auth_key) = new_details; @@ -523,16 +548,16 @@ impl TryFrom<(DidCreationOperation, DidVerificationKey)> for DidDe 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(op.new_key_agreement_keys, current_block_number); + new_did_details.add_key_agreement_keys(op.new_key_agreement_keys, current_block_number)?; - if let Some(attesation_key) = op.new_attestation_key { - new_did_details.update_attestation_key(attesation_key, current_block_number); + if let Some(attestation_key) = op.new_attestation_key { + new_did_details.update_attestation_key(attestation_key, current_block_number)?; } if let Some(delegation_key) = op.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.endpoint_url = op.new_endpoint_url; @@ -557,19 +582,19 @@ impl TryFrom<(DidDetails, DidUpdateOperation)> for DidDetails::MaxNewKeyAgreementKeys>::get().saturated_into::(), - DidError::InputError(InputError::MaxKeyAgreementKeysLimitExceeded) + InputError::MaxKeyAgreementKeysLimitExceeded ); ensure!( update_operation.public_keys_to_remove.len() <= <::MaxVerificationKeysToRevoke>::get().saturated_into::(), - DidError::InputError(InputError::MaxVerificationKeysToRemoveLimitExceeded) + InputError::MaxVerificationKeysToRemoveLimitExceeded ); if let Some(ref endpoint_url) = update_operation.new_endpoint_url { ensure!( endpoint_url.len() <= T::MaxUrlLength::get().saturated_into::(), - DidError::InputError(InputError::MaxUrlLengthExceeded) + InputError::MaxUrlLengthExceeded ); } @@ -584,11 +609,11 @@ impl TryFrom<(DidDetails, DidUpdateOperation)> for DidDetails TryFrom<(DidDetails, DidUpdateOperation)> for DidDetails { - new_details.update_delegation_key(new_delegation_key, current_block_number); + new_details.update_delegation_key(new_delegation_key, current_block_number)?; } // Nothing happens. DidVerificationKeyUpdateAction::Ignore => {} @@ -660,12 +685,12 @@ pub trait DeriveDidCallAuthorizationVerificationKeyRelationship { /// contain information about the caller's DID, the type of DID key /// required to verify the operation signature, and the tx counter to /// protect against replay attacks. -#[derive(Clone, Debug, Decode, Encode, PartialEq)] +#[derive(Clone, Decode, Encode, PartialEq)] pub struct DidCreationOperation { /// 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: BoundedBTreeSet, /// \[OPTIONAL\] The new attestation key. pub new_attestation_key: Option, /// \[OPTIONAL\] The new delegation key. @@ -696,14 +721,14 @@ impl DidOperation for DidCreationOperation { /// contain information about the caller's DID, the type of DID key /// required to verify the operation signature, and the tx counter to /// protect against replay attacks. -#[derive(Clone, Debug, Decode, Encode, PartialEq)] +#[derive(Clone, Decode, Encode, PartialEq)] pub struct DidUpdateOperation { /// The DID identifier. pub did: DidIdentifierOf, /// \[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: BoundedBTreeSet, /// \[OPTIONAL\] The attestation key update action. pub attestation_key_update: DidVerificationKeyUpdateAction, /// \[OPTIONAL\] The delegation key update action. @@ -712,7 +737,7 @@ pub struct DidUpdateOperation { /// 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: BoundedBTreeSet, T::MaxOldAttestationKeys>, /// \[OPTIONAL\] The new endpoint URL. pub new_endpoint_url: Option, /// The DID tx counter. diff --git a/pallets/did/src/errors.rs b/pallets/did/src/errors.rs index 8b37443171..358c73ac22 100644 --- a/pallets/did/src/errors.rs +++ b/pallets/did/src/errors.rs @@ -33,6 +33,18 @@ 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) + } +} + /// Error involving the pallet's storage. #[derive(Debug, Eq, PartialEq)] pub enum StorageError { @@ -52,6 +64,15 @@ 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. + MaxPublicKeysPerDidKeyIdentifierExceeded, + /// The maximum number of key agreements has been reached for the DID + /// subject. + MaxTotalKeyAgreementKeysExceeded, + /// The maximum number of old attestation keys still stored for + /// attestation verification has been reached. + MaxOldAttestationKeysExceeded, } /// Error generated when validating a DID operation. diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index b4035145da..8d5bcbc7ea 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -127,7 +127,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}; +use sp_std::{boxed::Box, convert::TryFrom, fmt::Debug, prelude::Clone}; #[frame_support::pallet] pub mod pallet { @@ -179,15 +179,36 @@ pub mod pallet { /// 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 MaxPublicKeysPerDidKeyIdentifier: 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 number of old attestation keys which can still be used to + /// verify previously issued attestations but cannot create new + /// attestations. + #[pallet::constant] + type MaxOldAttestationKeys: Get + Debug + Clone + PartialEq; + /// Maximum length in ASCII characters of the endpoint URL specified in /// a creation or update operation. #[pallet::constant] @@ -268,6 +289,15 @@ pub mod pallet { MaxUrlLengthExceeded, /// 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. + MaxPublicKeysPerDidKeyIdentifierExceeded, + /// The maximum number of key agreements has been reached for the DID + /// subject. + MaxTotalKeyAgreementKeysExceeded, + /// The maximum number of old attestation keys still stored for + /// attestation verification has been reached. + MaxOldAttestationKeysExceeded, } impl From for Error { @@ -292,6 +322,11 @@ pub mod pallet { } StorageError::MaxTxCounterValue => Self::MaxTxCounterValue, StorageError::CurrentlyActiveKey => Self::CurrentlyActiveKey, + StorageError::MaxPublicKeysPerDidKeyIdentifierExceeded => { + Self::MaxPublicKeysPerDidKeyIdentifierExceeded + } + StorageError::MaxTotalKeyAgreementKeysExceeded => Self::MaxTotalKeyAgreementKeysExceeded, + StorageError::MaxOldAttestationKeysExceeded => Self::MaxOldAttestationKeysExceeded, } } } From 84c93d0376a8398d9fa0c7558bc0b3838bd7a311 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 4 Aug 2021 12:03:18 +0200 Subject: [PATCH 17/37] fix: did tests --- pallets/did/src/did_details.rs | 32 +++++++++++ pallets/did/src/mock.rs | 80 ++++++++++++++++----------- pallets/did/src/tests.rs | 98 +++++++++++++++++++++------------- pallets/did/src/url.rs | 2 +- pallets/did/src/utils.rs | 4 +- runtimes/peregrine/src/lib.rs | 9 ++++ runtimes/standalone/src/lib.rs | 9 ++++ 7 files changed, 162 insertions(+), 72 deletions(-) diff --git a/pallets/did/src/did_details.rs b/pallets/did/src/did_details.rs index 6cd6050495..1d8a97f9db 100644 --- a/pallets/did/src/did_details.rs +++ b/pallets/did/src/did_details.rs @@ -715,6 +715,21 @@ impl DidOperation for DidCreationOperation { } } +// required because BoundedTreeSet does not implement Debug outside of std +// FIXME: Can we derive Debug and use custom impl only in std? +// #[cfg(not(feature = "std"))] +impl fmt::Debug for DidCreationOperation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("DidCreationOperation") + .field(&self.did) + .field(&self.new_key_agreement_keys.clone().into_inner()) + .field(&self.new_attestation_key) + .field(&self.new_delegation_key) + .field(&self.new_endpoint_url) + .finish() + } +} + /// An operation to update a DID. /// /// The struct implements the [DidOperation] trait, and as such it must @@ -744,6 +759,23 @@ pub struct DidUpdateOperation { pub tx_counter: u64, } +// required because BoundedTreeSet does not implement Debug outside of std +// FIXME: Can we derive Debug and use custom impl only in std? +// #[cfg(not(feature = "std"))] +impl fmt::Debug for DidUpdateOperation { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("DidUpdateOperation") + .field(&self.did) + .field(&self.new_key_agreement_keys.clone().into_inner()) + .field(&self.attestation_key_update) + .field(&self.delegation_key_update) + .field(&self.public_keys_to_remove.clone().into_inner()) + .field(&self.new_endpoint_url) + .field(&self.tx_counter) + .finish() + } +} + impl DidOperation for DidUpdateOperation { fn get_verification_key_relationship(&self) -> DidVerificationKeyRelationship { DidVerificationKeyRelationship::Authentication diff --git a/pallets/did/src/mock.rs b/pallets/did/src/mock.rs index a7d986b2d7..03361fba43 100644 --- a/pallets/did/src/mock.rs +++ b/pallets/did/src/mock.rs @@ -20,7 +20,7 @@ #![allow(unused_must_use)] use codec::{Decode, Encode}; -use frame_support::{parameter_types, weights::constants::RocksDbWeight}; +use frame_support::{parameter_types, storage::bounded_btree_set::BoundedBTreeSet, weights::constants::RocksDbWeight}; #[cfg(feature = "runtime-benchmarks")] use frame_system::EnsureSigned; use sp_core::{ecdsa, ed25519, sr25519, Pair}; @@ -92,6 +92,12 @@ parameter_types! { pub const MaxNewKeyAgreementKeys: u32 = 10u32; pub const MaxVerificationKeysToRevoke: u32 = 10u32; pub const MaxUrlLength: u32 = 200u32; + #[derive(Debug, Clone)] + pub const MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxTotalKeyAgreementKeys: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxOldAttestationKeys: u32 = 100; } impl Config for Test { @@ -100,8 +106,11 @@ impl Config for Test { type Call = Call; type Event = (); type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; - type MaxUrlLength = MaxUrlLength; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type MaxOldAttestationKeys = MaxOldAttestationKeys; + type MaxPublicKeysPerDidKeyIdentifier = MaxPublicKeysPerDidKeyIdentifier; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; + type MaxUrlLength = MaxUrlLength; type WeightInfo = (); } @@ -220,33 +229,39 @@ 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::>() +pub fn get_key_agreement_keys(n_keys: u32) -> BoundedBTreeSet { + 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_to_remove(n_keys: u32) -> BoundedBTreeSet { + 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); + generate_key_id(&key.into()) + }) + .collect::>(), + ) + .expect("Failed to convert public_keys_to_remove to BoundedBTreeSet") } // Assumes that the length of the URL is larger than 8 (length of the prefix https://) @@ -262,7 +277,7 @@ pub fn get_url_endpoint(length: u32) -> Url { pub fn generate_base_did_creation_operation(did: TestDidIdentifier) -> did::DidCreationOperation { DidCreationOperation { did, - new_key_agreement_keys: BTreeSet::new(), + new_key_agreement_keys: BoundedBTreeSet::new(), new_attestation_key: None, new_delegation_key: None, new_endpoint_url: None, @@ -273,11 +288,11 @@ pub fn generate_base_did_update_operation(did: TestDidIdentifier) -> did::DidUpd DidUpdateOperation { did, new_authentication_key: None, - new_key_agreement_keys: BTreeSet::new(), + new_key_agreement_keys: BoundedBTreeSet::new(), attestation_key_update: DidVerificationKeyUpdateAction::default(), delegation_key_update: DidVerificationKeyUpdateAction::default(), new_endpoint_url: None, - public_keys_to_remove: BTreeSet::new(), + public_keys_to_remove: BoundedBTreeSet::new(), tx_counter: 1u64, } } @@ -288,6 +303,7 @@ pub fn generate_base_did_delete_operation(did: TestDidIdentifier) -> did::DidDel pub fn generate_base_did_details(authentication_key: did::DidVerificationKey) -> did::DidDetails { did::DidDetails::new(authentication_key, 0u64) + .expect("Failed to generate new DidDetails from auth_key due to BoundedBTreeSet bound") } pub fn generate_key_id(key: &did::DidPublicKey) -> TestKeyId { diff --git a/pallets/did/src/tests.rs b/pallets/did/src/tests.rs index 58d7eb12ad..8082d83ad8 100644 --- a/pallets/did/src/tests.rs +++ b/pallets/did/src/tests.rs @@ -16,11 +16,11 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok, storage::bounded_btree_set::BoundedBTreeSet}; use sp_core::*; use sp_std::{collections::btree_set::BTreeSet, convert::TryFrom}; -use crate::{self as did, mock::*}; +use crate::{self as did, mock::*, Config}; use ctype::mock as ctype_mock; // submit_did_create_operation @@ -135,11 +135,13 @@ 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 = BoundedBTreeSet::::MaxTotalKeyAgreementKeys>::try_from( vec![get_x25519_encryption_key(true), get_x25519_encryption_key(false)] .iter() .copied() - .collect(); + .collect::>(), + ) + .expect("Exceeded BounddBTreeSet 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_url = did::Url::from( @@ -345,10 +347,13 @@ fn check_successful_complete_update() { 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::>(), + BoundedBTreeSet::::MaxTotalKeyAgreementKeys>::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); @@ -357,18 +362,25 @@ fn check_successful_complete_update() { // removed. let mut operation = generate_base_did_update_operation(alice_did.clone()); operation.new_authentication_key = Some(did::DidVerificationKey::from(new_auth_key.public())); - operation.new_key_agreement_keys = vec![new_enc_key] - .iter() - .copied() - .collect::>(); + operation.new_key_agreement_keys = + BoundedBTreeSet::::MaxTotalKeyAgreementKeys>::try_from( + vec![new_enc_key] + .iter() + .copied() + .collect::>(), + ) + .expect("Should not fail to create BoundedBTreeSet from a single element"); operation.attestation_key_update = did::DidVerificationKeyUpdateAction::Change(did::DidVerificationKey::from(new_att_key.public())); operation.delegation_key_update = did::DidVerificationKeyUpdateAction::Change(did::DidVerificationKey::from(new_del_key.public())); - operation.public_keys_to_remove = vec![generate_key_id(&old_enc_key.into())] - .iter() - .copied() - .collect::>(); + operation.public_keys_to_remove = BoundedBTreeSet::::MaxOldAttestationKeys>::try_from( + vec![generate_key_id(&old_enc_key.into())] + .iter() + .copied() + .collect::>(), + ) + .expect("Should not fail to create BoundedBTreeSet from a single element"); operation.new_endpoint_url = Some(new_url); operation.tx_counter = old_did_details.last_tx_counter + 1u64; @@ -896,12 +908,15 @@ fn check_currently_active_authentication_key_update() { // Remove both attestation and delegation key let mut operation = generate_base_did_update_operation(alice_did.clone()); // Trying to remove the currently active authentication key - operation.public_keys_to_remove = vec![generate_key_id( - &did::DidVerificationKey::from(auth_key.public()).into(), - )] - .iter() - .copied() - .collect::>(); + operation.public_keys_to_remove = BoundedBTreeSet::::MaxOldAttestationKeys>::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 signature = auth_key.sign(operation.encode().as_ref()); @@ -936,10 +951,13 @@ fn check_currently_active_delegation_key_update() { // Remove both attestation and delegation key let mut operation = generate_base_did_update_operation(alice_did.clone()); // Trying to remove the currently active delegation key - operation.public_keys_to_remove = vec![generate_key_id(&did::DidVerificationKey::from(del_key.public()).into())] - .iter() - .copied() - .collect::>(); + operation.public_keys_to_remove = BoundedBTreeSet::::MaxOldAttestationKeys>::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 signature = auth_key.sign(operation.encode().as_ref()); @@ -974,10 +992,13 @@ fn check_currently_active_attestation_key_update() { // Remove both attestation and delegation key let mut operation = generate_base_did_update_operation(alice_did.clone()); // Trying to remove the currently active attestation key - operation.public_keys_to_remove = vec![generate_key_id(&did::DidVerificationKey::from(att_key.public()).into())] - .iter() - .copied() - .collect::>(); + operation.public_keys_to_remove = BoundedBTreeSet::::MaxOldAttestationKeys>::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 signature = auth_key.sign(operation.encode().as_ref()); @@ -1011,12 +1032,15 @@ fn check_verification_key_not_present_update() { // Remove both attestation and delegation key let mut operation = generate_base_did_update_operation(alice_did.clone()); // Trying to remove the currently active authentication key - operation.public_keys_to_remove = vec![generate_key_id( - &did::DidVerificationKey::from(key_to_delete.public()).into(), - )] - .iter() - .copied() - .collect::>(); + operation.public_keys_to_remove = BoundedBTreeSet::::MaxOldAttestationKeys>::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 signature = auth_key.sign(operation.encode().as_ref()); @@ -1066,7 +1090,7 @@ fn check_successful_deletion() { )); }); - 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 operation = generate_base_did_creation_operation(alice_did); diff --git a/pallets/did/src/url.rs b/pallets/did/src/url.rs index 1f92b74f6f..fce28957dc 100644 --- a/pallets/did/src/url.rs +++ b/pallets/did/src/url.rs @@ -17,7 +17,7 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use codec::{Decode, Encode}; -use sp_std::str; +use sp_std::{str, vec::Vec}; use crate::*; 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/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index f4ca4f2d62..f61a746370 100644 --- a/runtimes/peregrine/src/lib.rs +++ b/runtimes/peregrine/src/lib.rs @@ -696,6 +696,12 @@ parameter_types! { pub const MaxNewKeyAgreementKeys: u32 = 10u32; pub const MaxVerificationKeysToRevoke: u32 = 10u32; pub const MaxUrlLength: u32 = 200u32; + // TODO: Find reasonable numbers + pub const MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxTotalKeyAgreementKeys: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxOldAttestationKeys: u32 = 100; } impl did::Config for Runtime { @@ -704,6 +710,9 @@ impl did::Config for Runtime { type Call = Call; type Origin = Origin; type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type MaxOldAttestationKeys = MaxOldAttestationKeys; + type MaxPublicKeysPerDidKeyIdentifier = MaxPublicKeysPerDidKeyIdentifier; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; type WeightInfo = weights::did::WeightInfo; diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index c6fbcc7f0c..8168134faf 100644 --- a/runtimes/standalone/src/lib.rs +++ b/runtimes/standalone/src/lib.rs @@ -374,6 +374,12 @@ parameter_types! { pub const MaxNewKeyAgreementKeys: u32 = 10u32; pub const MaxVerificationKeysToRevoke: u32 = 10u32; pub const MaxUrlLength: u32 = 200u32; + // TODO: Find reasonable numbers + pub const MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxTotalKeyAgreementKeys: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxOldAttestationKeys: u32 = 100; } impl did::Config for Runtime { @@ -382,6 +388,9 @@ impl did::Config for Runtime { type Call = Call; type Origin = Origin; type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type MaxOldAttestationKeys = MaxOldAttestationKeys; + type MaxPublicKeysPerDidKeyIdentifier = MaxPublicKeysPerDidKeyIdentifier; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; type WeightInfo = (); From 7e83fa58b92ee104a285876bf899fa7f9bcc4c56 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 5 Aug 2021 15:28:06 +0200 Subject: [PATCH 18/37] refactor: rm redundancy, improve mock by splitting --- pallets/did/src/benchmarking.rs | 130 ++----- pallets/did/src/lib.rs | 2 +- pallets/did/src/mock.rs | 659 ++++++++++++++++---------------- pallets/did/src/tests.rs | 134 +++---- 4 files changed, 444 insertions(+), 481 deletions(-) diff --git a/pallets/did/src/benchmarking.rs b/pallets/did/src/benchmarking.rs index c9d32f99d3..0033c157b4 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; 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}; -use crate::*; -use did_details::*; +use crate::{ + did_details::*, + mock::{ + generate_base_did_creation_details, generate_base_did_details, generate_base_did_update_details, + get_key_agreement_keys, get_public_keys, get_url_endpoint, 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,41 +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_url_endpoint(length: u32) -> Url { - let total_length = usize::try_from(length).expect("Failed to convert URL max length value to usize value."); - let mut url_encoded_string = DEFAULT_URL_SCHEME.to_vec(); - url_encoded_string.resize(total_length, b'0'); - Url::Http( - HttpUrl::try_from(url_encoded_string.as_ref()).expect("Failed to create default URL with provided length."), - ) -} - -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_endpoint_url: None, - } -} - -fn generate_base_did_update_details(_did: DidIdentifierOf) -> DidUpdateDetails { - DidUpdateDetails { - new_authentication_key: None, - new_key_agreement_keys: BTreeSet::new(), - attestation_key_update: DidVerificationKeyUpdateAction::default(), - delegation_key_update: DidVerificationKeyUpdateAction::default(), - new_endpoint_url: None, - 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(); @@ -163,7 +104,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_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 did_endpoint = get_url_endpoint(u); @@ -212,7 +153,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_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 did_endpoint = get_url_endpoint(u); @@ -261,7 +202,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_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 did_endpoint = get_url_endpoint(u); @@ -310,21 +251,21 @@ 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); + let did_key_agreement_keys = get_key_agreement_keys::(m + n); - 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 new_url = get_url_endpoint(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 = DidVerificationKeyUpdateAction::Change(DidVerificationKey::from(new_did_public_att_key)); @@ -371,21 +312,21 @@ 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); + let did_key_agreement_keys = get_key_agreement_keys::(m + n); - 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 new_url = get_url_endpoint(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 = DidVerificationKeyUpdateAction::Change(DidVerificationKey::from(new_did_public_att_key)); @@ -432,21 +373,21 @@ 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); + let did_key_agreement_keys = get_key_agreement_keys::(m + n); - 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 new_url = get_url_endpoint(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 = DidVerificationKeyUpdateAction::Change(DidVerificationKey::from(new_did_public_att_key.clone())); @@ -487,13 +428,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() ); } @@ -503,7 +443,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); @@ -517,7 +457,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); @@ -531,7 +471,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); @@ -542,6 +482,6 @@ benchmarks! { impl_benchmark_test_suite! { Pallet, - crate::mock::ExtBuilder::default().build_with_keystore(None), - crate::mock::Test + crate::mock::std::ExtBuilder::default().build_with_keystore(None), + crate::mock::std::Test } diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index e6cb58b229..03ccf7d840 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -108,7 +108,7 @@ mod utils; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; -#[cfg(test)] +#[cfg(any(feature = "runtime-benchmarks", test))] mod mock; #[cfg(test)] mod tests; diff --git a/pallets/did/src/mock.rs b/pallets/did/src/mock.rs index 0c97de0867..6fdc600ea0 100644 --- a/pallets/did/src/mock.rs +++ b/pallets/did/src/mock.rs @@ -17,223 +17,20 @@ // 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)] - -#[cfg(feature = "runtime-benchmarks")] -use frame_system::EnsureSigned; - -use frame_support::{parameter_types, storage::bounded_btree_set::BoundedBTreeSet, weights::constants::RocksDbWeight}; -use sp_core::{ecdsa, ed25519, sr25519, Pair}; -use sp_keystore::{testing::KeyStore, KeystoreExt}; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, - MultiSigner, -}; -use sp_std::{collections::btree_set::BTreeSet, convert::TryInto, sync::Arc}; -use crate as did; use crate::*; +use did_details::*; +use frame_support::storage::bounded_btree_set::BoundedBTreeSet; +use sp_std::{ + collections::btree_set::BTreeSet, + convert::{TryFrom, TryInto}, +}; -pub type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -pub type Block = frame_system::mocking::MockBlock; - -pub type TestDidIdentifier = kilt_primitives::AccountId; -pub type TestKeyId = did::KeyIdOf; -pub type TestBlockNumber = kilt_primitives::BlockNumber; -pub type TestCtypeOwner = TestDidIdentifier; -pub type TestCtypeHash = kilt_primitives::Hash; - -frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - Did: did::{Pallet, Call, Storage, Event, Origin}, - Ctype: ctype::{Pallet, Call, Storage, Event}, - System: frame_system::{Pallet, Call, Config, Storage, Event}, - } -); - -parameter_types! { - pub const SS58Prefix: u8 = 38; - pub const BlockHashCount: u64 = 250; -} - -impl frame_system::Config for Test { - type Origin = Origin; - type Call = Call; - type Index = u64; - type BlockNumber = u64; - type Hash = kilt_primitives::Hash; - type Hashing = BlakeTwo256; - type AccountId = <::Signer as IdentifyAccount>::AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type Event = (); - type BlockHashCount = BlockHashCount; - type DbWeight = RocksDbWeight; - type Version = (); - - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type BaseCallFilter = (); - type SystemWeightInfo = (); - type BlockWeights = (); - type BlockLength = (); - type SS58Prefix = SS58Prefix; - type OnSetCode = (); -} - -parameter_types! { - pub const MaxNewKeyAgreementKeys: u32 = 10u32; - pub const MaxVerificationKeysToRevoke: u32 = 10u32; - pub const MaxUrlLength: u32 = 200u32; - #[derive(Debug, Clone)] - pub const MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; - #[derive(Debug, Clone, PartialEq)] - pub const MaxTotalKeyAgreementKeys: u32 = 1000; - #[derive(Debug, Clone, PartialEq)] - pub const MaxOldAttestationKeys: u32 = 100; -} - -impl Config for Test { - type DidIdentifier = TestDidIdentifier; - type Origin = Origin; - type Call = Call; - #[cfg(feature = "runtime-benchmarks")] - type EnsureOrigin = EnsureSigned; - #[cfg(not(feature = "runtime-benchmarks"))] - type EnsureOrigin = did::EnsureDidOrigin; - type Event = (); - type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; - type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; - type MaxOldAttestationKeys = MaxOldAttestationKeys; - type MaxPublicKeysPerDidKeyIdentifier = MaxPublicKeysPerDidKeyIdentifier; - type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; - type MaxUrlLength = MaxUrlLength; - type WeightInfo = (); -} - -impl ctype::Config for Test { - type CtypeCreatorId = TestCtypeOwner; - #[cfg(feature = "runtime-benchmarks")] - type EnsureOrigin = EnsureSigned; - #[cfg(not(feature = "runtime-benchmarks"))] - type EnsureOrigin = did::EnsureDidOrigin; - type Event = (); - type WeightInfo = (); -} - -#[cfg(test)] -pub(crate) const DEFAULT_ACCOUNT: kilt_primitives::AccountId = kilt_primitives::AccountId::new([0u8; 32]); - -const DEFAULT_AUTH_SEED: [u8; 32] = [4u8; 32]; -const ALTERNATIVE_AUTH_SEED: [u8; 32] = [40u8; 32]; -const DEFAULT_ENC_SEED: [u8; 32] = [5u8; 32]; -const ALTERNATIVE_ENC_SEED: [u8; 32] = [50u8; 32]; -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://"; - -pub fn get_did_identifier_from_ed25519_key(public_key: ed25519::Public) -> TestDidIdentifier { - MultiSigner::from(public_key).into_account() -} - -pub fn get_did_identifier_from_sr25519_key(public_key: sr25519::Public) -> TestDidIdentifier { - MultiSigner::from(public_key).into_account() -} - -pub fn get_did_identifier_from_ecdsa_key(public_key: ecdsa::Public) -> TestDidIdentifier { - MultiSigner::from(public_key).into_account() -} - -pub fn get_ed25519_authentication_key(default: bool) -> ed25519::Pair { - if default { - ed25519::Pair::from_seed(&DEFAULT_AUTH_SEED) - } else { - ed25519::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) - } -} - -pub fn get_sr25519_authentication_key(default: bool) -> sr25519::Pair { - if default { - sr25519::Pair::from_seed(&DEFAULT_AUTH_SEED) - } else { - sr25519::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) - } -} - -pub fn get_ecdsa_authentication_key(default: bool) -> ecdsa::Pair { - if default { - ecdsa::Pair::from_seed(&DEFAULT_AUTH_SEED) - } else { - ecdsa::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) - } -} - -pub fn get_x25519_encryption_key(default: bool) -> DidEncryptionKey { - if default { - DidEncryptionKey::X25519(DEFAULT_ENC_SEED) - } else { - DidEncryptionKey::X25519(ALTERNATIVE_ENC_SEED) - } -} - -pub fn get_ed25519_attestation_key(default: bool) -> ed25519::Pair { - if default { - ed25519::Pair::from_seed(&DEFAULT_ATT_SEED) - } else { - ed25519::Pair::from_seed(&ALTERNATIVE_ATT_SEED) - } -} - -pub fn get_sr25519_attestation_key(default: bool) -> sr25519::Pair { - if default { - sr25519::Pair::from_seed(&DEFAULT_ATT_SEED) - } else { - sr25519::Pair::from_seed(&ALTERNATIVE_ATT_SEED) - } -} - -pub fn get_ecdsa_attestation_key(default: bool) -> ecdsa::Pair { - if default { - ecdsa::Pair::from_seed(&DEFAULT_ATT_SEED) - } else { - ecdsa::Pair::from_seed(&ALTERNATIVE_ATT_SEED) - } -} - -pub fn get_ed25519_delegation_key(default: bool) -> ed25519::Pair { - if default { - ed25519::Pair::from_seed(&DEFAULT_DEL_SEED) - } else { - ed25519::Pair::from_seed(&ALTERNATIVE_DEL_SEED) - } -} - -pub fn get_sr25519_delegation_key(default: bool) -> sr25519::Pair { - if default { - sr25519::Pair::from_seed(&DEFAULT_DEL_SEED) - } else { - sr25519::Pair::from_seed(&ALTERNATIVE_DEL_SEED) - } -} - -pub fn get_ecdsa_delegation_key(default: bool) -> ecdsa::Pair { - if default { - ecdsa::Pair::from_seed(&DEFAULT_DEL_SEED) - } else { - ecdsa::Pair::from_seed(&ALTERNATIVE_DEL_SEED) - } -} +pub(crate) const DEFAULT_URL_SCHEME: [u8; 8] = *b"https://"; -pub fn get_key_agreement_keys(n_keys: u32) -> BoundedBTreeSet { +pub fn get_key_agreement_keys( + n_keys: u32, +) -> BoundedBTreeSet { BoundedBTreeSet::try_from( (1..=n_keys) .map(|i| { @@ -250,7 +47,7 @@ pub fn get_key_agreement_keys(n_keys: u32) -> BoundedBTreeSet BoundedBTreeSet { +pub fn get_public_keys(n_keys: u32) -> BoundedBTreeSet, T::MaxOldAttestationKeys> { BoundedBTreeSet::try_from( (1..=n_keys) .map(|i| { @@ -261,11 +58,11 @@ pub fn get_public_keys_to_remove(n_keys: u32) -> BoundedBTreeSet(&key.into()) }) - .collect::>(), + .collect::>>(), ) - .expect("Failed to convert public_keys_to_remove to BoundedBTreeSet") + .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://) @@ -278,7 +75,7 @@ pub fn get_url_endpoint(length: u32) -> Url { ) } -pub fn generate_base_did_creation_details(did: TestDidIdentifier) -> did::DidCreationDetails { +pub fn generate_base_did_creation_details(did: DidIdentifierOf) -> DidCreationDetails { DidCreationDetails { did, new_key_agreement_keys: BoundedBTreeSet::new(), @@ -288,7 +85,7 @@ pub fn generate_base_did_creation_details(did: TestDidIdentifier) -> did::DidCre } } -pub fn generate_base_did_update_details() -> did::DidUpdateDetails { +pub fn generate_base_did_update_details() -> DidUpdateDetails { DidUpdateDetails { new_authentication_key: None, new_key_agreement_keys: BoundedBTreeSet::new(), @@ -299,134 +96,354 @@ pub fn generate_base_did_update_details() -> did::DidUpdateDetails { } } -pub fn generate_base_did_details(authentication_key: did::DidVerificationKey) -> did::DidDetails { - did::DidDetails::new(authentication_key, 0u64) +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") } -pub fn generate_key_id(key: &did::DidPublicKey) -> TestKeyId { - utils::calculate_key_id::(key) -} +#[cfg(any(feature = "std", test))] +pub mod std { + #![allow(dead_code)] + /// FIXME: Why does clippy not realize the complained functions are used in + /// the test? -pub(crate) fn get_attestation_key_test_input() -> TestCtypeHash { - TestCtypeHash::from_slice(&[0u8; 32]) -} -pub(crate) fn get_attestation_key_call() -> Call { - Call::Ctype(ctype::Call::add(get_attestation_key_test_input())) -} -pub(crate) fn get_authentication_key_test_input() -> TestCtypeHash { - TestCtypeHash::from_slice(&[1u8; 32]) -} -pub(crate) fn get_authentication_key_call() -> Call { - Call::Ctype(ctype::Call::add(get_authentication_key_test_input())) -} -pub(crate) fn get_delegation_key_test_input() -> TestCtypeHash { - TestCtypeHash::from_slice(&[2u8; 32]) -} -pub(crate) fn get_delegation_key_call() -> Call { - Call::Ctype(ctype::Call::add(get_delegation_key_test_input())) -} -pub(crate) fn get_none_key_test_input() -> TestCtypeHash { - TestCtypeHash::from_slice(&[3u8; 32]) -} -pub(crate) fn get_none_key_call() -> Call { - Call::Ctype(ctype::Call::add(get_none_key_test_input())) -} + #[cfg(feature = "runtime-benchmarks")] + use frame_system::EnsureSigned; + + use frame_support::{parameter_types, weights::constants::RocksDbWeight}; + use sp_core::{ecdsa, ed25519, sr25519, Pair}; + use sp_keystore::{testing::KeyStore, KeystoreExt}; + use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + MultiSigner, + }; + use sp_std::sync::Arc; + + use crate as did; + use crate::*; + + pub type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + pub type Block = frame_system::mocking::MockBlock; + + pub type TestDidIdentifier = kilt_primitives::AccountId; + pub type TestKeyId = did::KeyIdOf; + pub type TestBlockNumber = kilt_primitives::BlockNumber; + pub type TestCtypeOwner = TestDidIdentifier; + pub type TestCtypeHash = kilt_primitives::Hash; + + frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + Did: did::{Pallet, Call, Storage, Event, Origin}, + Ctype: ctype::{Pallet, Call, Storage, Event}, + System: frame_system::{Pallet, Call, Config, Storage, Event}, + } + ); + + parameter_types! { + pub const SS58Prefix: u8 = 38; + pub const BlockHashCount: u64 = 250; + } + + impl frame_system::Config for Test { + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = kilt_primitives::Hash; + type Hashing = BlakeTwo256; + type AccountId = <::Signer as IdentifyAccount>::AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type DbWeight = RocksDbWeight; + type Version = (); + + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type BaseCallFilter = (); + type SystemWeightInfo = (); + type BlockWeights = (); + type BlockLength = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); + } + + parameter_types! { + pub const MaxNewKeyAgreementKeys: u32 = 10u32; + pub const MaxVerificationKeysToRevoke: u32 = 10u32; + pub const MaxUrlLength: u32 = 200u32; + #[derive(Debug, Clone)] + pub const MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxTotalKeyAgreementKeys: u32 = 1000; + #[derive(Debug, Clone, PartialEq)] + pub const MaxOldAttestationKeys: u32 = 100; + } + + impl Config for Test { + type DidIdentifier = TestDidIdentifier; + type Origin = Origin; + type Call = Call; + #[cfg(feature = "runtime-benchmarks")] + type EnsureOrigin = EnsureSigned; + #[cfg(not(feature = "runtime-benchmarks"))] + type EnsureOrigin = did::EnsureDidOrigin; + type Event = (); + type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type MaxOldAttestationKeys = MaxOldAttestationKeys; + type MaxPublicKeysPerDidKeyIdentifier = MaxPublicKeysPerDidKeyIdentifier; + type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; + type MaxUrlLength = MaxUrlLength; + type WeightInfo = (); + } + + impl ctype::Config for Test { + type CtypeCreatorId = TestCtypeOwner; + #[cfg(feature = "runtime-benchmarks")] + type EnsureOrigin = EnsureSigned; + #[cfg(not(feature = "runtime-benchmarks"))] + type EnsureOrigin = did::EnsureDidOrigin; + type Event = (); + type WeightInfo = (); + } + + #[cfg(test)] + pub(crate) const DEFAULT_ACCOUNT: kilt_primitives::AccountId = kilt_primitives::AccountId::new([0u8; 32]); + + const DEFAULT_AUTH_SEED: [u8; 32] = [4u8; 32]; + const ALTERNATIVE_AUTH_SEED: [u8; 32] = [40u8; 32]; + const DEFAULT_ENC_SEED: [u8; 32] = [5u8; 32]; + const ALTERNATIVE_ENC_SEED: [u8; 32] = [50u8; 32]; + 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]; -impl did::DeriveDidCallAuthorizationVerificationKeyRelationship for Call { - fn derive_verification_key_relationship(&self) -> Option { - if *self == get_attestation_key_call() { - Some(did::DidVerificationKeyRelationship::AssertionMethod) - } else if *self == get_authentication_key_call() { - Some(did::DidVerificationKeyRelationship::Authentication) - } else if *self == get_delegation_key_call() { - Some(did::DidVerificationKeyRelationship::CapabilityDelegation) + pub fn get_did_identifier_from_ed25519_key(public_key: ed25519::Public) -> TestDidIdentifier { + MultiSigner::from(public_key).into_account() + } + + pub fn get_did_identifier_from_sr25519_key(public_key: sr25519::Public) -> TestDidIdentifier { + MultiSigner::from(public_key).into_account() + } + + pub fn get_did_identifier_from_ecdsa_key(public_key: ecdsa::Public) -> TestDidIdentifier { + MultiSigner::from(public_key).into_account() + } + + pub fn get_ed25519_authentication_key(default: bool) -> ed25519::Pair { + if default { + ed25519::Pair::from_seed(&DEFAULT_AUTH_SEED) } else { - #[cfg(feature = "runtime-benchmarks")] - if *self == Self::get_call_for_did_call_benchmark() { - // Always require an authentication key to dispatch calls during benchmarking - return Some(did::DidVerificationKeyRelationship::Authentication); - } - None + ed25519::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) } } - // Always return a System::remark() extrinsic call - #[cfg(feature = "runtime-benchmarks")] - fn get_call_for_did_call_benchmark() -> Self { - Call::System(frame_system::Call::remark(vec![])) + pub fn get_sr25519_authentication_key(default: bool) -> sr25519::Pair { + if default { + sr25519::Pair::from_seed(&DEFAULT_AUTH_SEED) + } else { + sr25519::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) + } } -} -pub fn generate_test_did_call( - verification_key_required: did::DidVerificationKeyRelationship, - caller: TestDidIdentifier, -) -> did::DidAuthorizedCallOperationWithVerificationRelationship { - let call = match verification_key_required { - DidVerificationKeyRelationship::AssertionMethod => get_attestation_key_call(), - DidVerificationKeyRelationship::Authentication => get_authentication_key_call(), - DidVerificationKeyRelationship::CapabilityDelegation => get_delegation_key_call(), - _ => get_none_key_call(), - }; - did::DidAuthorizedCallOperationWithVerificationRelationship { - operation: did::DidAuthorizedCallOperation { - did: caller, - call, - tx_counter: 1u64, - }, - verification_key_relationship: verification_key_required, + pub fn get_ecdsa_authentication_key(default: bool) -> ecdsa::Pair { + if default { + ecdsa::Pair::from_seed(&DEFAULT_AUTH_SEED) + } else { + ecdsa::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) + } } -} -#[allow(dead_code)] -pub fn initialize_logger() { - env_logger::builder().is_test(true).try_init(); -} + pub fn get_x25519_encryption_key(default: bool) -> DidEncryptionKey { + if default { + DidEncryptionKey::X25519(DEFAULT_ENC_SEED) + } else { + DidEncryptionKey::X25519(ALTERNATIVE_ENC_SEED) + } + } -#[derive(Clone)] -pub struct ExtBuilder { - dids_stored: Vec<(TestDidIdentifier, did::DidDetails)>, -} + pub fn get_ed25519_attestation_key(default: bool) -> ed25519::Pair { + if default { + ed25519::Pair::from_seed(&DEFAULT_ATT_SEED) + } else { + ed25519::Pair::from_seed(&ALTERNATIVE_ATT_SEED) + } + } -impl Default for ExtBuilder { - fn default() -> Self { - Self { dids_stored: vec![] } + pub fn get_sr25519_attestation_key(default: bool) -> sr25519::Pair { + if default { + sr25519::Pair::from_seed(&DEFAULT_ATT_SEED) + } else { + sr25519::Pair::from_seed(&ALTERNATIVE_ATT_SEED) + } } -} -impl ExtBuilder { - pub fn with_dids(mut self, dids: Vec<(TestDidIdentifier, did::DidDetails)>) -> Self { - self.dids_stored = dids; - self + pub fn get_ecdsa_attestation_key(default: bool) -> ecdsa::Pair { + if default { + ecdsa::Pair::from_seed(&DEFAULT_ATT_SEED) + } else { + ecdsa::Pair::from_seed(&ALTERNATIVE_ATT_SEED) + } } - pub fn build(self, ext: Option) -> sp_io::TestExternalities { - let mut ext = if let Some(ext) = ext { - ext + pub fn get_ed25519_delegation_key(default: bool) -> ed25519::Pair { + if default { + ed25519::Pair::from_seed(&DEFAULT_DEL_SEED) } else { - let storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); - sp_io::TestExternalities::new(storage) - }; + ed25519::Pair::from_seed(&ALTERNATIVE_DEL_SEED) + } + } - if !self.dids_stored.is_empty() { - ext.execute_with(|| { - self.dids_stored.iter().for_each(|did| { - did::Did::::insert(did.0.clone(), did.1.clone()); - }) - }); + pub fn get_sr25519_delegation_key(default: bool) -> sr25519::Pair { + if default { + sr25519::Pair::from_seed(&DEFAULT_DEL_SEED) + } else { + sr25519::Pair::from_seed(&ALTERNATIVE_DEL_SEED) } + } - ext + pub fn get_ecdsa_delegation_key(default: bool) -> ecdsa::Pair { + if default { + ecdsa::Pair::from_seed(&DEFAULT_DEL_SEED) + } else { + ecdsa::Pair::from_seed(&ALTERNATIVE_DEL_SEED) + } } - // allowance only required for clippy, this function is actually used - #[allow(dead_code)] - pub fn build_with_keystore(self, ext: Option) -> sp_io::TestExternalities { - let mut ext = self.build(ext); + pub fn generate_key_id(key: &did::DidPublicKey) -> TestKeyId { + utils::calculate_key_id::(key) + } - let keystore = KeyStore::new(); - ext.register_extension(KeystoreExt(Arc::new(keystore))); + pub(crate) fn get_attestation_key_test_input() -> TestCtypeHash { + TestCtypeHash::from_slice(&[0u8; 32]) + } + pub(crate) fn get_attestation_key_call() -> Call { + Call::Ctype(ctype::Call::add(get_attestation_key_test_input())) + } + pub(crate) fn get_authentication_key_test_input() -> TestCtypeHash { + TestCtypeHash::from_slice(&[1u8; 32]) + } + pub(crate) fn get_authentication_key_call() -> Call { + Call::Ctype(ctype::Call::add(get_authentication_key_test_input())) + } + pub(crate) fn get_delegation_key_test_input() -> TestCtypeHash { + TestCtypeHash::from_slice(&[2u8; 32]) + } + pub(crate) fn get_delegation_key_call() -> Call { + Call::Ctype(ctype::Call::add(get_delegation_key_test_input())) + } + pub(crate) fn get_none_key_test_input() -> TestCtypeHash { + TestCtypeHash::from_slice(&[3u8; 32]) + } + pub(crate) fn get_none_key_call() -> Call { + Call::Ctype(ctype::Call::add(get_none_key_test_input())) + } + + impl did::DeriveDidCallAuthorizationVerificationKeyRelationship for Call { + fn derive_verification_key_relationship(&self) -> Option { + if *self == get_attestation_key_call() { + Some(did::DidVerificationKeyRelationship::AssertionMethod) + } else if *self == get_authentication_key_call() { + Some(did::DidVerificationKeyRelationship::Authentication) + } else if *self == get_delegation_key_call() { + Some(did::DidVerificationKeyRelationship::CapabilityDelegation) + } else { + #[cfg(feature = "runtime-benchmarks")] + if *self == Self::get_call_for_did_call_benchmark() { + // Always require an authentication key to dispatch calls during benchmarking + return Some(did::DidVerificationKeyRelationship::Authentication); + } + None + } + } + + // Always return a System::remark() extrinsic call + #[cfg(feature = "runtime-benchmarks")] + fn get_call_for_did_call_benchmark() -> Self { + Call::System(frame_system::Call::remark(vec![])) + } + } + + pub fn generate_test_did_call( + verification_key_required: did::DidVerificationKeyRelationship, + caller: TestDidIdentifier, + ) -> did::DidAuthorizedCallOperationWithVerificationRelationship { + let call = match verification_key_required { + DidVerificationKeyRelationship::AssertionMethod => get_attestation_key_call(), + DidVerificationKeyRelationship::Authentication => get_authentication_key_call(), + DidVerificationKeyRelationship::CapabilityDelegation => get_delegation_key_call(), + _ => get_none_key_call(), + }; + did::DidAuthorizedCallOperationWithVerificationRelationship { + operation: did::DidAuthorizedCallOperation { + did: caller, + call, + tx_counter: 1u64, + }, + verification_key_relationship: verification_key_required, + } + } - ext + #[allow(unused_must_use)] + pub fn initialize_logger() { + env_logger::builder().is_test(true).try_init(); + } + + #[derive(Clone)] + pub struct ExtBuilder { + dids_stored: Vec<(TestDidIdentifier, did::DidDetails)>, + } + + impl Default for ExtBuilder { + fn default() -> Self { + Self { dids_stored: vec![] } + } + } + + impl ExtBuilder { + pub fn with_dids(mut self, dids: Vec<(TestDidIdentifier, did::DidDetails)>) -> Self { + self.dids_stored = dids; + self + } + + pub fn build(self, ext: Option) -> sp_io::TestExternalities { + let mut ext = if let Some(ext) = ext { + ext + } else { + let storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + sp_io::TestExternalities::new(storage) + }; + + if !self.dids_stored.is_empty() { + ext.execute_with(|| { + self.dids_stored.iter().for_each(|did| { + did::Did::::insert(did.0.clone(), did.1.clone()); + }) + }); + } + + ext + } + + // allowance only required for clippy, this function is actually used + #[allow(dead_code)] + pub fn build_with_keystore(self, ext: Option) -> sp_io::TestExternalities { + let mut ext = self.build(ext); + + let keystore = KeyStore::new(); + ext.register_extension(KeystoreExt(Arc::new(keystore))); + + ext + } } } diff --git a/pallets/did/src/tests.rs b/pallets/did/src/tests.rs index fc5563a768..0153f368fb 100644 --- a/pallets/did/src/tests.rs +++ b/pallets/did/src/tests.rs @@ -20,7 +20,11 @@ use frame_support::{assert_err, assert_noop, assert_ok, storage::bounded_btree_s use sp_core::*; use sp_std::{collections::btree_set::BTreeSet, convert::TryFrom}; -use crate::{self as did, mock::*, Config}; +use crate::{ + self as did, + mock::{std::*, *}, + Config, +}; use ctype::mock as ctype_mock; // create @@ -30,7 +34,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 +69,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 +104,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()); @@ -148,7 +152,7 @@ fn check_successful_complete_creation() { did::HttpUrl::try_from("https://new_kilt.io".as_bytes()) .expect("https://new_kilt.io should not be considered an invalid HTTP URL."), ); - let mut details = generate_base_did_creation_details(alice_did.clone()); + 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())); @@ -211,8 +215,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()); @@ -237,7 +241,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()); @@ -260,7 +264,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()); @@ -283,7 +287,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()); @@ -306,8 +310,9 @@ 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()); @@ -331,7 +336,7 @@ 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()); let url_endpoint = get_url_endpoint(::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); // Max length allowed + 1 details.new_endpoint_url = Some(url_endpoint); @@ -368,7 +373,7 @@ fn check_successful_complete_update() { .expect("https://new_kilt.io should not be considered an invalid HTTP URL."), ); - let mut old_did_details = generate_base_did_details(did::DidVerificationKey::from(old_auth_key.public())); + 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( BoundedBTreeSet::::MaxTotalKeyAgreementKeys>::try_from( vec![old_enc_key] @@ -383,7 +388,7 @@ fn check_successful_complete_update() { // 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 = BoundedBTreeSet::::MaxTotalKeyAgreementKeys>::try_from( @@ -474,12 +479,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())); + 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::DidVerificationKeyUpdateAction::Delete; details.delegation_key_update = did::DidVerificationKeyUpdateAction::Delete; @@ -526,10 +531,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::DidVerificationKeyUpdateAction::Change(did::DidVerificationKey::from(new_att_key.public())); @@ -580,11 +585,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())); + 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::DidVerificationKeyUpdateAction::Delete; let mut ext = ExtBuilder::default() @@ -621,8 +626,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); @@ -639,12 +644,13 @@ 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() @@ -667,13 +673,13 @@ 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() @@ -696,12 +702,12 @@ 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_endpoint_url = get_url_endpoint(::MaxUrlLength::get().saturating_add(1)); - let mut details = generate_base_did_update_details(); + let mut details = generate_base_did_update_details::(); details.new_endpoint_url = Some(new_endpoint_url); let mut ext = ExtBuilder::default() @@ -724,10 +730,10 @@ 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 = BoundedBTreeSet::::MaxOldAttestationKeys>::try_from( vec![generate_key_id( @@ -760,11 +766,11 @@ 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())); + 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 = BoundedBTreeSet::::MaxOldAttestationKeys>::try_from( vec![generate_key_id(&did::DidVerificationKey::from(del_key.public()).into())] @@ -795,11 +801,11 @@ 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())); + 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 = BoundedBTreeSet::::MaxOldAttestationKeys>::try_from( vec![generate_key_id(&did::DidVerificationKey::from(att_key.public()).into())] @@ -830,10 +836,10 @@ 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 = BoundedBTreeSet::::MaxOldAttestationKeys>::try_from( vec![generate_key_id( @@ -866,7 +872,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)]) @@ -879,7 +885,7 @@ fn check_successful_deletion() { 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()); @@ -940,7 +946,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() @@ -967,7 +973,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() @@ -995,7 +1001,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())]) @@ -1022,7 +1028,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())]) @@ -1049,7 +1055,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)]) @@ -1078,7 +1084,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)]) @@ -1105,7 +1111,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)]) @@ -1133,7 +1139,7 @@ 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())); + 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() @@ -1159,7 +1165,7 @@ 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())); + 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() @@ -1192,7 +1198,7 @@ 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())); + 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() @@ -1218,7 +1224,7 @@ 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())); + 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() @@ -1250,7 +1256,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)]) @@ -1274,7 +1280,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)]) @@ -1331,7 +1337,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())]) @@ -1362,7 +1368,7 @@ 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())); + 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() @@ -1394,7 +1400,7 @@ 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())); + 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() @@ -1446,7 +1452,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() @@ -1473,7 +1479,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 = @@ -1499,7 +1505,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()); @@ -1524,7 +1530,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()); @@ -1549,7 +1555,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()); @@ -1576,7 +1582,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()); @@ -1601,7 +1607,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()); From ebe38e32b2a06450c8ea1c1f2fce81665ff4b91a Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 5 Aug 2021 15:28:28 +0200 Subject: [PATCH 19/37] fix: clippy --- pallets/attestation/src/lib.rs | 2 -- pallets/delegation/src/benchmarking.rs | 2 +- pallets/delegation/src/mock.rs | 2 +- pallets/parachain-staking/src/migrations.rs | 5 +++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pallets/attestation/src/lib.rs b/pallets/attestation/src/lib.rs index b9eda60cc1..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; diff --git a/pallets/delegation/src/benchmarking.rs b/pallets/delegation/src/benchmarking.rs index fdc7e61d54..d03dcc180d 100644 --- a/pallets/delegation/src/benchmarking.rs +++ b/pallets/delegation/src/benchmarking.rs @@ -23,7 +23,7 @@ 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::*; diff --git a/pallets/delegation/src/mock.rs b/pallets/delegation/src/mock.rs index 2b0a166398..bf0154b5ac 100644 --- a/pallets/delegation/src/mock.rs +++ b/pallets/delegation/src/mock.rs @@ -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; diff --git a/pallets/parachain-staking/src/migrations.rs b/pallets/parachain-staking/src/migrations.rs index e94f0245ba..ceb56ed944 100644 --- a/pallets/parachain-staking/src/migrations.rs +++ b/pallets/parachain-staking/src/migrations.rs @@ -15,8 +15,9 @@ // 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 frame_support::{dispatch::Weight, ensure, traits::Get}; +#[cfg(feature = "try-runtime")] +use frame_support::ensure; +use frame_support::{dispatch::Weight, traits::Get}; use sp_runtime::{ codec::{Decode, Encode}, traits::Zero, From 00f8d8045e61f5552d88ebdd7cd4388bbcb060ab Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Thu, 5 Aug 2021 16:13:01 +0200 Subject: [PATCH 20/37] docs: improve insertion attempt comments --- pallets/parachain-staking/src/lib.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 6910d6fbfa..71ad983056 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -1063,6 +1063,8 @@ pub mod pallet { ); // 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 .insert(Stake { owner: acc.clone(), @@ -1256,6 +1258,8 @@ pub mod pallet { ); // 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 .insert(Stake { owner: acc.clone(), @@ -1469,7 +1473,9 @@ pub mod pallet { amount, }; - // attempt to insert delegator and check for uniqueness, excess is handled below + // 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 @@ -1582,8 +1588,9 @@ pub mod pallet { let num_delegations_pre_insertion: u32 = state.delegators.len().saturated_into(); ensure!(!state.is_leaving(), Error::::CannotDelegateIfLeaving); - // throws if delegation insertion exceeds bounded vec limit which we will handle - // below in Self::do_update_delegator + // 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 { From 0553b909bdaeabe2c9610a81202f1790a8be732f Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Fri, 6 Aug 2021 16:19:03 +0200 Subject: [PATCH 21/37] fix: incorrect names in Debug --- pallets/did/src/did_details.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pallets/did/src/did_details.rs b/pallets/did/src/did_details.rs index 002a8502c2..4f7b32d73c 100644 --- a/pallets/did/src/did_details.rs +++ b/pallets/did/src/did_details.rs @@ -656,7 +656,7 @@ pub struct DidCreationDetails { // #[cfg(not(feature = "std"))] impl fmt::Debug for DidCreationDetails { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("DidCreationOperation") + f.debug_tuple("DidCreationDetails") .field(&self.did) .field(&self.new_key_agreement_keys.clone().into_inner()) .field(&self.new_attestation_key) @@ -691,7 +691,7 @@ pub struct DidUpdateDetails { // #[cfg(not(feature = "std"))] impl fmt::Debug for DidUpdateDetails { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("DidUpdateOperation") + f.debug_tuple("DidUpdateDetails") .field(&self.new_authentication_key) .field(&self.new_key_agreement_keys.clone().into_inner()) .field(&self.attestation_key_update) From f1dac509d8a4e798ea0437bc134ca8b8999f6dcf Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 9 Aug 2021 10:26:05 +0200 Subject: [PATCH 22/37] refactor: remove redundant isCandidate check --- pallets/parachain-staking/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 71ad983056..7429c6a8c8 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -1044,7 +1044,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(), From 080c93f0b55d07dbd3f3ce3e86c9b1cee6b96bea Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 9 Aug 2021 15:04:28 +0200 Subject: [PATCH 23/37] fix: migrate Url to BoundedVec --- pallets/did/src/benchmarking.rs | 12 ++-- pallets/did/src/did_details.rs | 55 +++++++++------- pallets/did/src/errors.rs | 6 ++ pallets/did/src/lib.rs | 2 +- pallets/did/src/mock.rs | 9 ++- pallets/did/src/tests.rs | 110 +++++++++++++++---------------- pallets/did/src/url.rs | 112 +++++++++++++++++++++----------- runtimes/peregrine/src/lib.rs | 1 + runtimes/standalone/src/lib.rs | 1 + 9 files changed, 179 insertions(+), 129 deletions(-) diff --git a/pallets/did/src/benchmarking.rs b/pallets/did/src/benchmarking.rs index 0033c157b4..069881b332 100644 --- a/pallets/did/src/benchmarking.rs +++ b/pallets/did/src/benchmarking.rs @@ -107,7 +107,7 @@ benchmarks! { 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 did_endpoint = get_url_endpoint(u); + let did_endpoint = get_url_endpoint::(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; @@ -156,7 +156,7 @@ benchmarks! { 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 did_endpoint = get_url_endpoint(u); + let did_endpoint = get_url_endpoint::(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; @@ -205,7 +205,7 @@ benchmarks! { 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 did_endpoint = get_url_endpoint(u); + let did_endpoint = get_url_endpoint::(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; @@ -263,7 +263,7 @@ benchmarks! { 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 new_url = get_url_endpoint(u); + let new_url = get_url_endpoint::(u); let mut did_update_details = generate_base_did_update_details::(); did_update_details.new_authentication_key = Some(DidVerificationKey::from(new_did_public_auth_key)); @@ -324,7 +324,7 @@ benchmarks! { 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 new_url = get_url_endpoint(u); + let new_url = get_url_endpoint::(u); let mut did_update_details = generate_base_did_update_details::(); did_update_details.new_authentication_key = Some(DidVerificationKey::from(new_did_public_auth_key)); @@ -385,7 +385,7 @@ benchmarks! { 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 new_url = get_url_endpoint(u); + let new_url = get_url_endpoint::(u); 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())); diff --git a/pallets/did/src/did_details.rs b/pallets/did/src/did_details.rs index 4f7b32d73c..7b90a102ca 100644 --- a/pallets/did/src/did_details.rs +++ b/pallets/did/src/did_details.rs @@ -246,7 +246,7 @@ pub struct DidDetails { public_keys: BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDidKeyIdentifier>, /// \[OPTIONAL\] The URL pointing to the service endpoints the DID /// subject publicly exposes. - pub endpoint_url: Option, + pub endpoint_url: Option>, /// The counter used to avoid replay attacks, which is checked and /// updated upon each DID operation involving with the subject as the /// creator. @@ -425,7 +425,7 @@ 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: BoundedBTreeSet, + new_key_agreement_keys: KeyAgreementKeys, block_number: BlockNumberOf, ) -> Result<(), StorageError> { for new_key_agreement_key in new_key_agreement_keys { @@ -636,32 +636,35 @@ impl DidDetails { } } +pub(crate) type KeyAgreementKeys = BoundedBTreeSet::MaxTotalKeyAgreementKeys>; + /// The details of a new DID to create. #[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: BoundedBTreeSet, + pub new_key_agreement_keys: KeyAgreementKeys, /// \[OPTIONAL\] The new attestation key. pub new_attestation_key: Option, /// \[OPTIONAL\] The new delegation key. pub new_delegation_key: Option, /// \[OPTIONAL\] The URL containing the DID endpoints description. - pub new_endpoint_url: Option, + pub new_endpoint_url: Option>, } // required because BoundedTreeSet does not implement Debug outside of std -// FIXME: Can we derive Debug and use custom impl only in std? -// #[cfg(not(feature = "std"))] impl fmt::Debug for DidCreationDetails { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("DidCreationDetails") - .field(&self.did) - .field(&self.new_key_agreement_keys.clone().into_inner()) - .field(&self.new_attestation_key) - .field(&self.new_delegation_key) - .field(&self.new_endpoint_url) + 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_endpoint_url", &self.new_endpoint_url) .finish() } } @@ -672,7 +675,7 @@ 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: BoundedBTreeSet, + pub new_key_agreement_keys: KeyAgreementKeys, /// \[OPTIONAL\] The attestation key update action. pub attestation_key_update: DidVerificationKeyUpdateAction, /// \[OPTIONAL\] The delegation key update action. @@ -683,21 +686,25 @@ pub struct DidUpdateDetails { /// possible to specify it for removal in this set. pub public_keys_to_remove: BoundedBTreeSet, T::MaxOldAttestationKeys>, /// \[OPTIONAL\] The new endpoint URL. - pub new_endpoint_url: Option, + pub new_endpoint_url: Option>, } -// required because BoundedTreeSet does not implement Debug outside of std -// FIXME: Can we derive Debug and use custom impl only in std? -// #[cfg(not(feature = "std"))] +// 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_tuple("DidUpdateDetails") - .field(&self.new_authentication_key) - .field(&self.new_key_agreement_keys.clone().into_inner()) - .field(&self.attestation_key_update) - .field(&self.delegation_key_update) - .field(&self.public_keys_to_remove.clone().into_inner()) - .field(&self.new_endpoint_url) + 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("new_endpoint_url", &self.new_endpoint_url) .finish() } } diff --git a/pallets/did/src/errors.rs b/pallets/did/src/errors.rs index 358c73ac22..3c99cef876 100644 --- a/pallets/did/src/errors.rs +++ b/pallets/did/src/errors.rs @@ -45,6 +45,12 @@ impl From for DidError { } } +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 { diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index 03ccf7d840..2633292457 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -212,7 +212,7 @@ pub mod pallet { /// 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; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; diff --git a/pallets/did/src/mock.rs b/pallets/did/src/mock.rs index 6fdc600ea0..fe67ec1a2c 100644 --- a/pallets/did/src/mock.rs +++ b/pallets/did/src/mock.rs @@ -28,9 +28,7 @@ use sp_std::{ pub(crate) const DEFAULT_URL_SCHEME: [u8; 8] = *b"https://"; -pub fn get_key_agreement_keys( - n_keys: u32, -) -> BoundedBTreeSet { +pub fn get_key_agreement_keys(n_keys: u32) -> KeyAgreementKeys { BoundedBTreeSet::try_from( (1..=n_keys) .map(|i| { @@ -66,11 +64,11 @@ pub fn get_public_keys(n_keys: u32) -> BoundedBTreeSet, T: } // Assumes that the length of the URL is larger than 8 (length of the prefix https://) -pub fn get_url_endpoint(length: u32) -> Url { +pub fn get_url_endpoint(length: u32) -> Url { let total_length = usize::try_from(length).expect("Failed to convert URL max length value to usize value."); let mut url_encoded_string = DEFAULT_URL_SCHEME.to_vec(); url_encoded_string.resize(total_length, b'0'); - Url::Http( + Url::::Http( HttpUrl::try_from(url_encoded_string.as_ref()).expect("Failed to create default URL with provided length."), ) } @@ -179,6 +177,7 @@ pub mod std { 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 MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; diff --git a/pallets/did/src/tests.rs b/pallets/did/src/tests.rs index 0153f368fb..e9ff017c71 100644 --- a/pallets/did/src/tests.rs +++ b/pallets/did/src/tests.rs @@ -23,7 +23,7 @@ use sp_std::{collections::btree_set::BTreeSet, convert::TryFrom}; use crate::{ self as did, mock::{std::*, *}, - Config, + Config, DidError, FtpUrl, HttpUrl, IpfsUrl, }; use ctype::mock as ctype_mock; @@ -149,7 +149,7 @@ fn check_successful_complete_creation() { let del_key = get_sr25519_delegation_key(true); let att_key = get_ecdsa_attestation_key(true); let new_url = did::Url::from( - did::HttpUrl::try_from("https://new_kilt.io".as_bytes()) + HttpUrl::::try_from("https://new_kilt.io".as_bytes()) .expect("https://new_kilt.io should not be considered an invalid HTTP URL."), ); let mut details = generate_base_did_creation_details::(alice_did.clone()); @@ -335,7 +335,7 @@ fn check_max_limit_key_agreement_keys_did_creation() { 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()); - let url_endpoint = get_url_endpoint(::MaxUrlLength::get().saturating_add(1)); + let url_endpoint = get_url_endpoint::(::MaxUrlLength::get().saturating_add(1)); let mut details = generate_base_did_creation_details::(alice_did); // Max length allowed + 1 details.new_endpoint_url = Some(url_endpoint); @@ -369,7 +369,7 @@ fn check_successful_complete_update() { let new_att_key = get_ed25519_attestation_key(false); let new_del_key = get_sr25519_delegation_key(true); let new_url = did::Url::from( - did::HttpUrl::try_from("https://new_kilt.io".as_bytes()) + HttpUrl::::try_from("https://new_kilt.io".as_bytes()) .expect("https://new_kilt.io should not be considered an invalid HTTP URL."), ); @@ -705,7 +705,7 @@ fn check_url_too_long_did_update() { let old_did_details = generate_base_did_details::(did::DidVerificationKey::from(auth_key.public())); // Max URL length allowed + 1 - let new_endpoint_url = get_url_endpoint(::MaxUrlLength::get().saturating_add(1)); + let new_endpoint_url = get_url_endpoint::(::MaxUrlLength::get().saturating_add(1)); let mut details = generate_base_did_update_details::(); details.new_endpoint_url = Some(new_endpoint_url); @@ -1442,7 +1442,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) ); }); } @@ -1469,7 +1469,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) ); }); } @@ -1495,7 +1495,7 @@ fn check_smaller_counter_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::SignatureError(did::SignatureError::InvalidNonce) + DidError::SignatureError(did::SignatureError::InvalidNonce) ); }); } @@ -1520,7 +1520,7 @@ fn check_equal_counter_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::SignatureError(did::SignatureError::InvalidNonce) + DidError::SignatureError(did::SignatureError::InvalidNonce) ); }); } @@ -1545,7 +1545,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) ); }); } @@ -1568,7 +1568,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 )) ); @@ -1595,7 +1595,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) ); }); } @@ -1620,7 +1620,7 @@ fn check_invalid_signature_operation_verification() { &call_operation, &did::DidSignature::from(signature) ), - did::DidError::SignatureError(did::SignatureError::InvalidSignature) + DidError::SignatureError(did::SignatureError::InvalidSignature) ); }); } @@ -1629,48 +1629,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)) ); } @@ -1678,48 +1678,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)) ); } @@ -1728,33 +1728,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 fce28957dc..5a2965ec23 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, vec::Vec}; +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://"; @@ -32,15 +37,25 @@ pub const FTPS_URI_SCHEME: &str = "ftps://"; /// The expected URI scheme for IPFS endpoints. pub const IPFS_URI_SCHEME: &str = "ipfs://"; +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)] -pub struct HttpUrl { - payload: Vec, +#[derive(Clone, Decode, Encode, PartialEq)] +pub struct HttpUrl { + payload: UrlPayload, } -impl TryFrom<&[u8]> for HttpUrl { - type Error = UrlError; +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 = 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. @@ -54,21 +69,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)] -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. @@ -82,20 +106,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)] -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. @@ -116,28 +149,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)] -pub enum Url { +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() } @@ -145,20 +181,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/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index 99b9507fa2..41d0466607 100644 --- a/runtimes/peregrine/src/lib.rs +++ b/runtimes/peregrine/src/lib.rs @@ -695,6 +695,7 @@ 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; // TODO: Find reasonable numbers pub const MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index 6230e98bb4..82be546174 100644 --- a/runtimes/standalone/src/lib.rs +++ b/runtimes/standalone/src/lib.rs @@ -373,6 +373,7 @@ 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; // TODO: Find reasonable numbers pub const MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; From b90ed76f0a15f2cc9a30bbdb26f0593222eafbb0 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Mon, 9 Aug 2021 17:16:29 +0200 Subject: [PATCH 24/37] refactor: MaxPublicKeysPerDid --- pallets/did/src/benchmarking.rs | 2 +- pallets/did/src/deprecated.rs | 10 +++------- pallets/did/src/did_details.rs | 19 ++++++++----------- pallets/did/src/errors.rs | 2 +- pallets/did/src/lib.rs | 8 +++----- pallets/did/src/mock.rs | 4 ++-- runtimes/peregrine/src/lib.rs | 4 ++-- runtimes/standalone/src/lib.rs | 4 ++-- 8 files changed, 22 insertions(+), 31 deletions(-) diff --git a/pallets/did/src/benchmarking.rs b/pallets/did/src/benchmarking.rs index ab6a0b8a2a..758bfa0379 100644 --- a/pallets/did/src/benchmarking.rs +++ b/pallets/did/src/benchmarking.rs @@ -20,7 +20,7 @@ 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}; +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}; diff --git a/pallets/did/src/deprecated.rs b/pallets/did/src/deprecated.rs index 895246cf92..cdf45ea3f6 100644 --- a/pallets/did/src/deprecated.rs +++ b/pallets/did/src/deprecated.rs @@ -29,8 +29,7 @@ pub(crate) mod v1 { pub(crate) key_agreement_keys: BoundedBTreeSet, pub(crate) delegation_key: Option>, pub(crate) attestation_key: Option>, - pub(crate) public_keys: - BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDidKeyIdentifier>, + pub(crate) public_keys: BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDid>, pub(crate) endpoint_url: Option>, pub(crate) last_tx_counter: u64, } @@ -38,11 +37,8 @@ pub(crate) mod v1 { #[cfg(test)] impl DidDetails { pub(crate) fn new(authentication_key: DidVerificationKey, block_number: BlockNumberOf) -> Self { - let mut public_keys: BoundedBTreeMap< - KeyIdOf, - DidPublicKeyDetails, - T::MaxPublicKeysPerDidKeyIdentifier, - > = BoundedBTreeMap::default(); + let mut public_keys: BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDid> = + BoundedBTreeMap::default(); let authentication_key_id = utils::calculate_key_id::(&authentication_key.clone().into()); public_keys .try_insert( diff --git a/pallets/did/src/did_details.rs b/pallets/did/src/did_details.rs index 380aab415f..ab443027cd 100644 --- a/pallets/did/src/did_details.rs +++ b/pallets/did/src/did_details.rs @@ -247,7 +247,7 @@ 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: BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDidKeyIdentifier>, + pub(crate) public_keys: BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDid>, /// \[OPTIONAL\] The service endpoint details the DID /// subject publicly exposes. pub service_endpoints: Option>, @@ -263,8 +263,7 @@ impl DidDetails { /// /// The tx counter is automatically set to 0. pub fn new(authentication_key: DidVerificationKey, block_number: BlockNumberOf) -> Result { - let mut public_keys = - BoundedBTreeMap::, DidPublicKeyDetails, T::MaxPublicKeysPerDidKeyIdentifier>::new(); + let mut public_keys = BoundedBTreeMap::, DidPublicKeyDetails, T::MaxPublicKeysPerDid>::new(); let authentication_key_id = utils::calculate_key_id::(&authentication_key.clone().into()); public_keys .try_insert( @@ -274,7 +273,7 @@ impl DidDetails { block_number, }, ) - .map_err(|_| StorageError::MaxPublicKeysPerDidKeyIdentifierExceeded)?; + .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; Ok(Self { authentication_key: authentication_key_id, key_agreement_keys: BoundedBTreeSet::, T::MaxTotalKeyAgreementKeys>::new(), @@ -420,7 +419,7 @@ impl DidDetails { block_number, }, ) - .map_err(|_| StorageError::MaxPublicKeysPerDidKeyIdentifierExceeded)?; + .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; Ok(()) } @@ -442,7 +441,7 @@ impl DidDetails { block_number, }, ) - .map_err(|_| StorageError::MaxPublicKeysPerDidKeyIdentifierExceeded)?; + .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; self.key_agreement_keys .try_insert(new_key_agreement_id) .map_err(|_| StorageError::MaxTotalKeyAgreementKeysExceeded)?; @@ -470,7 +469,7 @@ impl DidDetails { block_number, }, ) - .map_err(|_| StorageError::MaxPublicKeysPerDidKeyIdentifierExceeded)?; + .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; Ok(()) } @@ -507,7 +506,7 @@ impl DidDetails { block_number, }, ) - .map_err(|_| StorageError::MaxPublicKeysPerDidKeyIdentifierExceeded)?; + .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; Ok(()) } @@ -592,9 +591,7 @@ impl DidDetails { &self.delegation_key } - pub fn get_public_keys( - &self, - ) -> &BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDidKeyIdentifier> { + pub fn get_public_keys(&self) -> &BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDid> { &self.public_keys } diff --git a/pallets/did/src/errors.rs b/pallets/did/src/errors.rs index 07336e329f..606fae4bf4 100644 --- a/pallets/did/src/errors.rs +++ b/pallets/did/src/errors.rs @@ -72,7 +72,7 @@ pub enum StorageError { MaxTxCounterValue, /// The maximum number of public keys for this DID key identifier has /// been reached. - MaxPublicKeysPerDidKeyIdentifierExceeded, + MaxPublicKeysPerDidExceeded, /// The maximum number of key agreements has been reached for the DID /// subject. MaxTotalKeyAgreementKeysExceeded, diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index 44f3b62c3b..c0d41990f8 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -194,7 +194,7 @@ pub mod pallet { /// contains old attestation keys which cannot issue new attestations /// but can still be used to verify previously issued attestations. #[pallet::constant] - type MaxPublicKeysPerDidKeyIdentifier: Get; + type MaxPublicKeysPerDid: Get; /// Maximum number of key agreement keys that can be added in a creation /// or update operation. @@ -325,7 +325,7 @@ pub mod pallet { InternalError, /// The maximum number of public keys for this DID key identifier has /// been reached. - MaxPublicKeysPerDidKeyIdentifierExceeded, + MaxPublicKeysPerDidExceeded, /// The maximum number of key agreements has been reached for the DID /// subject. MaxTotalKeyAgreementKeysExceeded, @@ -356,9 +356,7 @@ pub mod pallet { } StorageError::MaxTxCounterValue => Self::MaxTxCounterValue, StorageError::CurrentlyActiveKey => Self::CurrentlyActiveKey, - StorageError::MaxPublicKeysPerDidKeyIdentifierExceeded => { - Self::MaxPublicKeysPerDidKeyIdentifierExceeded - } + StorageError::MaxPublicKeysPerDidExceeded => Self::MaxPublicKeysPerDidExceeded, StorageError::MaxTotalKeyAgreementKeysExceeded => Self::MaxTotalKeyAgreementKeysExceeded, StorageError::MaxOldAttestationKeysExceeded => Self::MaxOldAttestationKeysExceeded, } diff --git a/pallets/did/src/mock.rs b/pallets/did/src/mock.rs index 0137b620e4..1339cd6b07 100644 --- a/pallets/did/src/mock.rs +++ b/pallets/did/src/mock.rs @@ -190,7 +190,7 @@ pub mod std { #[derive(Debug, Clone, PartialEq)] pub const MaxUrlLength: u32 = 200u32; #[derive(Debug, Clone)] - pub const MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; + pub const MaxPublicKeysPerDid: u32 = 1000; #[derive(Debug, Clone, PartialEq)] pub const MaxTotalKeyAgreementKeys: u32 = 1000; #[derive(Debug, Clone, PartialEq)] @@ -208,7 +208,7 @@ pub mod std { type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; type MaxOldAttestationKeys = MaxOldAttestationKeys; - type MaxPublicKeysPerDidKeyIdentifier = MaxPublicKeysPerDidKeyIdentifier; + type MaxPublicKeysPerDid = MaxPublicKeysPerDid; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; type MaxEndpointUrlsCount = MaxEndpointUrlsCount; diff --git a/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index c35db7eaf4..263428e05d 100644 --- a/runtimes/peregrine/src/lib.rs +++ b/runtimes/peregrine/src/lib.rs @@ -698,7 +698,7 @@ parameter_types! { #[derive(Debug, Clone, PartialEq)] pub const MaxUrlLength: u32 = 200u32; // TODO: Find reasonable numbers - pub const MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; + pub const MaxPublicKeysPerDid: u32 = 1000; #[derive(Debug, Clone, PartialEq)] pub const MaxTotalKeyAgreementKeys: u32 = 1000; #[derive(Debug, Clone, PartialEq)] @@ -719,7 +719,7 @@ impl did::Config for Runtime { type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; type MaxOldAttestationKeys = MaxOldAttestationKeys; - type MaxPublicKeysPerDidKeyIdentifier = MaxPublicKeysPerDidKeyIdentifier; + type MaxPublicKeysPerDid = MaxPublicKeysPerDid; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; type MaxEndpointUrlsCount = MaxEndpointUrlsCount; diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index d0f3f8b291..e1703e26bc 100644 --- a/runtimes/standalone/src/lib.rs +++ b/runtimes/standalone/src/lib.rs @@ -376,7 +376,7 @@ parameter_types! { #[derive(Debug, Clone, PartialEq)] pub const MaxUrlLength: u32 = 200u32; // TODO: Find reasonable numbers - pub const MaxPublicKeysPerDidKeyIdentifier: u32 = 1000; + pub const MaxPublicKeysPerDid: u32 = 1000; #[derive(Debug, Clone, PartialEq)] pub const MaxTotalKeyAgreementKeys: u32 = 1000; #[derive(Debug, Clone, PartialEq)] @@ -397,7 +397,7 @@ impl did::Config for Runtime { type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; type MaxOldAttestationKeys = MaxOldAttestationKeys; - type MaxPublicKeysPerDidKeyIdentifier = MaxPublicKeysPerDidKeyIdentifier; + type MaxPublicKeysPerDid = MaxPublicKeysPerDid; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; type MaxEndpointUrlsCount = MaxEndpointUrlsCount; From a807d3f6c695076aa8be9b1afda6381982343b5f Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 10:25:28 +0200 Subject: [PATCH 25/37] fix: bounds for did structs --- pallets/did/src/benchmarking.rs | 12 +++++----- pallets/did/src/deprecated.rs | 10 ++++----- pallets/did/src/did_details.rs | 25 ++++++++++++--------- pallets/did/src/errors.rs | 3 --- pallets/did/src/lib.rs | 10 --------- pallets/did/src/migrations/v1.rs | 5 ++++- pallets/did/src/mock.rs | 7 ++---- pallets/did/src/tests.rs | 38 +++++++++++++++++--------------- runtimes/peregrine/src/lib.rs | 3 --- runtimes/standalone/src/lib.rs | 3 --- 10 files changed, 51 insertions(+), 65 deletions(-) diff --git a/pallets/did/src/benchmarking.rs b/pallets/did/src/benchmarking.rs index 758bfa0379..eb8cec7d69 100644 --- a/pallets/did/src/benchmarking.rs +++ b/pallets/did/src/benchmarking.rs @@ -254,8 +254,8 @@ 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 = generate_base_did_details::(DidVerificationKey::from(did_public_auth_key)); assert_ok!(did_details.add_key_agreement_keys(did_key_agreement_keys, BlockNumberOf::::default())); @@ -316,8 +316,8 @@ 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 = generate_base_did_details::(DidVerificationKey::from(did_public_auth_key)); assert_ok!(did_details.add_key_agreement_keys(did_key_agreement_keys, BlockNumberOf::::default())); @@ -378,8 +378,8 @@ 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 = 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())); diff --git a/pallets/did/src/deprecated.rs b/pallets/did/src/deprecated.rs index cdf45ea3f6..538c761daa 100644 --- a/pallets/did/src/deprecated.rs +++ b/pallets/did/src/deprecated.rs @@ -18,7 +18,6 @@ pub(crate) mod v1 { use codec::{Decode, Encode}; - use frame_support::storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet}; use crate::*; @@ -26,10 +25,10 @@ pub(crate) mod v1 { #[derive(Clone, Decode, Encode, PartialEq)] pub struct DidDetails { pub(crate) authentication_key: KeyIdOf, - pub(crate) key_agreement_keys: BoundedBTreeSet, + pub(crate) key_agreement_keys: DidTotalKeyAgreementKeys, pub(crate) delegation_key: Option>, pub(crate) attestation_key: Option>, - pub(crate) public_keys: BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDid>, + pub(crate) public_keys: DidPublicKeyMap, pub(crate) endpoint_url: Option>, pub(crate) last_tx_counter: u64, } @@ -37,8 +36,7 @@ pub(crate) mod v1 { #[cfg(test)] impl DidDetails { pub(crate) fn new(authentication_key: DidVerificationKey, block_number: BlockNumberOf) -> Self { - let mut public_keys: BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDid> = - BoundedBTreeMap::default(); + let mut public_keys = DidPublicKeyMap::::default(); let authentication_key_id = utils::calculate_key_id::(&authentication_key.clone().into()); public_keys .try_insert( @@ -51,7 +49,7 @@ pub(crate) mod v1 { .expect("Should not exceed BoundedBTreeMap bounds when setting public keys"); Self { authentication_key: authentication_key_id, - key_agreement_keys: BoundedBTreeSet::::default(), + key_agreement_keys: DidTotalKeyAgreementKeys::::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 ab443027cd..ed70d2c45e 100644 --- a/pallets/did/src/did_details.rs +++ b/pallets/did/src/did_details.rs @@ -231,7 +231,7 @@ pub struct DidDetails { 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: BoundedBTreeSet, T::MaxTotalKeyAgreementKeys>, + pub(crate) key_agreement_keys: DidTotalKeyAgreementKeys, /// \[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>, @@ -247,7 +247,7 @@ 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: BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDid>, + pub(crate) public_keys: DidPublicKeyMap, /// \[OPTIONAL\] The service endpoint details the DID /// subject publicly exposes. pub service_endpoints: Option>, @@ -263,7 +263,7 @@ impl DidDetails { /// /// The tx counter is automatically set to 0. pub fn new(authentication_key: DidVerificationKey, block_number: BlockNumberOf) -> Result { - let mut public_keys = BoundedBTreeMap::, DidPublicKeyDetails, T::MaxPublicKeysPerDid>::new(); + let mut public_keys = DidPublicKeyMap::::default(); let authentication_key_id = utils::calculate_key_id::(&authentication_key.clone().into()); public_keys .try_insert( @@ -276,7 +276,7 @@ impl DidDetails { .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; Ok(Self { authentication_key: authentication_key_id, - key_agreement_keys: BoundedBTreeSet::, T::MaxTotalKeyAgreementKeys>::new(), + key_agreement_keys: DidTotalKeyAgreementKeys::::default(), attestation_key: None, delegation_key: None, service_endpoints: None, @@ -428,7 +428,7 @@ 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: KeyAgreementKeys, + new_key_agreement_keys: DidNewKeyAgreementKeys, block_number: BlockNumberOf, ) -> Result<(), StorageError> { for new_key_agreement_key in new_key_agreement_keys { @@ -591,7 +591,7 @@ impl DidDetails { &self.delegation_key } - pub fn get_public_keys(&self) -> &BoundedBTreeMap, DidPublicKeyDetails, T::MaxPublicKeysPerDid> { + pub fn get_public_keys(&self) -> &DidPublicKeyMap { &self.public_keys } @@ -637,7 +637,12 @@ impl DidDetails { } } -pub(crate) type KeyAgreementKeys = BoundedBTreeSet::MaxTotalKeyAgreementKeys>; +pub(crate) type DidNewKeyAgreementKeys = BoundedBTreeSet::MaxNewKeyAgreementKeys>; +pub(crate) type DidTotalKeyAgreementKeys = 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, Decode, Encode, PartialEq)] @@ -645,7 +650,7 @@ pub struct DidCreationDetails { /// The DID identifier. It has to be unique. pub did: DidIdentifierOf, /// The new key agreement keys. - pub new_key_agreement_keys: KeyAgreementKeys, + pub new_key_agreement_keys: DidNewKeyAgreementKeys, /// \[OPTIONAL\] The new attestation key. pub new_attestation_key: Option, /// \[OPTIONAL\] The new delegation key. @@ -676,7 +681,7 @@ 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: KeyAgreementKeys, + pub new_key_agreement_keys: DidNewKeyAgreementKeys, /// \[OPTIONAL\] The attestation key update action. pub attestation_key_update: DidFragmentUpdateAction, /// \[OPTIONAL\] The delegation key update action. @@ -685,7 +690,7 @@ 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: BoundedBTreeSet, T::MaxOldAttestationKeys>, + pub public_keys_to_remove: DidVerificationKeysToRevoke, /// The update action on the service endpoints information. pub service_endpoints_update: DidFragmentUpdateAction>, } diff --git a/pallets/did/src/errors.rs b/pallets/did/src/errors.rs index 606fae4bf4..08afcd2b0c 100644 --- a/pallets/did/src/errors.rs +++ b/pallets/did/src/errors.rs @@ -76,9 +76,6 @@ pub enum StorageError { /// The maximum number of key agreements has been reached for the DID /// subject. MaxTotalKeyAgreementKeysExceeded, - /// The maximum number of old attestation keys still stored for - /// attestation verification has been reached. - MaxOldAttestationKeysExceeded, } /// Error generated when validating a DID operation. diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index c0d41990f8..28d5f2e980 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -212,12 +212,6 @@ pub mod pallet { #[pallet::constant] type MaxVerificationKeysToRevoke: Get; - /// Maximum number of old attestation keys which can still be used to - /// verify previously issued attestations but cannot create new - /// attestations. - #[pallet::constant] - type MaxOldAttestationKeys: Get + Debug + Clone + PartialEq; - /// Maximum length in ASCII characters of the endpoint URL specified in /// a creation or update operation. #[pallet::constant] @@ -329,9 +323,6 @@ pub mod pallet { /// The maximum number of key agreements has been reached for the DID /// subject. MaxTotalKeyAgreementKeysExceeded, - /// The maximum number of old attestation keys still stored for - /// attestation verification has been reached. - MaxOldAttestationKeysExceeded, } impl From for Error { @@ -358,7 +349,6 @@ pub mod pallet { StorageError::CurrentlyActiveKey => Self::CurrentlyActiveKey, StorageError::MaxPublicKeysPerDidExceeded => Self::MaxPublicKeysPerDidExceeded, StorageError::MaxTotalKeyAgreementKeysExceeded => Self::MaxTotalKeyAgreementKeysExceeded, - StorageError::MaxOldAttestationKeysExceeded => Self::MaxOldAttestationKeysExceeded, } } } diff --git a/pallets/did/src/migrations/v1.rs b/pallets/did/src/migrations/v1.rs index 66ce50ca26..0bfc604b81 100644 --- a/pallets/did/src/migrations/v1.rs +++ b/pallets/did/src/migrations/v1.rs @@ -88,6 +88,7 @@ mod tests { use super::*; use crate::mock::std::Test as TestRuntime; use mock::std::{get_did_identifier_from_ed25519_key, get_ed25519_authentication_key, ExtBuilder}; + use sp_std::convert::TryFrom; #[test] fn fail_version_higher() { @@ -168,7 +169,9 @@ mod tests { 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 1339cd6b07..650a2313ca 100644 --- a/pallets/did/src/mock.rs +++ b/pallets/did/src/mock.rs @@ -31,7 +31,7 @@ use sp_std::{ 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) -> KeyAgreementKeys { +pub fn get_key_agreement_keys(n_keys: u32) -> DidNewKeyAgreementKeys { BoundedBTreeSet::try_from( (1..=n_keys) .map(|i| { @@ -48,7 +48,7 @@ pub fn get_key_agreement_keys(n_keys: u32) -> KeyAgreementKeys { .expect("Failed to convert key_agreement_keys to BoundedBTreeSet") } -pub fn get_public_keys(n_keys: u32) -> BoundedBTreeSet, T::MaxOldAttestationKeys> { +pub fn get_public_keys(n_keys: u32) -> DidVerificationKeysToRevoke { BoundedBTreeSet::try_from( (1..=n_keys) .map(|i| { @@ -194,8 +194,6 @@ pub mod std { #[derive(Debug, Clone, PartialEq)] pub const MaxTotalKeyAgreementKeys: u32 = 1000; #[derive(Debug, Clone, PartialEq)] - pub const MaxOldAttestationKeys: u32 = 100; - #[derive(Debug, Clone, PartialEq)] pub const MaxEndpointUrlsCount: u32 = 3u32; } @@ -207,7 +205,6 @@ pub mod std { type Event = (); type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; - type MaxOldAttestationKeys = MaxOldAttestationKeys; type MaxPublicKeysPerDid = MaxPublicKeysPerDid; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; diff --git a/pallets/did/src/tests.rs b/pallets/did/src/tests.rs index 444012a83f..d43f7c6b05 100644 --- a/pallets/did/src/tests.rs +++ b/pallets/did/src/tests.rs @@ -16,14 +16,14 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org -use frame_support::{assert_err, assert_noop, assert_ok, storage::bounded_btree_set::BoundedBTreeSet}; +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::{std::*, *}, - Config, DidError, FtpUrl, HttpUrl, IpfsUrl, + DidError, DidNewKeyAgreementKeys, DidVerificationKeysToRevoke, FtpUrl, HttpUrl, IpfsUrl, }; use ctype::mock as ctype_mock; @@ -139,13 +139,13 @@ 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 = BoundedBTreeSet::::MaxTotalKeyAgreementKeys>::try_from( + let enc_keys = DidNewKeyAgreementKeys::::try_from( vec![get_x25519_encryption_key(true), get_x25519_encryption_key(false)] .iter() .copied() .collect::>(), ) - .expect("Exceeded BounddBTreeSet bounds when creating new key agreement keys"); + .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); @@ -309,6 +309,7 @@ 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()); @@ -406,7 +407,7 @@ fn check_successful_complete_update() { 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( - BoundedBTreeSet::::MaxTotalKeyAgreementKeys>::try_from( + DidNewKeyAgreementKeys::::try_from( vec![old_enc_key] .iter() .copied() @@ -421,19 +422,18 @@ fn check_successful_complete_update() { // removed. 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 = - BoundedBTreeSet::::MaxTotalKeyAgreementKeys>::try_from( - vec![new_enc_key] - .iter() - .copied() - .collect::>(), - ) - .expect("Should not fail to create BoundedBTreeSet from a single element"); + 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 = BoundedBTreeSet::::MaxOldAttestationKeys>::try_from( + details.public_keys_to_remove = DidVerificationKeysToRevoke::::try_from( vec![generate_key_id(&old_enc_key.into())] .iter() .copied() @@ -753,6 +753,7 @@ 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()); @@ -782,6 +783,7 @@ 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()); @@ -880,7 +882,7 @@ fn check_currently_active_authentication_key_update() { // Remove both attestation and delegation key let mut details = generate_base_did_update_details::(); // Trying to remove the currently active authentication key - details.public_keys_to_remove = BoundedBTreeSet::::MaxOldAttestationKeys>::try_from( + details.public_keys_to_remove = DidVerificationKeysToRevoke::::try_from( vec![generate_key_id( &did::DidVerificationKey::from(auth_key.public()).into(), )] @@ -917,7 +919,7 @@ fn check_currently_active_delegation_key_update() { // Remove both attestation and delegation key let mut details = generate_base_did_update_details::(); // Trying to remove the currently active delegation key - details.public_keys_to_remove = BoundedBTreeSet::::MaxOldAttestationKeys>::try_from( + details.public_keys_to_remove = DidVerificationKeysToRevoke::::try_from( vec![generate_key_id(&did::DidVerificationKey::from(del_key.public()).into())] .iter() .copied() @@ -952,7 +954,7 @@ fn check_currently_active_attestation_key_update() { // Remove both attestation and delegation key let mut details = generate_base_did_update_details::(); // Trying to remove the currently active attestation key - details.public_keys_to_remove = BoundedBTreeSet::::MaxOldAttestationKeys>::try_from( + details.public_keys_to_remove = DidVerificationKeysToRevoke::::try_from( vec![generate_key_id(&did::DidVerificationKey::from(att_key.public()).into())] .iter() .copied() @@ -986,7 +988,7 @@ fn check_verification_key_not_present_update() { // Remove both attestation and delegation key let mut details = generate_base_did_update_details::(); // Trying to remove the currently active authentication key - details.public_keys_to_remove = BoundedBTreeSet::::MaxOldAttestationKeys>::try_from( + details.public_keys_to_remove = DidVerificationKeysToRevoke::::try_from( vec![generate_key_id( &did::DidVerificationKey::from(key_to_delete.public()).into(), )] diff --git a/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index 263428e05d..e16e2b033e 100644 --- a/runtimes/peregrine/src/lib.rs +++ b/runtimes/peregrine/src/lib.rs @@ -702,8 +702,6 @@ parameter_types! { #[derive(Debug, Clone, PartialEq)] pub const MaxTotalKeyAgreementKeys: u32 = 1000; #[derive(Debug, Clone, PartialEq)] - pub const MaxOldAttestationKeys: u32 = 100; - #[derive(Debug, Clone, PartialEq)] pub const MaxEndpointUrlsCount: u32 = 3u32; } @@ -718,7 +716,6 @@ impl did::Config for Runtime { type EnsureOrigin = EnsureSigned; type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; - type MaxOldAttestationKeys = MaxOldAttestationKeys; type MaxPublicKeysPerDid = MaxPublicKeysPerDid; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index e1703e26bc..7f6bbb0b6a 100644 --- a/runtimes/standalone/src/lib.rs +++ b/runtimes/standalone/src/lib.rs @@ -380,8 +380,6 @@ parameter_types! { #[derive(Debug, Clone, PartialEq)] pub const MaxTotalKeyAgreementKeys: u32 = 1000; #[derive(Debug, Clone, PartialEq)] - pub const MaxOldAttestationKeys: u32 = 100; - #[derive(Debug, Clone, PartialEq)] pub const MaxEndpointUrlsCount: u32 = 3u32; } @@ -396,7 +394,6 @@ impl did::Config for Runtime { type EnsureOrigin = EnsureSigned; type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; - type MaxOldAttestationKeys = MaxOldAttestationKeys; type MaxPublicKeysPerDid = MaxPublicKeysPerDid; type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; type MaxUrlLength = MaxUrlLength; From 5120472aaeeafe3936f84523fcd52d9dc321fe57 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 10:33:12 +0200 Subject: [PATCH 26/37] refactor: apply shorter unlocking mutation --- pallets/kilt-launch/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pallets/kilt-launch/src/lib.rs b/pallets/kilt-launch/src/lib.rs index 8315458c37..690df5abd6 100644 --- a/pallets/kilt-launch/src/lib.rs +++ b/pallets/kilt-launch/src/lib.rs @@ -134,7 +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::TryFrom; + use sp_std::convert::TryInto; pub const KILT_LAUNCH_ID: LockIdentifier = *b"kiltlnch"; pub const VESTING_ID: LockIdentifier = *b"vesting "; @@ -812,17 +812,15 @@ pub mod pallet { // `UnlockingAt` if max_amount.is_some() { >::try_mutate(unlock_block, |maybe_bv| -> DispatchResult { - if let Some(bv) = maybe_bv.as_ref() { - let filtered: Vec = bv + if let Some(bv) = maybe_bv { + *bv = bv .clone() .into_inner() .into_iter() .filter(|acc_id| acc_id != source) - .collect(); - *maybe_bv = Some( - BoundedVec::::try_from(filtered) - .map_err(|_| Error::::MaxClaimsExceeded)?, - ); + .collect::>() + .try_into() + .map_err(|_| Error::::MaxClaimsExceeded)? } Ok(()) })?; From 038677c5dc4e4aefa9e5442e41ea027aa88b297e Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 10:33:45 +0200 Subject: [PATCH 27/37] fix: remove unused pub --- pallets/parachain-staking/src/set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/parachain-staking/src/set.rs b/pallets/parachain-staking/src/set.rs index e9d4c62ad8..57ea210be8 100644 --- a/pallets/parachain-staking/src/set.rs +++ b/pallets/parachain-staking/src/set.rs @@ -28,7 +28,7 @@ use sp_std::{fmt, prelude::*}; /// An ordered set backed by `BoundedVec`. #[derive(PartialEq, Eq, Encode, Decode, DefaultNoBound, Clone)] -pub struct OrderedSet(pub BoundedVec); +pub struct OrderedSet(BoundedVec); impl> OrderedSet { /// Create a new empty set. From 158c0ccbc8c8bbe847470ddfeceac416637228c8 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 10:45:53 +0200 Subject: [PATCH 28/37] refactor: try_insert, try_upsert --- pallets/parachain-staking/src/lib.rs | 10 +++++----- pallets/parachain-staking/src/set.rs | 22 +++++++++++----------- pallets/parachain-staking/src/tests.rs | 2 +- pallets/parachain-staking/src/types.rs | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 7429c6a8c8..e5a9644fb4 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -1065,7 +1065,7 @@ pub mod pallet { // 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 - .insert(Stake { + .try_insert(Stake { owner: acc.clone(), amount: stake, }) @@ -1260,7 +1260,7 @@ pub mod pallet { // 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 - .insert(Stake { + .try_insert(Stake { owner: acc.clone(), amount: state.total, }) @@ -1478,7 +1478,7 @@ pub mod pallet { let insert_delegator = state .delegators // we handle TooManyDelegators error below in do_update_delegator - .insert(delegation.clone()) + .try_insert(delegation.clone()) .unwrap_or(true); // should never fail but let's be safe ensure!(insert_delegator, Error::::DelegatorExists); @@ -1607,7 +1607,7 @@ pub mod pallet { // throws if delegation insertion exceeds bounded vec limit which we will handle // below in Self::do_update_delegator ensure!( - state.delegators.insert(delegation.clone()).unwrap_or(true), + state.delegators.try_insert(delegation.clone()).unwrap_or(true), Error::::DelegatorExists ); @@ -1961,7 +1961,7 @@ pub mod pallet { fn update(candidate: T::AccountId, total: BalanceOf) -> DispatchResult { let mut candidates = >::get(); candidates - .upsert(Stake { + .try_upsert(Stake { owner: candidate, amount: total, }) diff --git a/pallets/parachain-staking/src/set.rs b/pallets/parachain-staking/src/set.rs index 57ea210be8..0bb7e060d7 100644 --- a/pallets/parachain-staking/src/set.rs +++ b/pallets/parachain-staking/src/set.rs @@ -60,7 +60,7 @@ impl> OrderedSet { /// Throws if insertion would exceed the bounded vec's max size. /// /// Returns true if the item is unique in the set, otherwise returns false. - pub fn insert(&mut self, value: T) -> Result { + pub fn try_insert(&mut self, value: T) -> Result { match self.linear_search(&value) { Ok(_) => Ok(false), Err(loc) => { @@ -99,7 +99,7 @@ impl> OrderedSet { /// /// Returns the old value if existing or None if the value did not exist /// before. - pub fn upsert(&mut self, value: T) -> Result, ()> { + 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); @@ -340,16 +340,16 @@ mod tests { let mut set: OrderedSet = OrderedSet::new(); assert_eq!(set, OrderedSet::::from(vec![].try_into().unwrap())); - assert_eq!(set.insert(1), Ok(true)); + assert_eq!(set.try_insert(1), Ok(true)); assert_eq!(set, OrderedSet::::from(vec![1].try_into().unwrap())); - assert_eq!(set.insert(5), Ok(true)); + assert_eq!(set.try_insert(5), Ok(true)); assert_eq!(set, OrderedSet::::from(vec![1, 5].try_into().unwrap())); - assert_eq!(set.insert(3), Ok(true)); + assert_eq!(set.try_insert(3), Ok(true)); assert_eq!(set, OrderedSet::::from(vec![1, 3, 5].try_into().unwrap())); - assert_eq!(set.insert(3), Ok(false)); + assert_eq!(set.try_insert(3), Ok(false)); assert_eq!(set, OrderedSet::::from(vec![1, 3, 5].try_into().unwrap())); } @@ -401,7 +401,7 @@ mod tests { 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.insert(11).is_err()); + 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]); @@ -417,7 +417,7 @@ mod tests { #[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.insert(6); + let inserted = set.try_insert(6); assert!(inserted.is_err()); } @@ -458,7 +458,7 @@ mod tests { .try_into() .unwrap(), ); - assert_eq!(set.insert(StakeOf:: { owner: 2, amount: 75 }), Ok(true)); + assert_eq!(set.try_insert(StakeOf:: { owner: 2, amount: 75 }), Ok(true)); assert_eq!( set, OrderedSet::from( @@ -475,7 +475,7 @@ mod tests { ) ); assert_eq!( - set.upsert(StakeOf:: { owner: 2, amount: 90 }), + set.try_upsert(StakeOf:: { owner: 2, amount: 90 }), Ok(Some(StakeOf:: { owner: 2, amount: 75 })) ); assert_eq!( @@ -494,7 +494,7 @@ mod tests { ) ); assert_eq!( - set.upsert(StakeOf:: { owner: 2, amount: 60 }), + set.try_upsert(StakeOf:: { owner: 2, amount: 60 }), Ok(Some(StakeOf:: { owner: 2, amount: 90 })) ); assert_eq!( diff --git a/pallets/parachain-staking/src/tests.rs b/pallets/parachain-staking/src/tests.rs index 465b113427..1405c07eeb 100644 --- a/pallets/parachain-staking/src/tests.rs +++ b/pallets/parachain-staking/src/tests.rs @@ -1843,7 +1843,7 @@ fn should_not_reward_delegators_below_min_stake() { owner: 4u64, amount: delegator_stake_below_min, }; - assert_eq!(state.delegators.insert(impossible_bond), Ok(true)); + 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)]; diff --git a/pallets/parachain-staking/src/types.rs b/pallets/parachain-staking/src/types.rs index d9c72fffe3..e93c621c2b 100644 --- a/pallets/parachain-staking/src/types.rs +++ b/pallets/parachain-staking/src/types.rs @@ -237,7 +237,7 @@ where /// doesn't insert the new delegation. 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); Ok(true) } else { From 1201ef8f7e4aa37cac97308d27b38cd22ac06c43 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 10:50:45 +0200 Subject: [PATCH 29/37] fix: rm expect in delegator constructor --- pallets/parachain-staking/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/parachain-staking/src/types.rs b/pallets/parachain-staking/src/types.rs index e93c621c2b..16f52d6c51 100644 --- a/pallets/parachain-staking/src/types.rs +++ b/pallets/parachain-staking/src/types.rs @@ -225,7 +225,7 @@ where amount, }] .try_into() - .expect("At least one collator per delegator should be enabled"), + .unwrap_or_default(), ), total: amount, } From 522c885b886cd8330817227986ac1bda66b2acb6 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 11:45:26 +0200 Subject: [PATCH 30/37] fix: allow delegator constructor to throw --- pallets/parachain-staking/src/lib.rs | 7 ++++++- pallets/parachain-staking/src/types.rs | 9 ++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index e5a9644fb4..befcc60db9 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -1483,6 +1483,11 @@ pub mod pallet { // should never fail but let's be safe 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 num_delegations_pre_insertion == T::MaxDelegatorsPerCollator::get() { Self::do_update_delegator(delegation, state)? @@ -1500,7 +1505,7 @@ pub mod pallet { // 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 diff --git a/pallets/parachain-staking/src/types.rs b/pallets/parachain-staking/src/types.rs index 16f52d6c51..38255362bd 100644 --- a/pallets/parachain-staking/src/types.rs +++ b/pallets/parachain-staking/src/types.rs @@ -217,18 +217,17 @@ where Balance: Copy + Add + Saturating + PartialOrd + Eq + Ord + Debug + Zero, MaxCollatorsPerDelegator: Get + Debug + PartialEq, { - pub fn new(collator: AccountId, amount: Balance) -> Self { - Delegator { + pub fn try_new(collator: AccountId, amount: Balance) -> Result { + Ok(Delegator { delegations: OrderedSet::from( vec![Stake { owner: collator, amount, }] - .try_into() - .unwrap_or_default(), + .try_into()?, ), total: amount, - } + }) } /// Adds a new delegation. From 77b653bfac7e3257056962c9bf76cc79757bf6cf Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 11:45:48 +0200 Subject: [PATCH 31/37] refactor: apply suggestion for sort_greatest_to_lowest --- pallets/parachain-staking/src/set.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pallets/parachain-staking/src/set.rs b/pallets/parachain-staking/src/set.rs index 0bb7e060d7..db3f7dc03b 100644 --- a/pallets/parachain-staking/src/set.rs +++ b/pallets/parachain-staking/src/set.rs @@ -225,12 +225,11 @@ impl> OrderedSet { } /// Sorts from greatest to lowest. - /// - /// 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. pub fn sort_greatest_to_lowest(&mut self) { - let mut sorted_v = self.0.clone().into_inner(); + // 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::replace(&mut self.0, BoundedVec::default()).into(); sorted_v.sort_by(|a, b| b.cmp(a)); self.0 = sorted_v.try_into().expect("Did not extend size of bounded vec"); } From 3bb2acc8049d074a0f65fa1a1487d5054ae1fef2 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 12:58:04 +0200 Subject: [PATCH 32/37] refactor: remove deprecated in staking --- pallets/parachain-staking/src/deprecated.rs | 83 ------------------- pallets/parachain-staking/src/lib.rs | 5 +- .../parachain-staking/src/migrations/v4.rs | 28 ++++--- 3 files changed, 17 insertions(+), 99 deletions(-) delete mode 100644 pallets/parachain-staking/src/deprecated.rs diff --git a/pallets/parachain-staking/src/deprecated.rs b/pallets/parachain-staking/src/deprecated.rs deleted file mode 100644 index 7a58e4d9de..0000000000 --- a/pallets/parachain-staking/src/deprecated.rs +++ /dev/null @@ -1,83 +0,0 @@ -// 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 - -/// Deprecated types used in versions 1 to 4 (Vec instead of BoundedVec). -use crate::Config; - -pub(crate) mod v1_v4 { - use crate::types::{AccountIdOf, BalanceOf, CollatorStatus, Stake}; - use frame_support::dispatch::fmt::Debug; - #[cfg(feature = "std")] - use serde::{Deserialize, Serialize}; - use sp_runtime::{ - codec::{Decode, Encode}, - RuntimeDebug, - }; - use sp_std::prelude::*; - - use super::*; - - #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] - #[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode, Default, Clone)] - pub struct OrderedSet(Vec); - impl OrderedSet { - pub(crate) fn sort_greatest_to_lowest(&mut self) { - self.0.sort_by(|a, b| b.cmp(a)); - } - } - - #[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)] - pub struct Collator - where - AccountId: Eq + Ord + Debug, - Balance: Eq + Ord + Debug, - { - pub(crate) id: AccountId, - pub(crate) stake: Balance, - pub(crate) delegators: OrderedSet>, - pub(crate) total: Balance, - pub(crate) state: CollatorStatus, - } - pub(crate) type CollatorOf = Collator, BalanceOf>; - - #[derive(Encode, Decode, RuntimeDebug, PartialEq)] - pub struct Delegator { - pub(crate) delegations: OrderedSet>, - pub(crate) total: Balance, - } - - pub(crate) mod storage { - use frame_support::{decl_module, decl_storage}; - use sp_std::prelude::*; - - use super::*; - - decl_module! { - pub struct OldPallet for enum Call where origin: T::Origin {} - } - - decl_storage! { - pub(crate) trait Store for OldPallet as ParachainStaking { - pub(crate) DelegatorState get(fn delegator_state): map hasher(twox_64_concat) T::AccountId => Option>>; - pub(crate) CollatorState get(fn collator_state): map hasher(twox_64_concat) T::AccountId => Option>>; - pub(crate) SelectedCandidates get(fn selected_candidates): Vec; - pub(crate) CandidatePool get(fn candidate_pool): OrderedSet>>; - } - } - } -} diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index befcc60db9..27d6757102 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -162,7 +162,6 @@ pub(crate) mod mock; #[cfg(test)] pub(crate) mod tests; -mod deprecated; mod inflation; pub mod migrations; mod set; @@ -1485,8 +1484,8 @@ pub mod pallet { // 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)?; + 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 num_delegations_pre_insertion == T::MaxDelegatorsPerCollator::get() { diff --git a/pallets/parachain-staking/src/migrations/v4.rs b/pallets/parachain-staking/src/migrations/v4.rs index aab4f55b0c..6253a1d61c 100644 --- a/pallets/parachain-staking/src/migrations/v4.rs +++ b/pallets/parachain-staking/src/migrations/v4.rs @@ -17,14 +17,11 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org use crate::{ - deprecated::v1_v4::{ - storage::{CandidatePool, CollatorState, DelegatorState}, - CollatorOf, Delegator, - }, migrations::StakingStorageVersion, - pallet::*, + types::{CollatorOf, Delegator}, + CandidatePool, CollatorState, Config, DelegatorState, StorageVersion, }; -use frame_support::{dispatch::Weight, traits::Get, StoragePrefixedMap, StorageValue}; +use frame_support::{dispatch::Weight, traits::Get}; #[cfg(feature = "try-runtime")] pub(crate) fn pre_migrate() -> Result<(), &'static str> { @@ -40,18 +37,20 @@ pub(crate) fn migrate() -> Weight { let mut n = 1u64; // for each candidate: sort delegators from greatest to lowest - CollatorState::::translate_values(|mut state: CollatorOf| { + 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) - }); + 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"); @@ -63,7 +62,10 @@ pub(crate) fn migrate() -> Weight { pub(crate) fn post_migrate() -> Result<(), &'static str> { let mut candidates = CandidatePool::::get(); candidates.sort_greatest_to_lowest(); - assert_eq!(CandidatePool::::get(), candidates); + assert_eq!( + CandidatePool::::get().into_bounded_vec().into_inner(), + candidates.into_bounded_vec().into_inner() + ); assert_eq!(StorageVersion::::get(), StakingStorageVersion::V4); Ok(()) } From 54d17ce279bb6af925f7150c8b07ddb6c91af31a Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 12:58:41 +0200 Subject: [PATCH 33/37] fix: clippy --- pallets/parachain-staking/src/set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/parachain-staking/src/set.rs b/pallets/parachain-staking/src/set.rs index db3f7dc03b..1adea2d275 100644 --- a/pallets/parachain-staking/src/set.rs +++ b/pallets/parachain-staking/src/set.rs @@ -229,7 +229,7 @@ impl> OrderedSet { // 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::replace(&mut self.0, BoundedVec::default()).into(); + 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"); } From 7ffd5ab0425ac4c64eb8bac534b2056eb8e809df Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 13:36:40 +0200 Subject: [PATCH 34/37] fix: split did::mock to make benchmarks work again --- pallets/did/src/benchmarking.rs | 6 +- pallets/did/src/lib.rs | 4 +- pallets/did/src/migrations/v1.rs | 4 +- pallets/did/src/mock.rs | 669 +++++++++++++------------------ pallets/did/src/mock_utils.rs | 112 ++++++ pallets/did/src/tests.rs | 5 +- 6 files changed, 407 insertions(+), 393 deletions(-) create mode 100644 pallets/did/src/mock_utils.rs diff --git a/pallets/did/src/benchmarking.rs b/pallets/did/src/benchmarking.rs index eb8cec7d69..665c4324dc 100644 --- a/pallets/did/src/benchmarking.rs +++ b/pallets/did/src/benchmarking.rs @@ -27,7 +27,7 @@ use sp_runtime::{traits::IdentifyAccount, MultiSigner, SaturatedConversion}; use crate::{ did_details::*, - mock::{ + 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, }, @@ -488,6 +488,6 @@ benchmarks! { impl_benchmark_test_suite! { Pallet, - crate::mock::std::ExtBuilder::default().build_with_keystore(None), - crate::mock::std::Test + crate::mock::ExtBuilder::default().build_with_keystore(None), + crate::mock::Test } diff --git a/pallets/did/src/lib.rs b/pallets/did/src/lib.rs index 28d5f2e980..1d9c319823 100644 --- a/pallets/did/src/lib.rs +++ b/pallets/did/src/lib.rs @@ -112,8 +112,10 @@ mod utils; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; -#[cfg(any(feature = "runtime-benchmarks", test))] +#[cfg(test)] mod mock; +#[cfg(any(feature = "runtime-benchmarks", test))] +mod mock_utils; #[cfg(test)] mod tests; diff --git a/pallets/did/src/migrations/v1.rs b/pallets/did/src/migrations/v1.rs index 0bfc604b81..9ad829fd05 100644 --- a/pallets/did/src/migrations/v1.rs +++ b/pallets/did/src/migrations/v1.rs @@ -86,8 +86,8 @@ mod tests { use sp_core::Pair; use super::*; - use crate::mock::std::Test as TestRuntime; - use mock::std::{get_did_identifier_from_ed25519_key, get_ed25519_authentication_key, ExtBuilder}; + 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] diff --git a/pallets/did/src/mock.rs b/pallets/did/src/mock.rs index 650a2313ca..887e330168 100644 --- a/pallets/did/src/mock.rs +++ b/pallets/did/src/mock.rs @@ -17,452 +17,353 @@ // If you feel like getting in touch with us, you can do so at info@botlabs.org #![allow(clippy::from_over_into)] +#![allow(dead_code)] + +use frame_support::{parameter_types, weights::constants::RocksDbWeight}; +use frame_system::EnsureSigned; +use sp_core::{ecdsa, ed25519, sr25519, Pair}; +use sp_keystore::{testing::KeyStore, KeystoreExt}; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, + MultiSigner, +}; +use sp_std::sync::Arc; +use crate as did; 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 type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +pub type Block = frame_system::mocking::MockBlock; + +pub type TestDidIdentifier = kilt_primitives::AccountId; +pub type TestKeyId = did::KeyIdOf; +pub type TestBlockNumber = kilt_primitives::BlockNumber; +pub type TestCtypeOwner = TestDidIdentifier; +pub type TestCtypeHash = kilt_primitives::Hash; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + Did: did::{Pallet, Call, Storage, Event, Origin}, + Ctype: ctype::{Pallet, Call, Storage, Event}, + System: frame_system::{Pallet, Call, Config, Storage, Event}, + } +); + +parameter_types! { + pub const SS58Prefix: u8 = 38; + pub const BlockHashCount: u64 = 250; } -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, - } +impl frame_system::Config for Test { + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = kilt_primitives::Hash; + type Hashing = BlakeTwo256; + type AccountId = <::Signer as IdentifyAccount>::AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type DbWeight = RocksDbWeight; + type Version = (); + + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type BaseCallFilter = (); + type SystemWeightInfo = (); + type BlockWeights = (); + type BlockLength = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); } -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(), - } +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; } -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") +impl Config for Test { + type DidIdentifier = TestDidIdentifier; + type Origin = Origin; + type Call = Call; + type EnsureOrigin = EnsureSigned; + type Event = (); + type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; + type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; + type MaxPublicKeysPerDid = MaxPublicKeysPerDid; + type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; + type MaxUrlLength = MaxUrlLength; + type MaxEndpointUrlsCount = MaxEndpointUrlsCount; + type WeightInfo = (); } -#[cfg(any(feature = "std", test))] -pub mod std { - #![allow(dead_code)] - - use frame_support::{parameter_types, weights::constants::RocksDbWeight}; - use frame_system::EnsureSigned; - use sp_core::{ecdsa, ed25519, sr25519, Pair}; - use sp_keystore::{testing::KeyStore, KeystoreExt}; - use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentifyAccount, IdentityLookup, Verify}, - MultiSigner, - }; - use sp_std::sync::Arc; - - use crate as did; - use crate::*; - - pub type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; - pub type Block = frame_system::mocking::MockBlock; - - pub type TestDidIdentifier = kilt_primitives::AccountId; - pub type TestKeyId = did::KeyIdOf; - pub type TestBlockNumber = kilt_primitives::BlockNumber; - pub type TestCtypeOwner = TestDidIdentifier; - pub type TestCtypeHash = kilt_primitives::Hash; - - frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - Did: did::{Pallet, Call, Storage, Event, Origin}, - Ctype: ctype::{Pallet, Call, Storage, Event}, - System: frame_system::{Pallet, Call, Config, Storage, Event}, - } - ); - - parameter_types! { - pub const SS58Prefix: u8 = 38; - pub const BlockHashCount: u64 = 250; - } - - impl frame_system::Config for Test { - type Origin = Origin; - type Call = Call; - type Index = u64; - type BlockNumber = u64; - type Hash = kilt_primitives::Hash; - type Hashing = BlakeTwo256; - type AccountId = <::Signer as IdentifyAccount>::AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type Event = (); - type BlockHashCount = BlockHashCount; - type DbWeight = RocksDbWeight; - type Version = (); - - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type BaseCallFilter = (); - type SystemWeightInfo = (); - type BlockWeights = (); - type BlockLength = (); - type SS58Prefix = SS58Prefix; - type OnSetCode = (); - } +impl ctype::Config for Test { + type CtypeCreatorId = TestCtypeOwner; + #[cfg(feature = "runtime-benchmarks")] + type EnsureOrigin = EnsureSigned; + #[cfg(not(feature = "runtime-benchmarks"))] + type EnsureOrigin = did::EnsureDidOrigin; + type Event = (); + type WeightInfo = (); +} - 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; - } +#[cfg(test)] +pub(crate) const DEFAULT_ACCOUNT: kilt_primitives::AccountId = kilt_primitives::AccountId::new([0u8; 32]); - impl Config for Test { - type DidIdentifier = TestDidIdentifier; - type Origin = Origin; - type Call = Call; - type EnsureOrigin = EnsureSigned; - type Event = (); - type MaxNewKeyAgreementKeys = MaxNewKeyAgreementKeys; - type MaxTotalKeyAgreementKeys = MaxTotalKeyAgreementKeys; - type MaxPublicKeysPerDid = MaxPublicKeysPerDid; - type MaxVerificationKeysToRevoke = MaxVerificationKeysToRevoke; - type MaxUrlLength = MaxUrlLength; - type MaxEndpointUrlsCount = MaxEndpointUrlsCount; - type WeightInfo = (); - } +const DEFAULT_AUTH_SEED: [u8; 32] = [4u8; 32]; +const ALTERNATIVE_AUTH_SEED: [u8; 32] = [40u8; 32]; +const DEFAULT_ENC_SEED: [u8; 32] = [5u8; 32]; +const ALTERNATIVE_ENC_SEED: [u8; 32] = [50u8; 32]; +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]; - impl ctype::Config for Test { - type CtypeCreatorId = TestCtypeOwner; - #[cfg(feature = "runtime-benchmarks")] - type EnsureOrigin = EnsureSigned; - #[cfg(not(feature = "runtime-benchmarks"))] - type EnsureOrigin = did::EnsureDidOrigin; - type Event = (); - type WeightInfo = (); - } +pub fn get_did_identifier_from_ed25519_key(public_key: ed25519::Public) -> TestDidIdentifier { + MultiSigner::from(public_key).into_account() +} - #[cfg(test)] - pub(crate) const DEFAULT_ACCOUNT: kilt_primitives::AccountId = kilt_primitives::AccountId::new([0u8; 32]); +pub fn get_did_identifier_from_sr25519_key(public_key: sr25519::Public) -> TestDidIdentifier { + MultiSigner::from(public_key).into_account() +} - const DEFAULT_AUTH_SEED: [u8; 32] = [4u8; 32]; - const ALTERNATIVE_AUTH_SEED: [u8; 32] = [40u8; 32]; - const DEFAULT_ENC_SEED: [u8; 32] = [5u8; 32]; - const ALTERNATIVE_ENC_SEED: [u8; 32] = [50u8; 32]; - 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]; +pub fn get_did_identifier_from_ecdsa_key(public_key: ecdsa::Public) -> TestDidIdentifier { + MultiSigner::from(public_key).into_account() +} - pub fn get_did_identifier_from_ed25519_key(public_key: ed25519::Public) -> TestDidIdentifier { - MultiSigner::from(public_key).into_account() +pub fn get_ed25519_authentication_key(default: bool) -> ed25519::Pair { + if default { + ed25519::Pair::from_seed(&DEFAULT_AUTH_SEED) + } else { + ed25519::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) } +} - pub fn get_did_identifier_from_sr25519_key(public_key: sr25519::Public) -> TestDidIdentifier { - MultiSigner::from(public_key).into_account() +pub fn get_sr25519_authentication_key(default: bool) -> sr25519::Pair { + if default { + sr25519::Pair::from_seed(&DEFAULT_AUTH_SEED) + } else { + sr25519::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) } +} - pub fn get_did_identifier_from_ecdsa_key(public_key: ecdsa::Public) -> TestDidIdentifier { - MultiSigner::from(public_key).into_account() +pub fn get_ecdsa_authentication_key(default: bool) -> ecdsa::Pair { + if default { + ecdsa::Pair::from_seed(&DEFAULT_AUTH_SEED) + } else { + ecdsa::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) } +} - pub fn get_ed25519_authentication_key(default: bool) -> ed25519::Pair { - if default { - ed25519::Pair::from_seed(&DEFAULT_AUTH_SEED) - } else { - ed25519::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) - } +pub fn get_x25519_encryption_key(default: bool) -> DidEncryptionKey { + if default { + DidEncryptionKey::X25519(DEFAULT_ENC_SEED) + } else { + DidEncryptionKey::X25519(ALTERNATIVE_ENC_SEED) } +} - pub fn get_sr25519_authentication_key(default: bool) -> sr25519::Pair { - if default { - sr25519::Pair::from_seed(&DEFAULT_AUTH_SEED) - } else { - sr25519::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) - } +pub fn get_ed25519_attestation_key(default: bool) -> ed25519::Pair { + if default { + ed25519::Pair::from_seed(&DEFAULT_ATT_SEED) + } else { + ed25519::Pair::from_seed(&ALTERNATIVE_ATT_SEED) } +} - pub fn get_ecdsa_authentication_key(default: bool) -> ecdsa::Pair { - if default { - ecdsa::Pair::from_seed(&DEFAULT_AUTH_SEED) - } else { - ecdsa::Pair::from_seed(&ALTERNATIVE_AUTH_SEED) - } +pub fn get_sr25519_attestation_key(default: bool) -> sr25519::Pair { + if default { + sr25519::Pair::from_seed(&DEFAULT_ATT_SEED) + } else { + sr25519::Pair::from_seed(&ALTERNATIVE_ATT_SEED) } +} - pub fn get_x25519_encryption_key(default: bool) -> DidEncryptionKey { - if default { - DidEncryptionKey::X25519(DEFAULT_ENC_SEED) - } else { - DidEncryptionKey::X25519(ALTERNATIVE_ENC_SEED) - } +pub fn get_ecdsa_attestation_key(default: bool) -> ecdsa::Pair { + if default { + ecdsa::Pair::from_seed(&DEFAULT_ATT_SEED) + } else { + ecdsa::Pair::from_seed(&ALTERNATIVE_ATT_SEED) } +} - pub fn get_ed25519_attestation_key(default: bool) -> ed25519::Pair { - if default { - ed25519::Pair::from_seed(&DEFAULT_ATT_SEED) - } else { - ed25519::Pair::from_seed(&ALTERNATIVE_ATT_SEED) - } +pub fn get_ed25519_delegation_key(default: bool) -> ed25519::Pair { + if default { + ed25519::Pair::from_seed(&DEFAULT_DEL_SEED) + } else { + ed25519::Pair::from_seed(&ALTERNATIVE_DEL_SEED) } +} - pub fn get_sr25519_attestation_key(default: bool) -> sr25519::Pair { - if default { - sr25519::Pair::from_seed(&DEFAULT_ATT_SEED) - } else { - sr25519::Pair::from_seed(&ALTERNATIVE_ATT_SEED) - } +pub fn get_sr25519_delegation_key(default: bool) -> sr25519::Pair { + if default { + sr25519::Pair::from_seed(&DEFAULT_DEL_SEED) + } else { + sr25519::Pair::from_seed(&ALTERNATIVE_DEL_SEED) } +} - pub fn get_ecdsa_attestation_key(default: bool) -> ecdsa::Pair { - if default { - ecdsa::Pair::from_seed(&DEFAULT_ATT_SEED) - } else { - ecdsa::Pair::from_seed(&ALTERNATIVE_ATT_SEED) - } +pub fn get_ecdsa_delegation_key(default: bool) -> ecdsa::Pair { + if default { + ecdsa::Pair::from_seed(&DEFAULT_DEL_SEED) + } else { + ecdsa::Pair::from_seed(&ALTERNATIVE_DEL_SEED) } +} - pub fn get_ed25519_delegation_key(default: bool) -> ed25519::Pair { - if default { - ed25519::Pair::from_seed(&DEFAULT_DEL_SEED) - } else { - ed25519::Pair::from_seed(&ALTERNATIVE_DEL_SEED) - } - } +pub fn generate_key_id(key: &did::DidPublicKey) -> TestKeyId { + utils::calculate_key_id::(key) +} - pub fn get_sr25519_delegation_key(default: bool) -> sr25519::Pair { - if default { - sr25519::Pair::from_seed(&DEFAULT_DEL_SEED) - } else { - sr25519::Pair::from_seed(&ALTERNATIVE_DEL_SEED) - } - } +pub(crate) fn get_attestation_key_test_input() -> TestCtypeHash { + TestCtypeHash::from_slice(&[0u8; 32]) +} +pub(crate) fn get_attestation_key_call() -> Call { + Call::Ctype(ctype::Call::add(get_attestation_key_test_input())) +} +pub(crate) fn get_authentication_key_test_input() -> TestCtypeHash { + TestCtypeHash::from_slice(&[1u8; 32]) +} +pub(crate) fn get_authentication_key_call() -> Call { + Call::Ctype(ctype::Call::add(get_authentication_key_test_input())) +} +pub(crate) fn get_delegation_key_test_input() -> TestCtypeHash { + TestCtypeHash::from_slice(&[2u8; 32]) +} +pub(crate) fn get_delegation_key_call() -> Call { + Call::Ctype(ctype::Call::add(get_delegation_key_test_input())) +} +pub(crate) fn get_none_key_test_input() -> TestCtypeHash { + TestCtypeHash::from_slice(&[3u8; 32]) +} +pub(crate) fn get_none_key_call() -> Call { + Call::Ctype(ctype::Call::add(get_none_key_test_input())) +} - pub fn get_ecdsa_delegation_key(default: bool) -> ecdsa::Pair { - if default { - ecdsa::Pair::from_seed(&DEFAULT_DEL_SEED) +impl did::DeriveDidCallAuthorizationVerificationKeyRelationship for Call { + fn derive_verification_key_relationship(&self) -> Option { + if *self == get_attestation_key_call() { + Some(did::DidVerificationKeyRelationship::AssertionMethod) + } else if *self == get_authentication_key_call() { + Some(did::DidVerificationKeyRelationship::Authentication) + } else if *self == get_delegation_key_call() { + Some(did::DidVerificationKeyRelationship::CapabilityDelegation) } else { - ecdsa::Pair::from_seed(&ALTERNATIVE_DEL_SEED) + #[cfg(feature = "runtime-benchmarks")] + if *self == Self::get_call_for_did_call_benchmark() { + // Always require an authentication key to dispatch calls during benchmarking + return Some(did::DidVerificationKeyRelationship::Authentication); + } + None } } - pub fn generate_key_id(key: &did::DidPublicKey) -> TestKeyId { - utils::calculate_key_id::(key) + // Always return a System::remark() extrinsic call + #[cfg(feature = "runtime-benchmarks")] + fn get_call_for_did_call_benchmark() -> Self { + Call::System(frame_system::Call::remark(vec![])) } +} - pub(crate) fn get_attestation_key_test_input() -> TestCtypeHash { - TestCtypeHash::from_slice(&[0u8; 32]) - } - pub(crate) fn get_attestation_key_call() -> Call { - Call::Ctype(ctype::Call::add(get_attestation_key_test_input())) - } - pub(crate) fn get_authentication_key_test_input() -> TestCtypeHash { - TestCtypeHash::from_slice(&[1u8; 32]) - } - pub(crate) fn get_authentication_key_call() -> Call { - Call::Ctype(ctype::Call::add(get_authentication_key_test_input())) - } - pub(crate) fn get_delegation_key_test_input() -> TestCtypeHash { - TestCtypeHash::from_slice(&[2u8; 32]) - } - pub(crate) fn get_delegation_key_call() -> Call { - Call::Ctype(ctype::Call::add(get_delegation_key_test_input())) - } - pub(crate) fn get_none_key_test_input() -> TestCtypeHash { - TestCtypeHash::from_slice(&[3u8; 32]) - } - pub(crate) fn get_none_key_call() -> Call { - Call::Ctype(ctype::Call::add(get_none_key_test_input())) +pub fn generate_test_did_call( + verification_key_required: did::DidVerificationKeyRelationship, + caller: TestDidIdentifier, +) -> did::DidAuthorizedCallOperationWithVerificationRelationship { + let call = match verification_key_required { + DidVerificationKeyRelationship::AssertionMethod => get_attestation_key_call(), + DidVerificationKeyRelationship::Authentication => get_authentication_key_call(), + DidVerificationKeyRelationship::CapabilityDelegation => get_delegation_key_call(), + _ => get_none_key_call(), + }; + did::DidAuthorizedCallOperationWithVerificationRelationship { + operation: did::DidAuthorizedCallOperation { + did: caller, + call, + tx_counter: 1u64, + }, + verification_key_relationship: verification_key_required, } +} - impl did::DeriveDidCallAuthorizationVerificationKeyRelationship for Call { - fn derive_verification_key_relationship(&self) -> Option { - if *self == get_attestation_key_call() { - Some(did::DidVerificationKeyRelationship::AssertionMethod) - } else if *self == get_authentication_key_call() { - Some(did::DidVerificationKeyRelationship::Authentication) - } else if *self == get_delegation_key_call() { - Some(did::DidVerificationKeyRelationship::CapabilityDelegation) - } else { - #[cfg(feature = "runtime-benchmarks")] - if *self == Self::get_call_for_did_call_benchmark() { - // Always require an authentication key to dispatch calls during benchmarking - return Some(did::DidVerificationKeyRelationship::Authentication); - } - None - } - } +#[allow(unused_must_use)] +pub fn initialize_logger() { + env_logger::builder().is_test(true).try_init(); +} - // Always return a System::remark() extrinsic call - #[cfg(feature = "runtime-benchmarks")] - fn get_call_for_did_call_benchmark() -> Self { - Call::System(frame_system::Call::remark(vec![])) - } - } +#[derive(Clone)] +pub struct ExtBuilder { + dids_stored: Vec<(TestDidIdentifier, did::DidDetails)>, + storage_version: DidStorageVersion, +} - pub fn generate_test_did_call( - verification_key_required: did::DidVerificationKeyRelationship, - caller: TestDidIdentifier, - ) -> did::DidAuthorizedCallOperationWithVerificationRelationship { - let call = match verification_key_required { - DidVerificationKeyRelationship::AssertionMethod => get_attestation_key_call(), - DidVerificationKeyRelationship::Authentication => get_authentication_key_call(), - DidVerificationKeyRelationship::CapabilityDelegation => get_delegation_key_call(), - _ => get_none_key_call(), - }; - did::DidAuthorizedCallOperationWithVerificationRelationship { - operation: did::DidAuthorizedCallOperation { - did: caller, - call, - tx_counter: 1u64, - }, - verification_key_relationship: verification_key_required, +impl Default for ExtBuilder { + fn default() -> Self { + Self { + dids_stored: vec![], + storage_version: DidStorageVersion::default(), } } +} - #[allow(unused_must_use)] - pub fn initialize_logger() { - env_logger::builder().is_test(true).try_init(); - } - - #[derive(Clone)] - pub struct ExtBuilder { - dids_stored: Vec<(TestDidIdentifier, did::DidDetails)>, - storage_version: DidStorageVersion, +impl ExtBuilder { + pub fn with_dids(mut self, dids: Vec<(TestDidIdentifier, did::DidDetails)>) -> Self { + self.dids_stored = dids; + self } - impl Default for ExtBuilder { - fn default() -> Self { - Self { - dids_stored: vec![], - storage_version: DidStorageVersion::default(), - } - } + pub fn with_storage_version(mut self, storage_version: DidStorageVersion) -> Self { + self.storage_version = storage_version; + self } - impl ExtBuilder { - pub fn with_dids(mut self, dids: Vec<(TestDidIdentifier, did::DidDetails)>) -> Self { - self.dids_stored = dids; - self - } - - pub fn with_storage_version(mut self, storage_version: DidStorageVersion) -> Self { - self.storage_version = storage_version; - self - } - - pub fn build(self, ext: Option) -> sp_io::TestExternalities { - let mut ext = if let Some(ext) = ext { - ext - } else { - let storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); - sp_io::TestExternalities::new(storage) - }; - - if !self.dids_stored.is_empty() { - ext.execute_with(|| { - self.dids_stored.iter().for_each(|did| { - did::Did::::insert(did.0.clone(), did.1.clone()); - }) - }); - } + pub fn build(self, ext: Option) -> sp_io::TestExternalities { + let mut ext = if let Some(ext) = ext { + ext + } else { + let storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + sp_io::TestExternalities::new(storage) + }; + if !self.dids_stored.is_empty() { ext.execute_with(|| { - did::StorageVersion::::set(self.storage_version); + self.dids_stored.iter().for_each(|did| { + did::Did::::insert(did.0.clone(), did.1.clone()); + }) }); - - ext } - // allowance only required for clippy, this function is actually used - #[allow(dead_code)] - pub fn build_with_keystore(self, ext: Option) -> sp_io::TestExternalities { - let mut ext = self.build(ext); + ext.execute_with(|| { + did::StorageVersion::::set(self.storage_version); + }); - let keystore = KeyStore::new(); - ext.register_extension(KeystoreExt(Arc::new(keystore))); + ext + } - ext - } + // allowance only required for clippy, this function is actually used + #[allow(dead_code)] + pub fn build_with_keystore(self, ext: Option) -> sp_io::TestExternalities { + let mut ext = self.build(ext); + + let keystore = KeyStore::new(); + ext.register_extension(KeystoreExt(Arc::new(keystore))); + + ext } } 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 d43f7c6b05..6c9dced4d6 100644 --- a/pallets/did/src/tests.rs +++ b/pallets/did/src/tests.rs @@ -21,9 +21,8 @@ use sp_core::*; use sp_std::{collections::btree_set::BTreeSet, convert::TryFrom}; use crate::{ - self as did, - mock::{std::*, *}, - DidError, DidNewKeyAgreementKeys, DidVerificationKeysToRevoke, FtpUrl, HttpUrl, IpfsUrl, + self as did, mock::*, mock_utils::*, DidError, DidNewKeyAgreementKeys, DidVerificationKeysToRevoke, FtpUrl, + HttpUrl, IpfsUrl, }; use ctype::mock as ctype_mock; From cf0949321f4e2d2ecd842df99a3ca79244783af5 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Tue, 10 Aug 2021 16:48:18 +0200 Subject: [PATCH 35/37] refactor: DidKeyAgreementKeys --- pallets/did/src/deprecated.rs | 4 ++-- pallets/did/src/did_details.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pallets/did/src/deprecated.rs b/pallets/did/src/deprecated.rs index 538c761daa..b51d07fb3d 100644 --- a/pallets/did/src/deprecated.rs +++ b/pallets/did/src/deprecated.rs @@ -25,7 +25,7 @@ pub(crate) mod v1 { #[derive(Clone, Decode, Encode, PartialEq)] pub struct DidDetails { pub(crate) authentication_key: KeyIdOf, - pub(crate) key_agreement_keys: DidTotalKeyAgreementKeys, + pub(crate) key_agreement_keys: DidKeyAgreementKeys, pub(crate) delegation_key: Option>, pub(crate) attestation_key: Option>, pub(crate) public_keys: DidPublicKeyMap, @@ -49,7 +49,7 @@ pub(crate) mod v1 { .expect("Should not exceed BoundedBTreeMap bounds when setting public keys"); Self { authentication_key: authentication_key_id, - key_agreement_keys: DidTotalKeyAgreementKeys::::default(), + 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 ed70d2c45e..995ca0ad14 100644 --- a/pallets/did/src/did_details.rs +++ b/pallets/did/src/did_details.rs @@ -231,7 +231,7 @@ pub struct DidDetails { 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: DidTotalKeyAgreementKeys, + 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>, @@ -276,7 +276,7 @@ impl DidDetails { .map_err(|_| StorageError::MaxPublicKeysPerDidExceeded)?; Ok(Self { authentication_key: authentication_key_id, - key_agreement_keys: DidTotalKeyAgreementKeys::::default(), + key_agreement_keys: DidKeyAgreementKeys::::default(), attestation_key: None, delegation_key: None, service_endpoints: None, @@ -638,7 +638,7 @@ impl DidDetails { } pub(crate) type DidNewKeyAgreementKeys = BoundedBTreeSet::MaxNewKeyAgreementKeys>; -pub(crate) type DidTotalKeyAgreementKeys = BoundedBTreeSet, ::MaxTotalKeyAgreementKeys>; +pub(crate) type DidKeyAgreementKeys = BoundedBTreeSet, ::MaxTotalKeyAgreementKeys>; pub(crate) type DidVerificationKeysToRevoke = BoundedBTreeSet, ::MaxVerificationKeysToRevoke>; pub(crate) type DidPublicKeyMap = From c0422cbb04c81c482ec3975d6b75517ea5b1e172 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 11 Aug 2021 17:13:32 +0200 Subject: [PATCH 36/37] chore: update benchmarks --- pallets/attestation/src/default_weights.rs | 36 +- pallets/delegation/src/default_weights.rs | 60 ++- pallets/did/src/default_weights.rs | 224 ++++++----- pallets/kilt-launch/src/default_weights.rs | 70 ++-- .../parachain-staking/src/default_weights.rs | 352 +++++++++--------- runtimes/peregrine/src/weights/attestation.rs | 28 +- runtimes/peregrine/src/weights/delegation.rs | 42 +-- runtimes/peregrine/src/weights/did.rs | 118 +++--- runtimes/peregrine/src/weights/kilt_launch.rs | 34 +- .../src/weights/parachain_staking.rs | 4 +- runtimes/spiritnet/src/weights/kilt_launch.rs | 32 +- .../src/weights/parachain_staking.rs | 2 +- 12 files changed, 490 insertions(+), 512 deletions(-) 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/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/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/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/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/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/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: From 9b92141bb404bb8bfbb71f6ce83b1a7865c72ac5 Mon Sep 17 00:00:00 2001 From: William Freudenberger Date: Wed, 11 Aug 2021 17:32:06 +0200 Subject: [PATCH 37/37] chore: bump spec version to 20 --- runtimes/peregrine/src/lib.rs | 2 +- runtimes/spiritnet/src/lib.rs | 2 +- runtimes/standalone/src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/runtimes/peregrine/src/lib.rs b/runtimes/peregrine/src/lib.rs index e16e2b033e..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, diff --git a/runtimes/spiritnet/src/lib.rs b/runtimes/spiritnet/src/lib.rs index 3f48b02026..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, diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index 7f6bbb0b6a..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,