diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs index 0cc9fc0895b89dc5a44acb99ae3f936da3267fd3..1da429a4a0b0d3de3cfd095abf6181f2f4de55c3 100644 --- a/pallets/identity/src/lib.rs +++ b/pallets/identity/src/lib.rs @@ -620,3 +620,32 @@ where Ok(result) } } + +pub struct IdtyDataIter<T: Config>( + Box<dyn Iterator<Item = IdtyValue<T::BlockNumber, T::AccountId, T::IdtyData>>>, +); + +impl<T: Config> From<Option<Vec<u8>>> for IdtyDataIter<T> { + fn from(maybe_key: Option<Vec<u8>>) -> Self { + let mut iter = Identities::<T>::iter_values(); + if let Some(key) = maybe_key { + iter.set_last_raw_key(key); + } + Self(Box::new(iter)) + } +} + +impl<T: Config> Iterator for IdtyDataIter<T> { + type Item = (T::AccountId, T::IdtyData); + + fn next(&mut self) -> Option<Self::Item> { + if let Some(IdtyValue { + owner_key, data, .. + }) = self.0.next() + { + Some((owner_key, data)) + } else { + None + } + } +} diff --git a/pallets/universal-dividend/Cargo.toml b/pallets/universal-dividend/Cargo.toml index 27df84d6e81bf59ad29ba5cc982eddf8fd67510e..f6ab06ac8ba9283d204d110efe13d55e6b4f87e1 100644 --- a/pallets/universal-dividend/Cargo.toml +++ b/pallets/universal-dividend/Cargo.toml @@ -12,7 +12,7 @@ version = '3.0.0' default = ['std'] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", - "pallet-balances" + "pallet-balances", ] std = [ 'codec/std', diff --git a/pallets/universal-dividend/src/benchmarking.rs b/pallets/universal-dividend/src/benchmarking.rs index 0d4cfafc686952dcfdda3e93da440edded17adcc..0dd6b662d68a911565134f4fd2d9491611379472 100644 --- a/pallets/universal-dividend/src/benchmarking.rs +++ b/pallets/universal-dividend/src/benchmarking.rs @@ -18,8 +18,8 @@ use super::*; -use frame_benchmarking::{account, benchmarks, whitelisted_caller}; -use frame_support::pallet_prelude::IsType; +use frame_benchmarking::{account, benchmarks, whitelist_account, whitelisted_caller}; +use frame_support::pallet_prelude::{BoundedVec, IsType}; use frame_support::traits::{Get, OnInitialize}; use frame_system::RawOrigin; use pallet_balances::Pallet as Balances; @@ -68,6 +68,40 @@ benchmarks! { }: { Pallet::<T>::on_initialize(block_number.into()); } verify { } + // Benchmark `claim_uds` extrinsic with the worst possible conditions: + // * UDs have never been claimed + // * The maximum number of revaluations has taken place since + where_clause { + where + T: pallet_balances::Config, T::Balance: From<u64>, + <T::Currency as Currency<T::AccountId>>::Balance: IsType<T::Balance> + } + claim_uds { + let n in 1 .. T::MaxPastReeval::get(); + + // Caller should be a member + let caller: T::AccountId = T::MembersStorageIter::from(None) + .next() + .expect("we need at least one member") + .0; + + // Simulate n reevals + let mut past_reevals = BoundedVec::default(); + for i in 0..n { + past_reevals + .try_push((((3 * i) + 1) as u16, ((1_000 + (100 * i)) as u32).into())) + .expect("unreachable"); + } + PastReevals::<T>::put(past_reevals); + + // Simulate 3n+2 UDs + CurrentUdIndex::<T>::put(((3 * n) + 2) as u16); + + whitelist_account!(caller); + }: claim_uds(RawOrigin::Signed(caller)) + verify { + } + // Benchmark `transfer_ud` extrinsic with the worst possible conditions: // * Transfer will kill the sender account. // * Transfer will create the recipient account. @@ -121,7 +155,7 @@ benchmarks! { first_reeval: 8, first_ud: 1_000, initial_monetary_mass: 0, - initial_members: Vec::new() + initial_members: vec![1], }), crate::mock::Test ); diff --git a/pallets/universal-dividend/src/lib.rs b/pallets/universal-dividend/src/lib.rs index d6b181a26a4fc7b7343ceeef3cea5a8dbafe63fe..f6ebcc8afb51766c13bcd7ba91b6ffb67087d426 100644 --- a/pallets/universal-dividend/src/lib.rs +++ b/pallets/universal-dividend/src/lib.rs @@ -43,6 +43,7 @@ pub mod pallet { use frame_support::traits::{StorageVersion, StoredMap}; use frame_system::pallet_prelude::*; use sp_runtime::traits::Convert; + use sp_std::vec::Vec; pub type BalanceOf<T> = <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance; @@ -71,6 +72,9 @@ pub mod pallet { type MembersCount: Get<BalanceOf<Self>>; /// Somethings that must provide the list of accounts ids allowed to create the universal dividend type MembersStorage: frame_support::traits::StoredMap<Self::AccountId, FirstEligibleUd>; + /// An iterator over all members + type MembersStorageIter: From<Option<Vec<u8>>> + + Iterator<Item = (Self::AccountId, FirstEligibleUd)>; #[pallet::constant] /// Square of the money growth rate per ud reevaluation period type SquareMoneyGrowthRate: Get<Perbill>; diff --git a/pallets/universal-dividend/src/mock.rs b/pallets/universal-dividend/src/mock.rs index 238a3d5968f31f45be385cd1ee505f57e1044ff2..a53a0fe966f6cef5d1c78be10bae9785417ce984 100644 --- a/pallets/universal-dividend/src/mock.rs +++ b/pallets/universal-dividend/src/mock.rs @@ -18,7 +18,7 @@ use super::*; use crate::{self as pallet_universal_dividend}; use frame_support::{ parameter_types, - traits::{Everything, OnFinalize, OnInitialize, StorageMapShim}, + traits::{Everything, OnFinalize, OnInitialize}, }; use frame_system as system; use sp_core::H256; @@ -102,13 +102,49 @@ parameter_types! { pub const UdReevalPeriod: BlockNumber = 8; } +pub struct TestMembersStorage; +impl frame_support::traits::StoredMap<u64, FirstEligibleUd> for TestMembersStorage { + fn get(key: &u64) -> FirstEligibleUd { + crate::TestMembers::<Test>::get(key) + } + fn try_mutate_exists<R, E: From<sp_runtime::DispatchError>>( + key: &u64, + f: impl FnOnce(&mut Option<FirstEligibleUd>) -> Result<R, E>, + ) -> Result<R, E> { + let mut value = Some(crate::TestMembers::<Test>::get(key)); + let result = f(&mut value)?; + if let Some(value) = value { + crate::TestMembers::<Test>::insert(key, value) + } + Ok(result) + } +} +pub struct TestMembersStorageIter(frame_support::storage::PrefixIterator<(u64, FirstEligibleUd)>); +impl From<Option<Vec<u8>>> for TestMembersStorageIter { + fn from(maybe_key: Option<Vec<u8>>) -> Self { + let mut iter = crate::TestMembers::<Test>::iter(); + if let Some(key) = maybe_key { + iter.set_last_raw_key(key); + } + Self(iter) + } +} +impl Iterator for TestMembersStorageIter { + type Item = (u64, FirstEligibleUd); + + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } +} + impl pallet_universal_dividend::Config for Test { type BlockNumberIntoBalance = sp_runtime::traits::ConvertInto; type Currency = pallet_balances::Pallet<Test>; type Event = Event; type MaxPastReeval = frame_support::traits::ConstU32<2>; type MembersCount = MembersCount; - type MembersStorage = StorageMapShim<crate::TestMembers<Test>, (), u64, FirstEligibleUd>; + type MembersStorage = TestMembersStorage; + type MembersStorageIter = TestMembersStorageIter; type SquareMoneyGrowthRate = SquareMoneyGrowthRate; type UdCreationPeriod = UdCreationPeriod; type UdReevalPeriod = UdReevalPeriod; diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs index 46f01f6658fcf525561a1a5a00b2001280430c5c..be602e77dc69c1e0a2cbbc9236e0d8c9f72ea6cc 100644 --- a/runtime/common/src/pallets_config.rs +++ b/runtime/common/src/pallets_config.rs @@ -400,6 +400,7 @@ macro_rules! pallets_config { type MaxPastReeval = frame_support::traits::ConstU32<4>; type MembersCount = MembersCount; type MembersStorage = Identity; + type MembersStorageIter = pallet_identity::IdtyDataIter<Runtime>; type SquareMoneyGrowthRate = SquareMoneyGrowthRate; type UdCreationPeriod = UdCreationPeriod; type UdReevalPeriod = UdReevalPeriod;