diff --git a/docs/dev/weights-benchmarking.md b/docs/dev/weights-benchmarking.md index b378b0f0196b5704006bf417cffbe971436d241b..1428a4015c3c3d7d581096354a42f001ad108ba6 100644 --- a/docs/dev/weights-benchmarking.md +++ b/docs/dev/weights-benchmarking.md @@ -42,7 +42,7 @@ duniter benchmark pallet --chain=CHAINSPEC --steps=50 --repeat=20 --pallet=<pall 7. Use the `runtime/common/src/weights/pallet_<pallet>.rs` generated on the reference machine in the runtimes configuration. See af62a3b9cfc42d6653b3a957836f58540c18e65a for a complete real example. -Note 1: Use relevant chainspec for the benchmarks in place of `CHAINSPEC`. For example `--chain=gdev-benchmark` has already created identities that can be confirmed by pallet identity +Note 1: Use relevant chainspec for the benchmarks in place of `CHAINSPEC`, for example `--chain=dev`. Note 2: If the reference machine does not support wasmtime, you should replace `--wasm-execution=compiled` by `--wasm-execution=interpreted-i-know-what-i-do`. @@ -53,7 +53,7 @@ by `--wasm-execution=interpreted-i-know-what-i-do`. 2. Run base block benchmarks command: ``` -duniter benchmark overhead --chain=gdev-benchmark --execution=wasm --wasm-execution=compiled --weight-path=./runtime/common/src/weights/ --warmup=10 --repeat=100 +duniter benchmark overhead --chain=dev --execution=wasm --wasm-execution=compiled --weight-path=./runtime/common/src/weights/ --warmup=10 --repeat=100 ``` 3. Commit changes and open an MR. diff --git a/node/src/chain_spec/gdev.rs b/node/src/chain_spec/gdev.rs index a7594ac7b8ba312829b2fd86be739df286943a2d..f81462d418e63e717940cbb384e7b11420d042ba 100644 --- a/node/src/chain_spec/gdev.rs +++ b/node/src/chain_spec/gdev.rs @@ -183,53 +183,6 @@ pub fn development_chain_spec() -> Result<ChainSpec, String> { } } -/// generate chainspecs used for benchmarks -pub fn benchmark_chain_spec() -> Result<ChainSpec, String> { - let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?; - - Ok(ChainSpec::from_genesis( - // Name - "Development", - // ID - "gdev-benchmark", - ChainType::Development, - move || { - gen_genesis_for_benchmark_chain( - wasm_binary, - // Initial authorities len - 1, - // Initial smiths members len - 3, - // Inital identities len - 4, - // Sudo account - get_account_id_from_seed::<sr25519::Public>("Alice"), - true, - ) - }, - // Bootnodes - vec![], - // Telemetry - None, - // Protocol ID - None, - //Fork ID - None, - // Properties - Some( - serde_json::json!({ - "tokenDecimals": TOKEN_DECIMALS, - "tokenSymbol": TOKEN_SYMBOL, - }) - .as_object() - .expect("must be a map") - .clone(), - ), - // Extensions - None, - )) -} - /// generate live network chainspecs pub fn gen_live_conf() -> Result<ChainSpec, String> { let wasm_binary = WASM_BINARY.ok_or_else(|| "wasm not available".to_string())?; @@ -494,198 +447,6 @@ fn gen_genesis_for_local_chain( } } -/// genesis used for benchmark -/// contain identities prepared for testing -fn gen_genesis_for_benchmark_chain( - wasm_binary: &[u8], - initial_authorities_len: usize, - initial_smiths_len: usize, - initial_identities_len: usize, - root_key: AccountId, - _enable_println: bool, -) -> gdev_runtime::GenesisConfig { - assert!(initial_identities_len <= 6); - assert!(initial_smiths_len <= initial_identities_len); - assert!(initial_authorities_len <= initial_smiths_len); - - let babe_epoch_duration = get_env("DUNITER_BABE_EPOCH_DURATION", 30); - let cert_validity_period = get_env("DUNITER_CERT_VALIDITY_PERIOD", 1_000); - let membership_period = get_env("DUNITER_MEMBERSHIP_PERIOD", 1_000); - let smith_cert_validity_period = get_env("DUNITER_SMITH_CERT_VALIDITY_PERIOD", 1_000); - let smith_membership_period = get_env("DUNITER_SMITH_MEMBERSHIP_PERIOD", 1_000); - let ud_creation_period = get_env("DUNITER_UD_CREATION_PERIOD", 60_000) as u64; - let ud_reeval_period = get_env("DUNITER_UD_REEEVAL_PERIOD", 1_200_000) as u64; - let ud = 1_000; - let monetary_mass = initial_identities_len as u64 * ud; - - let initial_smiths = (0..initial_smiths_len) - .map(|i| get_authority_keys_from_seed(NAMES[i])) - .collect::<Vec<AuthorityKeys>>(); - let initial_identities = (0..initial_identities_len) - .map(|i| { - ( - IdtyName::from(NAMES[i]), - get_account_id_from_seed::<sr25519::Public>(NAMES[i]), - ) - }) - .collect::<BTreeMap<IdtyName, AccountId>>(); - - gdev_runtime::GenesisConfig { - system: SystemConfig { - // Add Wasm runtime to storage. - code: wasm_binary.to_vec(), - }, - account: AccountConfig { - accounts: initial_identities - .iter() - .enumerate() - .map(|(i, (_, owner_key))| { - ( - owner_key.clone(), - GenesisAccountData { - random_id: H256(blake2_256(&(i as u32, owner_key).encode())), - balance: ud, - is_identity: true, - }, - ) - }) - .collect(), - }, - parameters: ParametersConfig { - parameters: GenesisParameters { - babe_epoch_duration, - cert_period: 15, - cert_max_by_issuer: 10, - cert_min_received_cert_to_issue_cert: 2, - cert_validity_period, - idty_confirm_period: 40, - idty_creation_period: 50, - membership_period, - pending_membership_period: 500, - ud_creation_period, - ud_reeval_period, - smith_cert_period: 15, - smith_cert_max_by_issuer: 8, - smith_cert_min_received_cert_to_issue_cert: 2, - smith_cert_validity_period, - smith_membership_period, - smith_pending_membership_period: 500, - smith_wot_first_cert_issuable_on: 20, - smith_wot_min_cert_for_membership: 2, - wot_first_cert_issuable_on: 20, - wot_min_cert_for_create_idty_right: 2, - wot_min_cert_for_membership: 2, - }, - }, - authority_discovery: Default::default(), - authority_members: AuthorityMembersConfig { - initial_authorities: initial_smiths - .iter() - .enumerate() - .map(|(i, keys)| (i as u32 + 1, (keys.0.clone(), i < initial_authorities_len))) - .collect(), - }, - balances: BalancesConfig { - total_issuance: monetary_mass, - }, - babe: BabeConfig { - authorities: Vec::with_capacity(0), - epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG), - }, - grandpa: Default::default(), - im_online: Default::default(), - session: SessionConfig { - keys: initial_smiths - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - session_keys(x.1.clone(), x.2.clone(), x.3.clone(), x.4.clone()), - ) - }) - .collect::<Vec<_>>(), - }, - sudo: SudoConfig { - // Assign network admin rights. - key: Some(root_key), - }, - technical_committee: TechnicalCommitteeConfig { - members: initial_smiths - .iter() - .map(|x| x.0.clone()) - .collect::<Vec<_>>(), - ..Default::default() - }, - identity: IdentityConfig { - identities: initial_identities - .iter() - .enumerate() - .map(|(i, (name, owner_key))| { - if i != initial_identities_len - 1 { - GenesisIdty { - index: i as u32 + 1, - name: name.clone(), - value: IdtyValue { - data: IdtyData::new(), - next_creatable_identity_on: Default::default(), - old_owner_key: None, - owner_key: owner_key.clone(), - removable_on: 0, - status: IdtyStatus::Validated, - }, - } - } else { - GenesisIdty { - index: i as u32 + 1, - name: name.clone(), - value: IdtyValue { - data: IdtyData::new(), - next_creatable_identity_on: Default::default(), - old_owner_key: None, - owner_key: owner_key.clone(), - removable_on: 0, - status: IdtyStatus::Created, - }, - } - } - }) - .collect(), - }, - membership: MembershipConfig { - memberships: (1..=initial_identities.len()) - .filter_map(|i| { - if i != initial_identities_len { - Some((i as u32, MembershipData { expire_on: 0 })) - } else { - None - } - }) - .collect(), - }, - cert: CertConfig { - apply_cert_period_at_genesis: false, - certs_by_receiver: clique_wot(initial_identities.len()), - }, - smith_membership: SmithMembershipConfig { - memberships: (1..=initial_smiths_len) - .map(|i| (i as u32, MembershipData { expire_on: 0 })) - .collect(), - }, - smith_cert: SmithCertConfig { - apply_cert_period_at_genesis: false, - certs_by_receiver: clique_wot(initial_smiths_len), - }, - universal_dividend: UniversalDividendConfig { - first_reeval: None, - first_ud: None, - initial_monetary_mass: initial_identities_len as u64 * ud, - ud, - }, - treasury: Default::default(), - } -} - /// custom genesis fn genesis_data_to_gdev_genesis_conf( genesis_data: super::gen_genesis_data::GenesisData<GenesisParameters, SessionKeys>, diff --git a/node/src/command.rs b/node/src/command.rs index c29878b74f3965a57131d34a61b9499f3c76cca9..5ad7f7f109f8c3b0f2a656e632ffa71fb69f5927 100644 --- a/node/src/command.rs +++ b/node/src/command.rs @@ -44,20 +44,6 @@ lazy_static! { }; }*/ -//Currently, only `gdev-benchmark` supports the benchmark of all the extrinsics. Storage and overhead are equivalent with `gdev-benchmark` and `gdev`, so we enforce `gdev-benchmark` for all benchmark-related commands. -#[cfg(feature = "runtime-benchmarks")] -fn ensure_dev(spec: &Box<dyn sc_service::ChainSpec>) -> std::result::Result<(), String> { - if spec.id() == "gdev-benchmark" { - Ok(()) - } else { - Err(format!( - "{}{}", - "can only use subcommand with --chain [gdev-benchmark], got ", - spec.id() - )) - } -} - /// Unwraps a [`crate::client::Client`] into the concrete runtime client. #[cfg(feature = "runtime-benchmarks")] macro_rules! unwrap_client { @@ -123,9 +109,6 @@ impl SubstrateCli for Cli { "gdev" => Box::new(chain_spec::gdev::ChainSpec::from_json_bytes( &include_bytes!("../specs/gdev-raw.json")[..], )?), - // config used for benckmarks - #[cfg(feature = "gdev")] - "gdev-benchmark" => Box::new(chain_spec::gdev::benchmark_chain_spec()?), // === GTEST === // generate dev chainspecs with Alice validator // provide DUNITER_GTEST_GENESIS env var if you want to build genesis from json @@ -314,7 +297,6 @@ pub fn run() -> sc_cli::Result<()> { Some(Subcommand::Benchmark(cmd)) => { let runner = cli.create_runner(&**cmd)?; let chain_spec = &runner.config().chain_spec; - ensure_dev(chain_spec)?; match &**cmd { BenchmarkCmd::Storage(cmd) => runner.sync_run(|mut config| { diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs index 29fb7731dbd958025f893ab2b6fe5c56591283dd..e98a7af59396d2d60f9966207c6e1f3360dc6564 100644 --- a/pallets/duniter-wot/src/mock.rs +++ b/pallets/duniter-wot/src/mock.rs @@ -136,6 +136,8 @@ impl pallet_identity::Config for Test { type RevocationSignature = TestSignature; type RuntimeEvent = RuntimeEvent; type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkSetupHandler = (); } // Membership @@ -155,6 +157,8 @@ impl pallet_membership::Config<Instance1> for Test { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type PendingMembershipPeriod = PendingMembershipPeriod; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkSetupHandler = (); } // Cert @@ -211,6 +215,8 @@ impl pallet_membership::Config<Instance2> for Test { type PendingMembershipPeriod = SmithPendingMembershipPeriod; type WeightInfo = (); type RuntimeEvent = RuntimeEvent; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkSetupHandler = (); } // SmithCert diff --git a/pallets/identity/src/benchmarking.rs b/pallets/identity/src/benchmarking.rs index 27894c2aad0611f505e56cd91cfcb5dbf7fe2315..b1ddf6b685be8aec66d02b5a9b6e82c79807d9d3 100644 --- a/pallets/identity/src/benchmarking.rs +++ b/pallets/identity/src/benchmarking.rs @@ -136,21 +136,23 @@ benchmarks! { } validate_identity { - // The validation needs to be done on the prepared identity (last genesis identity) in the benchmark genesis. - // This identity is created but not confirmed and have received enough certificates to get a membership. - // The identity needs first to be validated with a call instead of added confirmed at genesis - // to get added to avoid a MembershipRequestNotFound error. - let caller: T::AccountId = Identities::<T>::get(T::IdtyIndex::one()).unwrap().owner_key; + let index = NextIdtyIndex::<T>::get(); + let caller: T::AccountId = Identities::<T>::get(T::IdtyIndex::one()).unwrap().owner_key; let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); - let index: T::IdtyIndex = NextIdtyIndex::<T>::get() - T::IdtyIndex::one(); - let name = IdtyName("new_identity".into()); - let owner_key: T::AccountId = Identities::<T>::get(index).unwrap().owner_key; + let owner_key: T::AccountId = account("new_identity", 2, SEED); let owner_key_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(owner_key.clone()).into(); + let name = IdtyName("new_identity".into()); + Pallet::<T>::create_identity(caller_origin.clone(), owner_key.clone())?; Pallet::<T>::confirm_identity(owner_key_origin.clone(), name.clone())?; + // Should be superior to the minimal number of certificates to gain membership. + for j in 0..100 { + let issuer: T::IdtyIndex = j.into(); + T::BenchmarkSetupHandler::add_cert(&issuer, &index); + } T::BenchmarkSetupHandler::force_status_ok(&index, &owner_key); - }: _<T::RuntimeOrigin>(caller_origin, index) + }: _<T::RuntimeOrigin>(caller_origin, index.into()) verify { - assert_has_event::<T>(Event::<T>::IdtyValidated { idty_index: index }.into()); + assert_has_event::<T>(Event::<T>::IdtyValidated { idty_index: index.into() }.into()); } change_owner_key { diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs index 46b953a075d3848f7a29c0244b7f1512c8cdd8aa..8d2c12eeb66ee8cf26650f607017631270a1899d 100644 --- a/pallets/identity/src/lib.rs +++ b/pallets/identity/src/lib.rs @@ -116,7 +116,7 @@ pub mod pallet { type WeightInfo: WeightInfo; /// Type representing the a distance handler to prepare identity for benchmarking #[cfg(feature = "runtime-benchmarks")] - type BenchmarkSetupHandler: SetDistance<Self::IdtyIndex, Self::AccountId>; + type BenchmarkSetupHandler: SetupBenchmark<Self::IdtyIndex, Self::AccountId>; } // GENESIS STUFFĂ‚ // diff --git a/pallets/identity/src/traits.rs b/pallets/identity/src/traits.rs index 1d8dd0152ae9c14d137ae9b3965cf44ed99a1d2d..1bd9a2a4cbd2ece902298e22b65d4f08d845d7b4 100644 --- a/pallets/identity/src/traits.rs +++ b/pallets/identity/src/traits.rs @@ -78,11 +78,13 @@ impl<IndtyIndex> RemoveIdentityConsumers<IndtyIndex> for () { } #[cfg(feature = "runtime-benchmarks")] -pub trait SetDistance<IndtyIndex, AccountId> { +pub trait SetupBenchmark<IndtyIndex, AccountId> { fn force_status_ok(idty_index: &IndtyIndex, account: &AccountId) -> (); + fn add_cert(issuer: &IndtyIndex, receiver: &IndtyIndex) -> (); } #[cfg(feature = "runtime-benchmarks")] -impl<IdtyIndex, AccountId> SetDistance<IdtyIndex, AccountId> for () { +impl<IdtyIndex, AccountId> SetupBenchmark<IdtyIndex, AccountId> for () { fn force_status_ok(_idty_id: &IdtyIndex, _account: &AccountId) -> () {} + fn add_cert(_issuer: &IdtyIndex, _receiver: &IdtyIndex) -> () {} } diff --git a/pallets/membership/src/benchmarking.rs b/pallets/membership/src/benchmarking.rs index 3021d59f50069fe39e22ad381a9c295a4377d06a..da0ce28b79f6aa29453b8b379843f268c982865c 100644 --- a/pallets/membership/src/benchmarking.rs +++ b/pallets/membership/src/benchmarking.rs @@ -56,23 +56,21 @@ benchmarks_instance_pallet! { } } claim_membership { - let idty_index: u32 = 3; - let idty: T::IdtyId = idty_index.into(); + let idty: T::IdtyId = 3.into(); Membership::<T, I>::take(idty); PendingMembership::<T, I>::insert(idty.clone(), T::MetaData::default()); let caller: T::AccountId = T::AccountIdOf::convert(idty.clone()).unwrap(); let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); - T::BenchmarkSetupHandler::force_status_ok(&idty_index, &caller); + T::BenchmarkSetupHandler::force_status_ok(&idty, &caller); }: _<T::RuntimeOrigin>(caller_origin) verify { assert_has_event::<T, I>(Event::<T, I>::MembershipAcquired(idty).into()); } renew_membership { - let idty_index: u32 = 3; - let idty: T::IdtyId = idty_index.into(); + let idty: T::IdtyId = 3.into(); let caller: T::AccountId = T::AccountIdOf::convert(idty.clone()).unwrap(); let caller_origin: <T as frame_system::Config>::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); - T::BenchmarkSetupHandler::force_status_ok(&idty_index, &caller); + T::BenchmarkSetupHandler::force_status_ok(&idty, &caller); }: _<T::RuntimeOrigin>(caller_origin) verify { assert_has_event::<T, I>(Event::<T, I>::MembershipRenewed(idty).into()); diff --git a/pallets/membership/src/lib.rs b/pallets/membership/src/lib.rs index 6a90624e7c44eff1a8dfd8a20b612e348d8135cd..73a7e10a84450b034b6a55228bde8b77a643a6a0 100644 --- a/pallets/membership/src/lib.rs +++ b/pallets/membership/src/lib.rs @@ -43,13 +43,15 @@ use sp_std::prelude::*; use std::collections::BTreeMap; #[cfg(feature = "runtime-benchmarks")] -pub trait SetDistance<IdtyId, AccountId> { +pub trait SetupBenchmark<IdtyId, AccountId> { fn force_status_ok(idty_index: &IdtyId, account: &AccountId) -> (); + fn add_cert(_issuer: &IdtyId, _receiver: &IdtyId) -> (); } #[cfg(feature = "runtime-benchmarks")] -impl<IdtyId, AccountId> SetDistance<IdtyId, AccountId> for () { +impl<IdtyId, AccountId> SetupBenchmark<IdtyId, AccountId> for () { fn force_status_ok(_idty_id: &IdtyId, _account: &AccountId) -> () {} + fn add_cert(_issuer: &IdtyId, _receiver: &IdtyId) -> () {} } #[frame_support::pallet] @@ -94,7 +96,7 @@ pub mod pallet { + IsType<<Self as frame_system::Config>::RuntimeEvent>; type WeightInfo: WeightInfo; #[cfg(feature = "runtime-benchmarks")] - type BenchmarkSetupHandler: SetDistance<u32, Self::AccountId>; + type BenchmarkSetupHandler: SetupBenchmark<Self::IdtyId, Self::AccountId>; } // GENESIS STUFFĂ‚ // diff --git a/pallets/universal-dividend/src/benchmarking.rs b/pallets/universal-dividend/src/benchmarking.rs index 5d2c636323be4f94535e8ed3c36f0cfd749058b7..9f0b147c171684ef502878c9edb3a41008d41d3b 100644 --- a/pallets/universal-dividend/src/benchmarking.rs +++ b/pallets/universal-dividend/src/benchmarking.rs @@ -84,11 +84,11 @@ benchmarks! { impl_benchmark_test_suite!( Pallet, crate::mock::new_test_ext(crate::mock::UniversalDividendConfig { - first_reeval: 48_000, - first_ud: 6_000, + first_reeval: Some(48_000), + first_ud: Some(6_000), initial_monetary_mass: 0, initial_members: vec![1], - ud, + ud: 10, }), crate::mock::Test ); diff --git a/runtime/common/src/providers.rs b/runtime/common/src/providers.rs index e8ddf8102dbae4d471b35a370260bdba7c76b6f8..9680798aa405cf46d70470eabf8d9ccd42721e14 100644 --- a/runtime/common/src/providers.rs +++ b/runtime/common/src/providers.rs @@ -132,9 +132,11 @@ macro_rules! impl_benchmark_setup_handler { impl<T> $t for BenchmarkSetupHandler<T> where T: pallet_distance::Config, + T: pallet_certification::Config<frame_support::instances::Instance1>, + <T as pallet_certification::Config<frame_support::instances::Instance1>>::IdtyIndex: From<u32>, { fn force_status_ok( - idty_id: &<T as pallet_identity::Config>::IdtyIndex, + idty_id: &IdtyIndex, account: &<T as frame_system::Config>::AccountId, ) -> () { let _ = pallet_distance::Pallet::<T>::set_distance_status( @@ -142,13 +144,14 @@ macro_rules! impl_benchmark_setup_handler { Some((account.clone(), pallet_distance::DistanceStatus::Valid)), ); } - // TODO: All the required preparation for the benchmarks, depending on the coupling - // between pallets, would be implemented here when moving away from prepared identities from the gdev-benchmark. + fn add_cert(issuer: &IdtyIndex, receiver: &IdtyIndex) { + let _ = pallet_certification::Pallet::<T, frame_support::instances::Instance1>::do_add_cert_checked((*issuer).into(), (*receiver).into(), false); + } } }; } #[cfg(feature = "runtime-benchmarks")] -impl_benchmark_setup_handler!(pallet_membership::SetDistance<<T as pallet_identity::Config>::IdtyIndex, T::AccountId>); +impl_benchmark_setup_handler!(pallet_membership::SetupBenchmark<<T as pallet_identity::Config>::IdtyIndex, T::AccountId>); #[cfg(feature = "runtime-benchmarks")] -impl_benchmark_setup_handler!(pallet_identity::traits::SetDistance<<T as pallet_identity::Config>::IdtyIndex, T::AccountId>); +impl_benchmark_setup_handler!(pallet_identity::traits::SetupBenchmark<<T as pallet_identity::Config>::IdtyIndex, T::AccountId>); diff --git a/runtime/g1/src/lib.rs b/runtime/g1/src/lib.rs index 62517b4f03f35f28096326e102765fe95fb3fe42..11d4afe1e674abee1cdd6d6881fd5921e2c6ad8f 100644 --- a/runtime/g1/src/lib.rs +++ b/runtime/g1/src/lib.rs @@ -132,7 +132,6 @@ pub type TechnicalCommitteeInstance = Instance2; #[cfg(feature = "runtime-benchmarks")] mod benches { define_benchmarks!( - // For completion, benchmarks only running on `gdev-benchmark`. [pallet_certification, Cert] [pallet_certification, SmithCert] [pallet_oneshot_account, OneshotAccount] diff --git a/runtime/gtest/src/lib.rs b/runtime/gtest/src/lib.rs index 083a83ec7fd858ece155a88c2798d5e40ac840e4..b04fd581e584dbdf2520225bca46cc18eebcb88f 100644 --- a/runtime/gtest/src/lib.rs +++ b/runtime/gtest/src/lib.rs @@ -137,7 +137,6 @@ pub type TechnicalCommitteeInstance = Instance2; #[cfg(feature = "runtime-benchmarks")] mod benches { define_benchmarks!( - // For completion, benchmarks only running on `gdev-benchmark`. [pallet_certification, Cert] [pallet_certification, SmithCert] [pallet_oneshot_account, OneshotAccount]