diff --git a/Cargo.lock b/Cargo.lock index 47aee8f69532d2b4ac1d7326d52de6025540f610..582ce61c7d1bb2da5971ab36f4e0cfe6f02b1a1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5844,10 +5844,12 @@ dependencies = [ name = "pallet-distance" version = "1.0.0" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "pallet-authority-members", "pallet-authorship", + "pallet-balances", "pallet-identity", "pallet-membership", "pallet-session", @@ -5856,6 +5858,8 @@ dependencies = [ "sp-core", "sp-distance", "sp-inherents", + "sp-io", + "sp-keystore", "sp-runtime", "sp-std 5.0.0", ] diff --git a/pallets/distance/Cargo.toml b/pallets/distance/Cargo.toml index 1a08c2f2fd428782d39aee506f315629a47494d2..06d5f430cb4c38c81dd0958f569ccd323d0ddbd9 100644 --- a/pallets/distance/Cargo.toml +++ b/pallets/distance/Cargo.toml @@ -11,8 +11,10 @@ version = '1.0.0' [features] default = ['std'] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] std = [ 'codec/std', + 'frame-benchmarking/std', 'frame-support/std', 'pallet-authority-members/std', 'pallet-authorship/std', @@ -43,6 +45,12 @@ features = ['derive'] package = 'parity-scale-codec' version = '3.1.5' +[dependencies.frame-benchmarking] +default-features = false +git = 'https://github.com/duniter/substrate' +optional = true +branch = 'duniter-substrate-v0.9.42' + [dependencies.frame-support] default-features = false git = 'https://github.com/duniter/substrate' @@ -83,6 +91,11 @@ default-features = false git = 'https://github.com/duniter/substrate' branch = 'duniter-substrate-v0.9.42' +[dev-dependencies] +pallet-balances = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42' } +sp-io = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42' } +sp-keystore = { git = 'https://github.com/duniter/substrate', branch = 'duniter-substrate-v0.9.42' } + ### DOC ### [package.metadata.docs.rs] diff --git a/pallets/distance/src/benchmarking.rs b/pallets/distance/src/benchmarking.rs new file mode 100644 index 0000000000000000000000000000000000000000..92a72420ef937bc8364aa60a21b13ee2d5bd0559 --- /dev/null +++ b/pallets/distance/src/benchmarking.rs @@ -0,0 +1,54 @@ +// Copyright 2023 Axiom-Team +// +// This file is part of Duniter-v2S. +// +// Duniter-v2S is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Duniter-v2S is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; + +use codec::Encode; +use frame_benchmarking::{account, benchmarks}; +use frame_support::traits::OnFinalize; +use frame_system::RawOrigin; +use sp_core::Get; +use sp_runtime::{traits::One, AccountId32, MultiSigner}; + +use crate::Pallet as Distance; + +const SEED: u32 = 1; + +benchmarks! { + on_finalize { + DidUpdate::<T>::set(true); + }: { Distance::<T>::on_finalize(Default::default()); } + verify { + assert!(!DidUpdate::<T>::get()); + } + + where_clause { + where + T::AccountId: From<AccountId32>, + T::IdtyIndex: From<u32>, + } + request_distance_evaluation { + let caller: T::AccountId = pallet_identity::Identities::<T>::get(T::IdtyIndex::one()).unwrap().owner_key; // Alice + let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); + }: _<T::RuntimeOrigin>(caller_origin.clone()) + verify { + + } + + impl_benchmark_test_suite!(Distance, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/pallets/distance/src/lib.rs b/pallets/distance/src/lib.rs index 3ed6ab2902d6424d0963a1f844f5a1ed51d37729..139b1237a17f6244a6eb830bc204a9036ea71641 100644 --- a/pallets/distance/src/lib.rs +++ b/pallets/distance/src/lib.rs @@ -16,7 +16,12 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + mod median; +#[cfg(test)] +mod mock; mod traits; mod types; mod weights; diff --git a/pallets/distance/src/mock.rs b/pallets/distance/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..24e163a76cb5b036b334779fae447f5424ab968e --- /dev/null +++ b/pallets/distance/src/mock.rs @@ -0,0 +1,286 @@ +// Copyright 2023 Axiom-Team +// +// This file is part of Duniter-v2S. +// +// Duniter-v2S is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// Duniter-v2S is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with Duniter-v2S. If not, see <https://www.gnu.org/licenses/>. + +use super::*; +use crate::{self as pallet_distance}; +use core::marker::PhantomData; +use frame_support::{ + parameter_types, + traits::{Everything, GenesisBuild, OnFinalize, OnInitialize}, +}; +use frame_system as system; +use pallet_balances::AccountData; +use pallet_session::ShouldEndSession; +use sp_core::{ConstU32, Pair, H256}; +use sp_keystore::{testing::MemoryKeystore, KeystoreExt}; +use sp_runtime::{ + impl_opaque_keys, + key_types::DUMMY, + testing::{Header, UintAuthorityId}, + traits::{ + BlakeTwo256, ConvertInto, IdentifyAccount, IdentityLookup, IsMember, OpaqueKeys, Verify, + }, + KeyTypeId, MultiSignature, MultiSigner, Perbill, +}; +use std::sync::Arc; + +type Balance = u64; +type Block = frame_system::mocking::MockBlock<Test>; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>; +pub type Signature = MultiSignature; +pub type AccountPublic = <Signature as Verify>::Signer; +pub type AccountId = <AccountPublic as IdentifyAccount>::AccountId; + +fn account(id: u8) -> AccountId { + let pair = sp_core::sr25519::Pair::from_seed(&[id; 32]); + MultiSigner::Sr25519(pair.public()).into_account() +} + +impl_opaque_keys! { + pub struct MockSessionKeys { + pub dummy: UintAuthorityId, + } +} + +impl From<UintAuthorityId> for MockSessionKeys { + fn from(dummy: UintAuthorityId) -> Self { + Self { dummy } + } +} + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event<T>}, + Session: pallet_session::{Pallet, Call, Storage, Config<T>, Event}, + Authorship: pallet_authorship::{Pallet, Storage}, + AuthorityMembers: pallet_authority_members::{Pallet, Call, Storage, Config<T>, Event<T>}, + Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>}, + Identity: pallet_identity::{Pallet, Call, Storage, Config<T>, Event<T>}, + Distance: pallet_distance::{Pallet, Call, Storage}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; +} + +impl system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup<Self::AccountId>; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = AccountData<u64>; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +pub struct TestSessionHandler; +impl pallet_session::SessionHandler<AccountId> for TestSessionHandler { + const KEY_TYPE_IDS: &'static [KeyTypeId] = &[DUMMY]; + + fn on_new_session<Ks: OpaqueKeys>( + _changed: bool, + _validators: &[(AccountId, Ks)], + _queued_validators: &[(AccountId, Ks)], + ) { + } + + fn on_disabled(_validator_index: u32) {} + + fn on_genesis_session<Ks: OpaqueKeys>(_validators: &[(AccountId, Ks)]) {} +} + +const SESSION_LENGTH: u64 = 5; +pub struct TestShouldEndSession; +impl ShouldEndSession<u64> for TestShouldEndSession { + fn should_end_session(now: u64) -> bool { + now % SESSION_LENGTH == 0 + } +} + +impl pallet_session::Config for Test { + type RuntimeEvent = RuntimeEvent; + type ValidatorId = AccountId; + type ValidatorIdOf = ConvertInto; + type ShouldEndSession = TestShouldEndSession; + type NextSessionRotation = (); + type SessionManager = AuthorityMembers; + type SessionHandler = TestSessionHandler; + type Keys = MockSessionKeys; + type WeightInfo = (); +} + +pub struct FullIdentificationOfImpl; +impl sp_runtime::traits::Convert<AccountId, Option<()>> for FullIdentificationOfImpl { + fn convert(_: AccountId) -> Option<()> { + Some(()) + } +} +impl pallet_session::historical::Config for Test { + type FullIdentification = (); + type FullIdentificationOf = FullIdentificationOfImpl; +} + +impl pallet_authorship::Config for Test { + type FindAuthor = pallet_session::FindAccountFromAuthorIndex<Self, ()>; + type EventHandler = (); +} + +pub struct TestIsSmithMember; +impl IsMember<u32> for TestIsSmithMember { + fn is_member(member_id: &u32) -> bool { + member_id % 3 == 0 + } +} + +pub struct IdentityIndexOf<T: pallet_identity::Config>(PhantomData<T>); + +impl<T: pallet_identity::Config> sp_runtime::traits::Convert<T::AccountId, Option<T::IdtyIndex>> + for IdentityIndexOf<T> +{ + fn convert(account_id: T::AccountId) -> Option<T::IdtyIndex> { + pallet_identity::Pallet::<T>::identity_index_of(account_id) + } +} + +impl pallet_authority_members::Config for Test { + type KeysWrapper = MockSessionKeys; + type IsMember = TestIsSmithMember; + type MaxAuthorities = ConstU32<4>; + type MemberId = u32; + type MemberIdOf = IdentityIndexOf<Self>; + type OnNewSession = (); + type OnRemovedMember = (); + type RemoveMemberOrigin = system::EnsureRoot<AccountId>; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 10; + pub const MaxLocks: u32 = 50; +} + +impl pallet_balances::Config for Test { + type Balance = Balance; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = pallet_balances::weights::SubstrateWeight<Test>; + type MaxLocks = MaxLocks; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type RuntimeEvent = RuntimeEvent; + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + pub const ChangeOwnerKeyPeriod: u64 = 10; + pub const ConfirmPeriod: u64 = 2; + pub const IdtyCreationPeriod: u64 = 3; + pub const MaxInactivityPeriod: u64 = 5; + pub const ValidationPeriod: u64 = 2; +} + +pub struct IdtyNameValidatorTestImpl; +impl pallet_identity::traits::IdtyNameValidator for IdtyNameValidatorTestImpl { + fn validate(idty_name: &pallet_identity::IdtyName) -> bool { + idty_name.0.len() < 16 + } +} + +impl pallet_identity::Config for Test { + type ChangeOwnerKeyPeriod = ChangeOwnerKeyPeriod; + type ConfirmPeriod = ConfirmPeriod; + type CheckIdtyCallAllowed = (); + type IdtyCreationPeriod = IdtyCreationPeriod; + type IdtyData = (); + type IdtyNameValidator = IdtyNameValidatorTestImpl; + type IdtyIndex = u32; + type IdtyRemovalOtherReason = (); + type NewOwnerKeySigner = AccountPublic; + type NewOwnerKeySignature = Signature; + type OnIdtyChange = (); + type RemoveIdentityConsumers = (); + type RevocationSigner = AccountPublic; + type RevocationSignature = Signature; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); +} + +parameter_types! { + pub const MinAccessibleReferees: Perbill = Perbill::from_percent(80); +} +impl pallet_distance::Config for Test { + type Currency = Balances; + type EvaluationPrice = frame_support::traits::ConstU64<1000>; + type MinAccessibleReferees = MinAccessibleReferees; + type ResultExpiration = frame_support::traits::ConstU32<720>; +} + +// Build genesis storage according to the mock runtime. +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default() + .build_storage::<Test>() + .unwrap(); + + frame_support::BasicExternalities::execute_with_storage(&mut t, || {}); + + let keystore = MemoryKeystore::new(); + let mut ext = sp_io::TestExternalities::new(t); + ext.register_extension(KeystoreExt(Arc::new(keystore))); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +pub fn run_to_block(n: u64) { + while System::block_number() < n { + Identity::on_finalize(System::block_number()); + Distance::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::reset_events(); + System::set_block_number(System::block_number() + 1); + System::on_initialize(System::block_number()); + Identity::on_initialize(System::block_number()); + Distance::on_initialize(System::block_number()); + } +}