From 35535efb3d9f4d3b3be63c3c2bcf963883ab6af1 Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Tue, 29 Oct 2024 09:52:00 +0100 Subject: [PATCH 1/5] [pallet-revive] implement tx origin API (#6105) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement a syscall to retreive the transaction origin. --------- Signed-off-by: Cyrill Leutwiler Signed-off-by: xermicus Co-authored-by: GitHub Action Co-authored-by: command-bot <> Co-authored-by: Alexander Theißen --- prdoc/pr_6105.prdoc | 14 + .../frame/revive/fixtures/contracts/origin.rs | 62 ++ .../frame/revive/src/benchmarking/mod.rs | 18 + substrate/frame/revive/src/exec.rs | 72 ++ substrate/frame/revive/src/tests.rs | 16 + substrate/frame/revive/src/wasm/runtime.rs | 18 + substrate/frame/revive/src/weights.rs | 903 +++++++++--------- substrate/frame/revive/uapi/src/host.rs | 11 + .../frame/revive/uapi/src/host/riscv32.rs | 3 +- 9 files changed, 670 insertions(+), 447 deletions(-) create mode 100644 prdoc/pr_6105.prdoc create mode 100644 substrate/frame/revive/fixtures/contracts/origin.rs diff --git a/prdoc/pr_6105.prdoc b/prdoc/pr_6105.prdoc new file mode 100644 index 000000000000..f8339c6ce535 --- /dev/null +++ b/prdoc/pr_6105.prdoc @@ -0,0 +1,14 @@ +title: '[pallet-revive] implement tx origin API' + +doc: +- audience: + - Runtime Dev + description: Implement a syscall to retreive the transaction origin. + +crates: +- name: pallet-revive + bump: minor +- name: pallet-revive-uapi + bump: minor +- name: pallet-revive-fixtures + bump: patch diff --git a/substrate/frame/revive/fixtures/contracts/origin.rs b/substrate/frame/revive/fixtures/contracts/origin.rs new file mode 100644 index 000000000000..8e9afd8e8052 --- /dev/null +++ b/substrate/frame/revive/fixtures/contracts/origin.rs @@ -0,0 +1,62 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests that the `origin` syscall works. +//! The fixture returns the observed origin if the caller is not the origin, +//! otherwise call itself recursively and assert the returned origin to match. + +#![no_std] +#![no_main] + +extern crate common; +use uapi::{HostFn, HostFnImpl as api}; + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn deploy() {} + +#[no_mangle] +#[polkavm_derive::polkavm_export] +pub extern "C" fn call() { + let mut caller = [0; 20]; + api::caller(&mut caller); + + let mut origin = [0; 20]; + api::origin(&mut origin); + + if caller != origin { + api::return_value(Default::default(), &origin); + } + + let mut addr = [0u8; 20]; + api::address(&mut addr); + + let mut buf = [0u8; 20]; + api::call( + uapi::CallFlags::ALLOW_REENTRY, + &addr, + 0u64, + 0u64, + None, + &[0; 32], + &[], + Some(&mut &mut buf[..]), + ) + .unwrap(); + + assert_eq!(buf, origin); +} diff --git a/substrate/frame/revive/src/benchmarking/mod.rs b/substrate/frame/revive/src/benchmarking/mod.rs index 8c9bf2cf70f0..bf27c660e1a4 100644 --- a/substrate/frame/revive/src/benchmarking/mod.rs +++ b/substrate/frame/revive/src/benchmarking/mod.rs @@ -523,6 +523,24 @@ mod benchmarks { ); } + #[benchmark(pov_mode = Measured)] + fn seal_origin() { + let len = H160::len_bytes(); + build_runtime!(runtime, memory: [vec![0u8; len as _], ]); + + let result; + #[block] + { + result = runtime.bench_origin(memory.as_mut_slice(), 0); + } + + assert_ok!(result); + assert_eq!( + ::decode(&mut &memory[..]).unwrap(), + T::AddressMapper::to_address(&runtime.ext().origin().account_id().unwrap()) + ); + } + #[benchmark(pov_mode = Measured)] fn seal_is_contract() { let Contract { account_id, .. } = diff --git a/substrate/frame/revive/src/exec.rs b/substrate/frame/revive/src/exec.rs index 9f3a75c0090d..8b9fd660296e 100644 --- a/substrate/frame/revive/src/exec.rs +++ b/substrate/frame/revive/src/exec.rs @@ -284,6 +284,9 @@ pub trait Ext: sealing::Sealed { /// Returns the caller. fn caller(&self) -> Origin; + /// Return the origin of the whole call stack. + fn origin(&self) -> &Origin; + /// Check if a contract lives at the specified `address`. fn is_contract(&self, address: &H160) -> bool; @@ -1547,6 +1550,10 @@ where } } + fn origin(&self) -> &Origin { + &self.origin + } + fn is_contract(&self, address: &H160) -> bool { ContractInfoOf::::contains_key(&address) } @@ -2381,6 +2388,71 @@ mod tests { assert_eq!(WitnessedCallerCharlie::get(), Some(BOB_ADDR)); } + #[test] + fn origin_returns_proper_values() { + parameter_types! { + static WitnessedCallerBob: Option = None; + static WitnessedCallerCharlie: Option = None; + } + + let bob_ch = MockLoader::insert(Call, |ctx, _| { + // Record the origin for bob. + WitnessedCallerBob::mutate(|witness| { + let origin = ctx.ext.origin(); + *witness = Some(::AddressMapper::to_address( + &origin.account_id().unwrap(), + )); + }); + + // Call into CHARLIE contract. + assert_matches!( + ctx.ext.call( + Weight::zero(), + U256::zero(), + &CHARLIE_ADDR, + U256::zero(), + vec![], + true, + false + ), + Ok(_) + ); + exec_success() + }); + let charlie_ch = MockLoader::insert(Call, |ctx, _| { + // Record the origin for charlie. + WitnessedCallerCharlie::mutate(|witness| { + let origin = ctx.ext.origin(); + *witness = Some(::AddressMapper::to_address( + &origin.account_id().unwrap(), + )); + }); + exec_success() + }); + + ExtBuilder::default().build().execute_with(|| { + place_contract(&BOB, bob_ch); + place_contract(&CHARLIE, charlie_ch); + let origin = Origin::from_account_id(ALICE); + let mut storage_meter = storage::meter::Meter::new(&origin, 0, 0).unwrap(); + + let result = MockStack::run_call( + origin, + BOB_ADDR, + &mut GasMeter::::new(GAS_LIMIT), + &mut storage_meter, + 0, + vec![], + None, + ); + + assert_matches!(result, Ok(_)); + }); + + assert_eq!(WitnessedCallerBob::get(), Some(ALICE_ADDR)); + assert_eq!(WitnessedCallerCharlie::get(), Some(ALICE_ADDR)); + } + #[test] fn is_contract_returns_proper_values() { let bob_ch = MockLoader::insert(Call, |ctx, _| { diff --git a/substrate/frame/revive/src/tests.rs b/substrate/frame/revive/src/tests.rs index 1b5e64739d88..37167d20a438 100644 --- a/substrate/frame/revive/src/tests.rs +++ b/substrate/frame/revive/src/tests.rs @@ -4476,6 +4476,22 @@ mod run_tests { }); } + #[test] + fn origin_api_works() { + let (code, _) = compile_module("origin").unwrap(); + + ExtBuilder::default().existential_deposit(100).build().execute_with(|| { + let _ = ::Currency::set_balance(&ALICE, 1_000_000); + + // Create fixture: Constructor does nothing + let Contract { addr, .. } = + builder::bare_instantiate(Code::Upload(code)).build_and_unwrap_contract(); + + // Call the contract: Asserts the origin API to work as expected + assert_ok!(builder::call(addr).build()); + }); + } + #[test] fn code_hash_works() { let (code_hash_code, self_code_hash) = compile_module("code_hash").unwrap(); diff --git a/substrate/frame/revive/src/wasm/runtime.rs b/substrate/frame/revive/src/wasm/runtime.rs index 00be26aeaf8b..4221498a725c 100644 --- a/substrate/frame/revive/src/wasm/runtime.rs +++ b/substrate/frame/revive/src/wasm/runtime.rs @@ -291,6 +291,8 @@ pub enum RuntimeCosts { CopyToContract(u32), /// Weight of calling `seal_caller`. Caller, + /// Weight of calling `seal_origin`. + Origin, /// Weight of calling `seal_is_contract`. IsContract, /// Weight of calling `seal_code_hash`. @@ -448,6 +450,7 @@ impl Token for RuntimeCosts { CopyToContract(len) => T::WeightInfo::seal_input(len), CopyFromContract(len) => T::WeightInfo::seal_return(len), Caller => T::WeightInfo::seal_caller(), + Origin => T::WeightInfo::seal_origin(), IsContract => T::WeightInfo::seal_is_contract(), CodeHash => T::WeightInfo::seal_code_hash(), OwnCodeHash => T::WeightInfo::seal_own_code_hash(), @@ -1388,6 +1391,21 @@ pub mod env { )?) } + /// Stores the address of the call stack origin into the supplied buffer. + /// See [`pallet_revive_uapi::HostFn::origin`]. + #[api_version(0)] + fn origin(&mut self, memory: &mut M, out_ptr: u32) -> Result<(), TrapReason> { + self.charge_gas(RuntimeCosts::Origin)?; + let origin = ::AddressMapper::to_address(self.ext.origin().account_id()?); + Ok(self.write_fixed_sandbox_output( + memory, + out_ptr, + origin.as_bytes(), + false, + already_charged, + )?) + } + /// Checks whether a specified address belongs to a contract. /// See [`pallet_revive_uapi::HostFn::is_contract`]. #[api_version(0)] diff --git a/substrate/frame/revive/src/weights.rs b/substrate/frame/revive/src/weights.rs index 3203a0cba9fb..bf2beb94d7a5 100644 --- a/substrate/frame/revive/src/weights.rs +++ b/substrate/frame/revive/src/weights.rs @@ -18,9 +18,9 @@ //! Autogenerated weights for `pallet_revive` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-10-16, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-dr4vwrkf-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-wmcgzesc-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -63,6 +63,7 @@ pub trait WeightInfo { fn dispatch_as_fallback_account() -> Weight; fn noop_host_fn(r: u32, ) -> Weight; fn seal_caller() -> Weight; + fn seal_origin() -> Weight; fn seal_is_contract() -> Weight; fn seal_code_hash() -> Weight; fn seal_own_code_hash() -> Weight; @@ -129,8 +130,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 3_053_000 picoseconds. - Weight::from_parts(3_150_000, 1594) + // Minimum execution time: 3_293_000 picoseconds. + Weight::from_parts(3_530_000, 1594) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -140,10 +141,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `425 + k * (69 ±0)` // Estimated: `415 + k * (70 ±0)` - // Minimum execution time: 15_219_000 picoseconds. - Weight::from_parts(12_576_960, 415) - // Standard Error: 1_429 - .saturating_add(Weight::from_parts(1_341_896, 0).saturating_mul(k.into())) + // Minimum execution time: 16_103_000 picoseconds. + Weight::from_parts(16_692_000, 415) + // Standard Error: 2_700 + .saturating_add(Weight::from_parts(1_493_715, 0).saturating_mul(k.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -163,12 +164,14 @@ impl WeightInfo for SubstrateWeight { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// The range of component `c` is `[0, 262144]`. - fn call_with_code_per_byte(_c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1519` - // Estimated: `7459` - // Minimum execution time: 88_906_000 picoseconds. - Weight::from_parts(93_353_224, 7459) + fn call_with_code_per_byte(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1561` + // Estimated: `7501` + // Minimum execution time: 98_125_000 picoseconds. + Weight::from_parts(105_486_409, 7501) + // Standard Error: 2 + .saturating_add(Weight::from_parts(4, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -191,11 +194,11 @@ impl WeightInfo for SubstrateWeight { fn instantiate_with_code(_c: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `416` - // Estimated: `6360` - // Minimum execution time: 202_688_000 picoseconds. - Weight::from_parts(197_366_807, 6360) - // Standard Error: 13 - .saturating_add(Weight::from_parts(4_261, 0).saturating_mul(i.into())) + // Estimated: `6348` + // Minimum execution time: 204_069_000 picoseconds. + Weight::from_parts(206_289_328, 6348) + // Standard Error: 16 + .saturating_add(Weight::from_parts(4_438, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -216,12 +219,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 262144]`. fn instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1313` - // Estimated: `4779` - // Minimum execution time: 169_246_000 picoseconds. - Weight::from_parts(149_480_457, 4779) - // Standard Error: 16 - .saturating_add(Weight::from_parts(4_041, 0).saturating_mul(i.into())) + // Measured: `1334` + // Estimated: `4782` + // Minimum execution time: 171_790_000 picoseconds. + Weight::from_parts(152_418_252, 4782) + // Standard Error: 20 + .saturating_add(Weight::from_parts(4_271, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -239,10 +242,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `1519` - // Estimated: `7459` - // Minimum execution time: 91_129_000 picoseconds. - Weight::from_parts(94_220_000, 7459) + // Measured: `1561` + // Estimated: `7501` + // Minimum execution time: 150_910_000 picoseconds. + Weight::from_parts(163_308_000, 7501) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -253,12 +256,14 @@ impl WeightInfo for SubstrateWeight { /// Storage: `Revive::PristineCode` (r:0 w:1) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) /// The range of component `c` is `[0, 262144]`. - fn upload_code(_c: u32, ) -> Weight { + fn upload_code(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 54_849_000 picoseconds. - Weight::from_parts(57_508_591, 3574) + // Minimum execution time: 57_970_000 picoseconds. + Weight::from_parts(62_605_851, 3574) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -272,8 +277,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `285` // Estimated: `3750` - // Minimum execution time: 45_017_000 picoseconds. - Weight::from_parts(46_312_000, 3750) + // Minimum execution time: 47_117_000 picoseconds. + Weight::from_parts(48_310_000, 3750) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -285,8 +290,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `529` // Estimated: `6469` - // Minimum execution time: 26_992_000 picoseconds. - Weight::from_parts(28_781_000, 6469) + // Minimum execution time: 30_754_000 picoseconds. + Weight::from_parts(32_046_000, 6469) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -298,8 +303,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 44_031_000 picoseconds. - Weight::from_parts(45_133_000, 3574) + // Minimum execution time: 46_338_000 picoseconds. + Weight::from_parts(47_697_000, 3574) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -311,8 +316,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `56` // Estimated: `3521` - // Minimum execution time: 35_681_000 picoseconds. - Weight::from_parts(36_331_000, 3521) + // Minimum execution time: 36_480_000 picoseconds. + Weight::from_parts(37_310_000, 3521) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -324,8 +329,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 11_550_000 picoseconds. - Weight::from_parts(12_114_000, 3610) + // Minimum execution time: 12_950_000 picoseconds. + Weight::from_parts(13_431_000, 3610) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -333,17 +338,24 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_063_000 picoseconds. - Weight::from_parts(7_671_454, 0) - // Standard Error: 105 - .saturating_add(Weight::from_parts(175_349, 0).saturating_mul(r.into())) + // Minimum execution time: 7_540_000 picoseconds. + Weight::from_parts(8_481_295, 0) + // Standard Error: 900 + .saturating_add(Weight::from_parts(183_511, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 266_000 picoseconds. - Weight::from_parts(313_000, 0) + // Minimum execution time: 328_000 picoseconds. + Weight::from_parts(361_000, 0) + } + fn seal_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 272_000 picoseconds. + Weight::from_parts(310_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) @@ -351,8 +363,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `306` // Estimated: `3771` - // Minimum execution time: 7_397_000 picoseconds. - Weight::from_parts(7_967_000, 3771) + // Minimum execution time: 7_755_000 picoseconds. + Weight::from_parts(8_364_000, 3771) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) @@ -361,51 +373,51 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `403` // Estimated: `3868` - // Minimum execution time: 8_395_000 picoseconds. - Weight::from_parts(8_863_000, 3868) + // Minimum execution time: 8_848_000 picoseconds. + Weight::from_parts(9_317_000, 3868) .saturating_add(T::DbWeight::get().reads(1_u64)) } fn seal_own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 265_000 picoseconds. - Weight::from_parts(292_000, 0) + // Minimum execution time: 285_000 picoseconds. + Weight::from_parts(333_000, 0) } fn seal_caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 298_000 picoseconds. - Weight::from_parts(334_000, 0) + // Minimum execution time: 314_000 picoseconds. + Weight::from_parts(418_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 262_000 picoseconds. - Weight::from_parts(274_000, 0) + // Minimum execution time: 297_000 picoseconds. + Weight::from_parts(353_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 277_000 picoseconds. - Weight::from_parts(297_000, 0) + // Minimum execution time: 285_000 picoseconds. + Weight::from_parts(316_000, 0) } fn seal_weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 620_000 picoseconds. - Weight::from_parts(706_000, 0) + // Minimum execution time: 676_000 picoseconds. + Weight::from_parts(895_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `140` + // Measured: `178` // Estimated: `0` - // Minimum execution time: 5_475_000 picoseconds. - Weight::from_parts(5_706_000, 0) + // Minimum execution time: 6_842_000 picoseconds. + Weight::from_parts(7_790_000, 0) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) @@ -415,8 +427,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `264` // Estimated: `3729` - // Minimum execution time: 9_141_000 picoseconds. - Weight::from_parts(9_674_000, 3729) + // Minimum execution time: 10_982_000 picoseconds. + Weight::from_parts(13_664_000, 3729) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) @@ -426,10 +438,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `238 + n * (1 ±0)` // Estimated: `3703 + n * (1 ±0)` - // Minimum execution time: 6_443_000 picoseconds. - Weight::from_parts(7_252_595, 3703) - // Standard Error: 12 - .saturating_add(Weight::from_parts(915, 0).saturating_mul(n.into())) + // Minimum execution time: 6_690_000 picoseconds. + Weight::from_parts(7_522_685, 3703) + // Standard Error: 21 + .saturating_add(Weight::from_parts(1_084, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -440,39 +452,39 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_745_000 picoseconds. - Weight::from_parts(3_121_250, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(627, 0).saturating_mul(n.into())) + // Minimum execution time: 3_090_000 picoseconds. + Weight::from_parts(3_585_913, 0) + // Standard Error: 11 + .saturating_add(Weight::from_parts(594, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 255_000 picoseconds. - Weight::from_parts(274_000, 0) + // Minimum execution time: 261_000 picoseconds. + Weight::from_parts(305_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 235_000 picoseconds. - Weight::from_parts(261_000, 0) + // Minimum execution time: 279_000 picoseconds. + Weight::from_parts(299_000, 0) } fn seal_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 249_000 picoseconds. - Weight::from_parts(263_000, 0) + // Minimum execution time: 280_000 picoseconds. + Weight::from_parts(317_000, 0) } fn seal_now() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 287_000 picoseconds. - Weight::from_parts(300_000, 0) + // Minimum execution time: 285_000 picoseconds. + Weight::from_parts(313_000, 0) } /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) @@ -480,8 +492,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `67` // Estimated: `1552` - // Minimum execution time: 6_147_000 picoseconds. - Weight::from_parts(6_562_000, 1552) + // Minimum execution time: 6_116_000 picoseconds. + Weight::from_parts(6_584_000, 1552) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// The range of component `n` is `[0, 262140]`. @@ -489,20 +501,20 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 453_000 picoseconds. - Weight::from_parts(548_774, 0) + // Minimum execution time: 477_000 picoseconds. + Weight::from_parts(887_560, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(147, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(154, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262140]`. fn seal_return(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 264_000 picoseconds. - Weight::from_parts(490_374, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(236, 0).saturating_mul(n.into())) + // Minimum execution time: 315_000 picoseconds. + Weight::from_parts(870_254, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(248, 0).saturating_mul(n.into())) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) @@ -518,11 +530,11 @@ impl WeightInfo for SubstrateWeight { fn seal_terminate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `323 + n * (88 ±0)` - // Estimated: `3788 + n * (2563 ±0)` - // Minimum execution time: 22_833_000 picoseconds. - Weight::from_parts(24_805_620, 3788) - // Standard Error: 9_498 - .saturating_add(Weight::from_parts(4_486_714, 0).saturating_mul(n.into())) + // Estimated: `3789 + n * (2563 ±0)` + // Minimum execution time: 23_098_000 picoseconds. + Weight::from_parts(26_001_186, 3789) + // Standard Error: 23_098 + .saturating_add(Weight::from_parts(4_935_203, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes(4_u64)) @@ -535,22 +547,22 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_969_000 picoseconds. - Weight::from_parts(4_994_916, 0) - // Standard Error: 3_727 - .saturating_add(Weight::from_parts(188_374, 0).saturating_mul(t.into())) - // Standard Error: 33 - .saturating_add(Weight::from_parts(925, 0).saturating_mul(n.into())) + // Minimum execution time: 5_271_000 picoseconds. + Weight::from_parts(5_803_969, 0) + // Standard Error: 10_511 + .saturating_add(Weight::from_parts(163_106, 0).saturating_mul(t.into())) + // Standard Error: 93 + .saturating_add(Weight::from_parts(361, 0).saturating_mul(n.into())) } /// The range of component `i` is `[0, 262144]`. fn seal_debug_message(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 328_000 picoseconds. - Weight::from_parts(928_905, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(753, 0).saturating_mul(i.into())) + // Minimum execution time: 375_000 picoseconds. + Weight::from_parts(1_601_309, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(787, 0).saturating_mul(i.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -558,8 +570,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 8_612_000 picoseconds. - Weight::from_parts(9_326_000, 744) + // Minimum execution time: 9_557_000 picoseconds. + Weight::from_parts(10_131_000, 744) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -568,8 +580,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 44_542_000 picoseconds. - Weight::from_parts(45_397_000, 10754) + // Minimum execution time: 45_601_000 picoseconds. + Weight::from_parts(46_296_000, 10754) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -578,8 +590,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 10_343_000 picoseconds. - Weight::from_parts(10_883_000, 744) + // Minimum execution time: 10_718_000 picoseconds. + Weight::from_parts(12_282_000, 744) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -589,8 +601,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 46_835_000 picoseconds. - Weight::from_parts(47_446_000, 10754) + // Minimum execution time: 47_580_000 picoseconds. + Weight::from_parts(50_301_000, 10754) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -602,12 +614,12 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + o * (1 ±0)` // Estimated: `247 + o * (1 ±0)` - // Minimum execution time: 10_604_000 picoseconds. - Weight::from_parts(11_282_849, 247) - // Standard Error: 48 - .saturating_add(Weight::from_parts(496, 0).saturating_mul(n.into())) - // Standard Error: 48 - .saturating_add(Weight::from_parts(764, 0).saturating_mul(o.into())) + // Minimum execution time: 11_483_000 picoseconds. + Weight::from_parts(13_084_262, 247) + // Standard Error: 218 + .saturating_add(Weight::from_parts(83, 0).saturating_mul(n.into())) + // Standard Error: 218 + .saturating_add(Weight::from_parts(683, 0).saturating_mul(o.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(o.into())) @@ -619,10 +631,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 10_081_000 picoseconds. - Weight::from_parts(11_186_557, 247) - // Standard Error: 68 - .saturating_add(Weight::from_parts(782, 0).saturating_mul(n.into())) + // Minimum execution time: 10_972_000 picoseconds. + Weight::from_parts(12_960_831, 247) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -634,10 +644,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_758_000 picoseconds. - Weight::from_parts(9_939_492, 247) - // Standard Error: 69 - .saturating_add(Weight::from_parts(1_703, 0).saturating_mul(n.into())) + // Minimum execution time: 9_989_000 picoseconds. + Weight::from_parts(12_783_294, 247) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -648,10 +656,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_525_000 picoseconds. - Weight::from_parts(9_522_265, 247) - // Standard Error: 66 - .saturating_add(Weight::from_parts(426, 0).saturating_mul(n.into())) + // Minimum execution time: 9_732_000 picoseconds. + Weight::from_parts(11_156_576, 247) + // Standard Error: 255 + .saturating_add(Weight::from_parts(1_956, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -662,10 +670,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 10_603_000 picoseconds. - Weight::from_parts(11_817_752, 247) - // Standard Error: 82 - .saturating_add(Weight::from_parts(1_279, 0).saturating_mul(n.into())) + // Minimum execution time: 10_883_000 picoseconds. + Weight::from_parts(13_454_925, 247) + // Standard Error: 276 + .saturating_add(Weight::from_parts(1_509, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -674,36 +682,36 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_553_000 picoseconds. - Weight::from_parts(1_615_000, 0) + // Minimum execution time: 1_586_000 picoseconds. + Weight::from_parts(1_869_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_932_000 picoseconds. - Weight::from_parts(2_064_000, 0) + // Minimum execution time: 1_997_000 picoseconds. + Weight::from_parts(2_093_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_510_000 picoseconds. - Weight::from_parts(1_545_000, 0) + // Minimum execution time: 1_531_000 picoseconds. + Weight::from_parts(1_734_000, 0) } fn get_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_663_000 picoseconds. - Weight::from_parts(1_801_000, 0) + // Minimum execution time: 1_635_000 picoseconds. + Weight::from_parts(1_880_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_026_000 picoseconds. - Weight::from_parts(1_137_000, 0) + // Minimum execution time: 1_192_000 picoseconds. + Weight::from_parts(1_339_000, 0) } /// The range of component `n` is `[0, 512]`. /// The range of component `o` is `[0, 512]`. @@ -711,59 +719,59 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_446_000 picoseconds. - Weight::from_parts(2_644_525, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(113, 0).saturating_mul(n.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(179, 0).saturating_mul(o.into())) + // Minimum execution time: 2_294_000 picoseconds. + Weight::from_parts(2_848_884, 0) + // Standard Error: 53 + .saturating_add(Weight::from_parts(176, 0).saturating_mul(n.into())) + // Standard Error: 53 + .saturating_add(Weight::from_parts(148, 0).saturating_mul(o.into())) } /// The range of component `n` is `[0, 512]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_085_000 picoseconds. - Weight::from_parts(2_379_853, 0) - // Standard Error: 19 - .saturating_add(Weight::from_parts(366, 0).saturating_mul(n.into())) + // Minimum execution time: 2_073_000 picoseconds. + Weight::from_parts(2_670_081, 0) + // Standard Error: 64 + .saturating_add(Weight::from_parts(270, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_876_000 picoseconds. - Weight::from_parts(2_073_689, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(376, 0).saturating_mul(n.into())) + // Minimum execution time: 1_879_000 picoseconds. + Weight::from_parts(2_294_904, 0) + // Standard Error: 55 + .saturating_add(Weight::from_parts(481, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_688_000 picoseconds. - Weight::from_parts(1_914_470, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(125, 0).saturating_mul(n.into())) + // Minimum execution time: 1_711_000 picoseconds. + Weight::from_parts(2_151_924, 0) + // Standard Error: 56 + .saturating_add(Weight::from_parts(98, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_take_transient_storage(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_479_000 picoseconds. - Weight::from_parts(2_758_250, 0) + // Minimum execution time: 2_615_000 picoseconds. + Weight::from_parts(3_050_600, 0) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) fn seal_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `352` - // Estimated: `3817` - // Minimum execution time: 15_745_000 picoseconds. - Weight::from_parts(16_300_000, 3817) + // Measured: `390` + // Estimated: `3855` + // Minimum execution time: 18_629_000 picoseconds. + Weight::from_parts(19_520_000, 3855) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) @@ -778,17 +786,15 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 262144]`. fn seal_call(t: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1309 + t * (140 ±0)` - // Estimated: `4774 + t * (140 ±0)` - // Minimum execution time: 39_639_000 picoseconds. - Weight::from_parts(40_909_376, 4774) - // Standard Error: 54_479 - .saturating_add(Weight::from_parts(1_526_185, 0).saturating_mul(t.into())) - // Standard Error: 0 - .saturating_add(Weight::from_parts(4, 0).saturating_mul(i.into())) + // Measured: `1319 + t * (178 ±0)` + // Estimated: `4784 + t * (178 ±0)` + // Minimum execution time: 43_655_000 picoseconds. + Weight::from_parts(50_252_813, 4784) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 140).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 178).saturating_mul(t.into())) } /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -796,10 +802,10 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) fn seal_delegate_call() -> Weight { // Proof Size summary in bytes: - // Measured: `1081` - // Estimated: `4546` - // Minimum execution time: 29_651_000 picoseconds. - Weight::from_parts(31_228_000, 4546) + // Measured: `1089` + // Estimated: `4554` + // Minimum execution time: 31_153_000 picoseconds. + Weight::from_parts(33_625_000, 4554) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) @@ -813,12 +819,12 @@ impl WeightInfo for SubstrateWeight { /// The range of component `i` is `[0, 262144]`. fn seal_instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1327` - // Estimated: `4792` - // Minimum execution time: 126_995_000 picoseconds. - Weight::from_parts(114_028_446, 4792) - // Standard Error: 11 - .saturating_add(Weight::from_parts(3_781, 0).saturating_mul(i.into())) + // Measured: `1360` + // Estimated: `4814` + // Minimum execution time: 130_134_000 picoseconds. + Weight::from_parts(120_699_282, 4814) + // Standard Error: 20 + .saturating_add(Weight::from_parts(4_054, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -827,64 +833,64 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 653_000 picoseconds. - Weight::from_parts(973_524, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_048, 0).saturating_mul(n.into())) + // Minimum execution time: 665_000 picoseconds. + Weight::from_parts(1_964_310, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_091, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_keccak_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_118_000 picoseconds. - Weight::from_parts(795_498, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(3_260, 0).saturating_mul(n.into())) + // Minimum execution time: 1_245_000 picoseconds. + Weight::from_parts(2_362_235, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(3_360, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 647_000 picoseconds. - Weight::from_parts(667_024, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_183, 0).saturating_mul(n.into())) + // Minimum execution time: 668_000 picoseconds. + Weight::from_parts(1_216_363, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_231, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_128(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 605_000 picoseconds. - Weight::from_parts(675_568, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_181, 0).saturating_mul(n.into())) + // Minimum execution time: 702_000 picoseconds. + Weight::from_parts(1_283_345, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_230, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 261889]`. fn seal_sr25519_verify(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 42_743_000 picoseconds. - Weight::from_parts(26_131_984, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(4_867, 0).saturating_mul(n.into())) + // Minimum execution time: 45_690_000 picoseconds. + Weight::from_parts(28_207_599, 0) + // Standard Error: 18 + .saturating_add(Weight::from_parts(5_142, 0).saturating_mul(n.into())) } fn seal_ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 50_838_000 picoseconds. - Weight::from_parts(52_248_000, 0) + // Minimum execution time: 51_869_000 picoseconds. + Weight::from_parts(56_118_000, 0) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_605_000 picoseconds. - Weight::from_parts(12_796_000, 0) + // Minimum execution time: 12_927_000 picoseconds. + Weight::from_parts(13_256_000, 0) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -892,8 +898,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `300` // Estimated: `3765` - // Minimum execution time: 16_377_000 picoseconds. - Weight::from_parts(16_932_000, 3765) + // Minimum execution time: 16_969_000 picoseconds. + Weight::from_parts(17_796_000, 3765) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -903,8 +909,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `338` // Estimated: `3803` - // Minimum execution time: 11_499_000 picoseconds. - Weight::from_parts(12_104_000, 3803) + // Minimum execution time: 11_827_000 picoseconds. + Weight::from_parts(13_675_000, 3803) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -914,8 +920,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `338` // Estimated: `3561` - // Minimum execution time: 10_308_000 picoseconds. - Weight::from_parts(11_000_000, 3561) + // Minimum execution time: 10_529_000 picoseconds. + Weight::from_parts(12_080_000, 3561) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -924,10 +930,10 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_162_000 picoseconds. - Weight::from_parts(9_180_011, 0) - // Standard Error: 63 - .saturating_add(Weight::from_parts(84_822, 0).saturating_mul(r.into())) + // Minimum execution time: 8_269_000 picoseconds. + Weight::from_parts(11_148_702, 0) + // Standard Error: 366 + .saturating_add(Weight::from_parts(87_469, 0).saturating_mul(r.into())) } } @@ -939,8 +945,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `1594` - // Minimum execution time: 3_053_000 picoseconds. - Weight::from_parts(3_150_000, 1594) + // Minimum execution time: 3_293_000 picoseconds. + Weight::from_parts(3_530_000, 1594) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -950,10 +956,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `425 + k * (69 ±0)` // Estimated: `415 + k * (70 ±0)` - // Minimum execution time: 15_219_000 picoseconds. - Weight::from_parts(12_576_960, 415) - // Standard Error: 1_429 - .saturating_add(Weight::from_parts(1_341_896, 0).saturating_mul(k.into())) + // Minimum execution time: 16_103_000 picoseconds. + Weight::from_parts(16_692_000, 415) + // Standard Error: 2_700 + .saturating_add(Weight::from_parts(1_493_715, 0).saturating_mul(k.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(k.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -973,12 +979,14 @@ impl WeightInfo for () { /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) /// The range of component `c` is `[0, 262144]`. - fn call_with_code_per_byte(_c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `1519` - // Estimated: `7459` - // Minimum execution time: 88_906_000 picoseconds. - Weight::from_parts(93_353_224, 7459) + fn call_with_code_per_byte(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1561` + // Estimated: `7501` + // Minimum execution time: 98_125_000 picoseconds. + Weight::from_parts(105_486_409, 7501) + // Standard Error: 2 + .saturating_add(Weight::from_parts(4, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1001,11 +1009,11 @@ impl WeightInfo for () { fn instantiate_with_code(_c: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `416` - // Estimated: `6360` - // Minimum execution time: 202_688_000 picoseconds. - Weight::from_parts(197_366_807, 6360) - // Standard Error: 13 - .saturating_add(Weight::from_parts(4_261, 0).saturating_mul(i.into())) + // Estimated: `6348` + // Minimum execution time: 204_069_000 picoseconds. + Weight::from_parts(206_289_328, 6348) + // Standard Error: 16 + .saturating_add(Weight::from_parts(4_438, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -1026,12 +1034,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 262144]`. fn instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1313` - // Estimated: `4779` - // Minimum execution time: 169_246_000 picoseconds. - Weight::from_parts(149_480_457, 4779) - // Standard Error: 16 - .saturating_add(Weight::from_parts(4_041, 0).saturating_mul(i.into())) + // Measured: `1334` + // Estimated: `4782` + // Minimum execution time: 171_790_000 picoseconds. + Weight::from_parts(152_418_252, 4782) + // Standard Error: 20 + .saturating_add(Weight::from_parts(4_271, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -1049,10 +1057,10 @@ impl WeightInfo for () { /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `Measured`) fn call() -> Weight { // Proof Size summary in bytes: - // Measured: `1519` - // Estimated: `7459` - // Minimum execution time: 91_129_000 picoseconds. - Weight::from_parts(94_220_000, 7459) + // Measured: `1561` + // Estimated: `7501` + // Minimum execution time: 150_910_000 picoseconds. + Weight::from_parts(163_308_000, 7501) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1063,12 +1071,14 @@ impl WeightInfo for () { /// Storage: `Revive::PristineCode` (r:0 w:1) /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) /// The range of component `c` is `[0, 262144]`. - fn upload_code(_c: u32, ) -> Weight { + fn upload_code(c: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 54_849_000 picoseconds. - Weight::from_parts(57_508_591, 3574) + // Minimum execution time: 57_970_000 picoseconds. + Weight::from_parts(62_605_851, 3574) + // Standard Error: 3 + .saturating_add(Weight::from_parts(6, 0).saturating_mul(c.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1082,8 +1092,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `285` // Estimated: `3750` - // Minimum execution time: 45_017_000 picoseconds. - Weight::from_parts(46_312_000, 3750) + // Minimum execution time: 47_117_000 picoseconds. + Weight::from_parts(48_310_000, 3750) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1095,8 +1105,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `529` // Estimated: `6469` - // Minimum execution time: 26_992_000 picoseconds. - Weight::from_parts(28_781_000, 6469) + // Minimum execution time: 30_754_000 picoseconds. + Weight::from_parts(32_046_000, 6469) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1108,8 +1118,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `109` // Estimated: `3574` - // Minimum execution time: 44_031_000 picoseconds. - Weight::from_parts(45_133_000, 3574) + // Minimum execution time: 46_338_000 picoseconds. + Weight::from_parts(47_697_000, 3574) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1121,8 +1131,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `56` // Estimated: `3521` - // Minimum execution time: 35_681_000 picoseconds. - Weight::from_parts(36_331_000, 3521) + // Minimum execution time: 36_480_000 picoseconds. + Weight::from_parts(37_310_000, 3521) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -1134,8 +1144,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 11_550_000 picoseconds. - Weight::from_parts(12_114_000, 3610) + // Minimum execution time: 12_950_000 picoseconds. + Weight::from_parts(13_431_000, 3610) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// The range of component `r` is `[0, 1600]`. @@ -1143,17 +1153,24 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_063_000 picoseconds. - Weight::from_parts(7_671_454, 0) - // Standard Error: 105 - .saturating_add(Weight::from_parts(175_349, 0).saturating_mul(r.into())) + // Minimum execution time: 7_540_000 picoseconds. + Weight::from_parts(8_481_295, 0) + // Standard Error: 900 + .saturating_add(Weight::from_parts(183_511, 0).saturating_mul(r.into())) } fn seal_caller() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 266_000 picoseconds. - Weight::from_parts(313_000, 0) + // Minimum execution time: 328_000 picoseconds. + Weight::from_parts(361_000, 0) + } + fn seal_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 272_000 picoseconds. + Weight::from_parts(310_000, 0) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) /// Proof: `Revive::ContractInfoOf` (`max_values`: None, `max_size`: Some(1779), added: 4254, mode: `Measured`) @@ -1161,8 +1178,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `306` // Estimated: `3771` - // Minimum execution time: 7_397_000 picoseconds. - Weight::from_parts(7_967_000, 3771) + // Minimum execution time: 7_755_000 picoseconds. + Weight::from_parts(8_364_000, 3771) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Revive::ContractInfoOf` (r:1 w:0) @@ -1171,51 +1188,51 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `403` // Estimated: `3868` - // Minimum execution time: 8_395_000 picoseconds. - Weight::from_parts(8_863_000, 3868) + // Minimum execution time: 8_848_000 picoseconds. + Weight::from_parts(9_317_000, 3868) .saturating_add(RocksDbWeight::get().reads(1_u64)) } fn seal_own_code_hash() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 265_000 picoseconds. - Weight::from_parts(292_000, 0) + // Minimum execution time: 285_000 picoseconds. + Weight::from_parts(333_000, 0) } fn seal_caller_is_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 298_000 picoseconds. - Weight::from_parts(334_000, 0) + // Minimum execution time: 314_000 picoseconds. + Weight::from_parts(418_000, 0) } fn seal_caller_is_root() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 262_000 picoseconds. - Weight::from_parts(274_000, 0) + // Minimum execution time: 297_000 picoseconds. + Weight::from_parts(353_000, 0) } fn seal_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 277_000 picoseconds. - Weight::from_parts(297_000, 0) + // Minimum execution time: 285_000 picoseconds. + Weight::from_parts(316_000, 0) } fn seal_weight_left() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 620_000 picoseconds. - Weight::from_parts(706_000, 0) + // Minimum execution time: 676_000 picoseconds. + Weight::from_parts(895_000, 0) } fn seal_balance() -> Weight { // Proof Size summary in bytes: - // Measured: `140` + // Measured: `178` // Estimated: `0` - // Minimum execution time: 5_475_000 picoseconds. - Weight::from_parts(5_706_000, 0) + // Minimum execution time: 6_842_000 picoseconds. + Weight::from_parts(7_790_000, 0) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) @@ -1225,8 +1242,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `264` // Estimated: `3729` - // Minimum execution time: 9_141_000 picoseconds. - Weight::from_parts(9_674_000, 3729) + // Minimum execution time: 10_982_000 picoseconds. + Weight::from_parts(13_664_000, 3729) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `Revive::ImmutableDataOf` (r:1 w:0) @@ -1236,10 +1253,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `238 + n * (1 ±0)` // Estimated: `3703 + n * (1 ±0)` - // Minimum execution time: 6_443_000 picoseconds. - Weight::from_parts(7_252_595, 3703) - // Standard Error: 12 - .saturating_add(Weight::from_parts(915, 0).saturating_mul(n.into())) + // Minimum execution time: 6_690_000 picoseconds. + Weight::from_parts(7_522_685, 3703) + // Standard Error: 21 + .saturating_add(Weight::from_parts(1_084, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1250,39 +1267,39 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_745_000 picoseconds. - Weight::from_parts(3_121_250, 0) - // Standard Error: 4 - .saturating_add(Weight::from_parts(627, 0).saturating_mul(n.into())) + // Minimum execution time: 3_090_000 picoseconds. + Weight::from_parts(3_585_913, 0) + // Standard Error: 11 + .saturating_add(Weight::from_parts(594, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } fn seal_value_transferred() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 255_000 picoseconds. - Weight::from_parts(274_000, 0) + // Minimum execution time: 261_000 picoseconds. + Weight::from_parts(305_000, 0) } fn seal_minimum_balance() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 235_000 picoseconds. - Weight::from_parts(261_000, 0) + // Minimum execution time: 279_000 picoseconds. + Weight::from_parts(299_000, 0) } fn seal_block_number() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 249_000 picoseconds. - Weight::from_parts(263_000, 0) + // Minimum execution time: 280_000 picoseconds. + Weight::from_parts(317_000, 0) } fn seal_now() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 287_000 picoseconds. - Weight::from_parts(300_000, 0) + // Minimum execution time: 285_000 picoseconds. + Weight::from_parts(313_000, 0) } /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `Measured`) @@ -1290,8 +1307,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `67` // Estimated: `1552` - // Minimum execution time: 6_147_000 picoseconds. - Weight::from_parts(6_562_000, 1552) + // Minimum execution time: 6_116_000 picoseconds. + Weight::from_parts(6_584_000, 1552) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// The range of component `n` is `[0, 262140]`. @@ -1299,20 +1316,20 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 453_000 picoseconds. - Weight::from_parts(548_774, 0) + // Minimum execution time: 477_000 picoseconds. + Weight::from_parts(887_560, 0) // Standard Error: 0 - .saturating_add(Weight::from_parts(147, 0).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(154, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262140]`. fn seal_return(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 264_000 picoseconds. - Weight::from_parts(490_374, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(236, 0).saturating_mul(n.into())) + // Minimum execution time: 315_000 picoseconds. + Weight::from_parts(870_254, 0) + // Standard Error: 1 + .saturating_add(Weight::from_parts(248, 0).saturating_mul(n.into())) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) @@ -1328,11 +1345,11 @@ impl WeightInfo for () { fn seal_terminate(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `323 + n * (88 ±0)` - // Estimated: `3788 + n * (2563 ±0)` - // Minimum execution time: 22_833_000 picoseconds. - Weight::from_parts(24_805_620, 3788) - // Standard Error: 9_498 - .saturating_add(Weight::from_parts(4_486_714, 0).saturating_mul(n.into())) + // Estimated: `3789 + n * (2563 ±0)` + // Minimum execution time: 23_098_000 picoseconds. + Weight::from_parts(26_001_186, 3789) + // Standard Error: 23_098 + .saturating_add(Weight::from_parts(4_935_203, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(RocksDbWeight::get().writes(4_u64)) @@ -1345,22 +1362,22 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_969_000 picoseconds. - Weight::from_parts(4_994_916, 0) - // Standard Error: 3_727 - .saturating_add(Weight::from_parts(188_374, 0).saturating_mul(t.into())) - // Standard Error: 33 - .saturating_add(Weight::from_parts(925, 0).saturating_mul(n.into())) + // Minimum execution time: 5_271_000 picoseconds. + Weight::from_parts(5_803_969, 0) + // Standard Error: 10_511 + .saturating_add(Weight::from_parts(163_106, 0).saturating_mul(t.into())) + // Standard Error: 93 + .saturating_add(Weight::from_parts(361, 0).saturating_mul(n.into())) } /// The range of component `i` is `[0, 262144]`. fn seal_debug_message(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 328_000 picoseconds. - Weight::from_parts(928_905, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(753, 0).saturating_mul(i.into())) + // Minimum execution time: 375_000 picoseconds. + Weight::from_parts(1_601_309, 0) + // Standard Error: 3 + .saturating_add(Weight::from_parts(787, 0).saturating_mul(i.into())) } /// Storage: `Skipped::Metadata` (r:0 w:0) /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -1368,8 +1385,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 8_612_000 picoseconds. - Weight::from_parts(9_326_000, 744) + // Minimum execution time: 9_557_000 picoseconds. + Weight::from_parts(10_131_000, 744) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1378,8 +1395,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 44_542_000 picoseconds. - Weight::from_parts(45_397_000, 10754) + // Minimum execution time: 45_601_000 picoseconds. + Weight::from_parts(46_296_000, 10754) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Skipped::Metadata` (r:0 w:0) @@ -1388,8 +1405,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `744` // Estimated: `744` - // Minimum execution time: 10_343_000 picoseconds. - Weight::from_parts(10_883_000, 744) + // Minimum execution time: 10_718_000 picoseconds. + Weight::from_parts(12_282_000, 744) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1399,8 +1416,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `10754` // Estimated: `10754` - // Minimum execution time: 46_835_000 picoseconds. - Weight::from_parts(47_446_000, 10754) + // Minimum execution time: 47_580_000 picoseconds. + Weight::from_parts(50_301_000, 10754) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1412,12 +1429,12 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + o * (1 ±0)` // Estimated: `247 + o * (1 ±0)` - // Minimum execution time: 10_604_000 picoseconds. - Weight::from_parts(11_282_849, 247) - // Standard Error: 48 - .saturating_add(Weight::from_parts(496, 0).saturating_mul(n.into())) - // Standard Error: 48 - .saturating_add(Weight::from_parts(764, 0).saturating_mul(o.into())) + // Minimum execution time: 11_483_000 picoseconds. + Weight::from_parts(13_084_262, 247) + // Standard Error: 218 + .saturating_add(Weight::from_parts(83, 0).saturating_mul(n.into())) + // Standard Error: 218 + .saturating_add(Weight::from_parts(683, 0).saturating_mul(o.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(o.into())) @@ -1429,10 +1446,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 10_081_000 picoseconds. - Weight::from_parts(11_186_557, 247) - // Standard Error: 68 - .saturating_add(Weight::from_parts(782, 0).saturating_mul(n.into())) + // Minimum execution time: 10_972_000 picoseconds. + Weight::from_parts(12_960_831, 247) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1444,10 +1459,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_758_000 picoseconds. - Weight::from_parts(9_939_492, 247) - // Standard Error: 69 - .saturating_add(Weight::from_parts(1_703, 0).saturating_mul(n.into())) + // Minimum execution time: 9_989_000 picoseconds. + Weight::from_parts(12_783_294, 247) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1458,10 +1471,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 8_525_000 picoseconds. - Weight::from_parts(9_522_265, 247) - // Standard Error: 66 - .saturating_add(Weight::from_parts(426, 0).saturating_mul(n.into())) + // Minimum execution time: 9_732_000 picoseconds. + Weight::from_parts(11_156_576, 247) + // Standard Error: 255 + .saturating_add(Weight::from_parts(1_956, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } @@ -1472,10 +1485,10 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `248 + n * (1 ±0)` // Estimated: `247 + n * (1 ±0)` - // Minimum execution time: 10_603_000 picoseconds. - Weight::from_parts(11_817_752, 247) - // Standard Error: 82 - .saturating_add(Weight::from_parts(1_279, 0).saturating_mul(n.into())) + // Minimum execution time: 10_883_000 picoseconds. + Weight::from_parts(13_454_925, 247) + // Standard Error: 276 + .saturating_add(Weight::from_parts(1_509, 0).saturating_mul(n.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) @@ -1484,36 +1497,36 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_553_000 picoseconds. - Weight::from_parts(1_615_000, 0) + // Minimum execution time: 1_586_000 picoseconds. + Weight::from_parts(1_869_000, 0) } fn set_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_932_000 picoseconds. - Weight::from_parts(2_064_000, 0) + // Minimum execution time: 1_997_000 picoseconds. + Weight::from_parts(2_093_000, 0) } fn get_transient_storage_empty() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_510_000 picoseconds. - Weight::from_parts(1_545_000, 0) + // Minimum execution time: 1_531_000 picoseconds. + Weight::from_parts(1_734_000, 0) } fn get_transient_storage_full() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_663_000 picoseconds. - Weight::from_parts(1_801_000, 0) + // Minimum execution time: 1_635_000 picoseconds. + Weight::from_parts(1_880_000, 0) } fn rollback_transient_storage() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_026_000 picoseconds. - Weight::from_parts(1_137_000, 0) + // Minimum execution time: 1_192_000 picoseconds. + Weight::from_parts(1_339_000, 0) } /// The range of component `n` is `[0, 512]`. /// The range of component `o` is `[0, 512]`. @@ -1521,59 +1534,59 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_446_000 picoseconds. - Weight::from_parts(2_644_525, 0) - // Standard Error: 17 - .saturating_add(Weight::from_parts(113, 0).saturating_mul(n.into())) - // Standard Error: 17 - .saturating_add(Weight::from_parts(179, 0).saturating_mul(o.into())) + // Minimum execution time: 2_294_000 picoseconds. + Weight::from_parts(2_848_884, 0) + // Standard Error: 53 + .saturating_add(Weight::from_parts(176, 0).saturating_mul(n.into())) + // Standard Error: 53 + .saturating_add(Weight::from_parts(148, 0).saturating_mul(o.into())) } /// The range of component `n` is `[0, 512]`. fn seal_clear_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_085_000 picoseconds. - Weight::from_parts(2_379_853, 0) - // Standard Error: 19 - .saturating_add(Weight::from_parts(366, 0).saturating_mul(n.into())) + // Minimum execution time: 2_073_000 picoseconds. + Weight::from_parts(2_670_081, 0) + // Standard Error: 64 + .saturating_add(Weight::from_parts(270, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_get_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_876_000 picoseconds. - Weight::from_parts(2_073_689, 0) - // Standard Error: 16 - .saturating_add(Weight::from_parts(376, 0).saturating_mul(n.into())) + // Minimum execution time: 1_879_000 picoseconds. + Weight::from_parts(2_294_904, 0) + // Standard Error: 55 + .saturating_add(Weight::from_parts(481, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_contains_transient_storage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_688_000 picoseconds. - Weight::from_parts(1_914_470, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(125, 0).saturating_mul(n.into())) + // Minimum execution time: 1_711_000 picoseconds. + Weight::from_parts(2_151_924, 0) + // Standard Error: 56 + .saturating_add(Weight::from_parts(98, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 512]`. fn seal_take_transient_storage(_n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_479_000 picoseconds. - Weight::from_parts(2_758_250, 0) + // Minimum execution time: 2_615_000 picoseconds. + Weight::from_parts(3_050_600, 0) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) /// Proof: `Revive::AddressSuffix` (`max_values`: None, `max_size`: Some(32), added: 2507, mode: `Measured`) fn seal_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `352` - // Estimated: `3817` - // Minimum execution time: 15_745_000 picoseconds. - Weight::from_parts(16_300_000, 3817) + // Measured: `390` + // Estimated: `3855` + // Minimum execution time: 18_629_000 picoseconds. + Weight::from_parts(19_520_000, 3855) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: `Revive::AddressSuffix` (r:1 w:0) @@ -1588,17 +1601,15 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 262144]`. fn seal_call(t: u32, i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1309 + t * (140 ±0)` - // Estimated: `4774 + t * (140 ±0)` - // Minimum execution time: 39_639_000 picoseconds. - Weight::from_parts(40_909_376, 4774) - // Standard Error: 54_479 - .saturating_add(Weight::from_parts(1_526_185, 0).saturating_mul(t.into())) - // Standard Error: 0 - .saturating_add(Weight::from_parts(4, 0).saturating_mul(i.into())) + // Measured: `1319 + t * (178 ±0)` + // Estimated: `4784 + t * (178 ±0)` + // Minimum execution time: 43_655_000 picoseconds. + Weight::from_parts(50_252_813, 4784) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) - .saturating_add(Weight::from_parts(0, 140).saturating_mul(t.into())) + .saturating_add(Weight::from_parts(0, 178).saturating_mul(t.into())) } /// Storage: `Revive::CodeInfoOf` (r:1 w:0) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -1606,10 +1617,10 @@ impl WeightInfo for () { /// Proof: `Revive::PristineCode` (`max_values`: None, `max_size`: Some(262180), added: 264655, mode: `Measured`) fn seal_delegate_call() -> Weight { // Proof Size summary in bytes: - // Measured: `1081` - // Estimated: `4546` - // Minimum execution time: 29_651_000 picoseconds. - Weight::from_parts(31_228_000, 4546) + // Measured: `1089` + // Estimated: `4554` + // Minimum execution time: 31_153_000 picoseconds. + Weight::from_parts(33_625_000, 4554) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) @@ -1623,12 +1634,12 @@ impl WeightInfo for () { /// The range of component `i` is `[0, 262144]`. fn seal_instantiate(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1327` - // Estimated: `4792` - // Minimum execution time: 126_995_000 picoseconds. - Weight::from_parts(114_028_446, 4792) - // Standard Error: 11 - .saturating_add(Weight::from_parts(3_781, 0).saturating_mul(i.into())) + // Measured: `1360` + // Estimated: `4814` + // Minimum execution time: 130_134_000 picoseconds. + Weight::from_parts(120_699_282, 4814) + // Standard Error: 20 + .saturating_add(Weight::from_parts(4_054, 0).saturating_mul(i.into())) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -1637,64 +1648,64 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 653_000 picoseconds. - Weight::from_parts(973_524, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_048, 0).saturating_mul(n.into())) + // Minimum execution time: 665_000 picoseconds. + Weight::from_parts(1_964_310, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_091, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_keccak_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_118_000 picoseconds. - Weight::from_parts(795_498, 0) - // Standard Error: 1 - .saturating_add(Weight::from_parts(3_260, 0).saturating_mul(n.into())) + // Minimum execution time: 1_245_000 picoseconds. + Weight::from_parts(2_362_235, 0) + // Standard Error: 10 + .saturating_add(Weight::from_parts(3_360, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_256(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 647_000 picoseconds. - Weight::from_parts(667_024, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_183, 0).saturating_mul(n.into())) + // Minimum execution time: 668_000 picoseconds. + Weight::from_parts(1_216_363, 0) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_231, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 262144]`. fn seal_hash_blake2_128(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 605_000 picoseconds. - Weight::from_parts(675_568, 0) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_181, 0).saturating_mul(n.into())) + // Minimum execution time: 702_000 picoseconds. + Weight::from_parts(1_283_345, 0) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_230, 0).saturating_mul(n.into())) } /// The range of component `n` is `[0, 261889]`. fn seal_sr25519_verify(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 42_743_000 picoseconds. - Weight::from_parts(26_131_984, 0) - // Standard Error: 15 - .saturating_add(Weight::from_parts(4_867, 0).saturating_mul(n.into())) + // Minimum execution time: 45_690_000 picoseconds. + Weight::from_parts(28_207_599, 0) + // Standard Error: 18 + .saturating_add(Weight::from_parts(5_142, 0).saturating_mul(n.into())) } fn seal_ecdsa_recover() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 50_838_000 picoseconds. - Weight::from_parts(52_248_000, 0) + // Minimum execution time: 51_869_000 picoseconds. + Weight::from_parts(56_118_000, 0) } fn seal_ecdsa_to_eth_address() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_605_000 picoseconds. - Weight::from_parts(12_796_000, 0) + // Minimum execution time: 12_927_000 picoseconds. + Weight::from_parts(13_256_000, 0) } /// Storage: `Revive::CodeInfoOf` (r:1 w:1) /// Proof: `Revive::CodeInfoOf` (`max_values`: None, `max_size`: Some(96), added: 2571, mode: `Measured`) @@ -1702,8 +1713,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `300` // Estimated: `3765` - // Minimum execution time: 16_377_000 picoseconds. - Weight::from_parts(16_932_000, 3765) + // Minimum execution time: 16_969_000 picoseconds. + Weight::from_parts(17_796_000, 3765) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1713,8 +1724,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `338` // Estimated: `3803` - // Minimum execution time: 11_499_000 picoseconds. - Weight::from_parts(12_104_000, 3803) + // Minimum execution time: 11_827_000 picoseconds. + Weight::from_parts(13_675_000, 3803) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1724,8 +1735,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `338` // Estimated: `3561` - // Minimum execution time: 10_308_000 picoseconds. - Weight::from_parts(11_000_000, 3561) + // Minimum execution time: 10_529_000 picoseconds. + Weight::from_parts(12_080_000, 3561) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -1734,9 +1745,9 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_162_000 picoseconds. - Weight::from_parts(9_180_011, 0) - // Standard Error: 63 - .saturating_add(Weight::from_parts(84_822, 0).saturating_mul(r.into())) + // Minimum execution time: 8_269_000 picoseconds. + Weight::from_parts(11_148_702, 0) + // Standard Error: 366 + .saturating_add(Weight::from_parts(87_469, 0).saturating_mul(r.into())) } } diff --git a/substrate/frame/revive/uapi/src/host.rs b/substrate/frame/revive/uapi/src/host.rs index 2663d7c2cf0c..aa92ed73a050 100644 --- a/substrate/frame/revive/uapi/src/host.rs +++ b/substrate/frame/revive/uapi/src/host.rs @@ -206,6 +206,17 @@ pub trait HostFn: private::Sealed { /// - `output`: A reference to the output data buffer to write the caller address. fn caller(output: &mut [u8; 20]); + /// Stores the origin address (initator of the call stack) into the supplied buffer. + /// + /// If there is no address associated with the origin (e.g. because the origin is root) then + /// it traps with `BadOrigin`. This can only happen through on-chain governance actions or + /// customized runtimes. + /// + /// # Parameters + /// + /// - `output`: A reference to the output data buffer to write the origin's address. + fn origin(output: &mut [u8; 20]); + /// Checks whether the caller of the current contract is the origin of the whole call stack. /// /// Prefer this over [`is_contract()`][`Self::is_contract`] when checking whether your contract diff --git a/substrate/frame/revive/uapi/src/host/riscv32.rs b/substrate/frame/revive/uapi/src/host/riscv32.rs index c2508198c935..07bbb24adedd 100644 --- a/substrate/frame/revive/uapi/src/host/riscv32.rs +++ b/substrate/frame/revive/uapi/src/host/riscv32.rs @@ -73,6 +73,7 @@ mod sys { pub fn input(out_ptr: *mut u8, out_len_ptr: *mut u32); pub fn seal_return(flags: u32, data_ptr: *const u8, data_len: u32); pub fn caller(out_ptr: *mut u8); + pub fn origin(out_ptr: *mut u8); pub fn is_contract(account_ptr: *const u8) -> ReturnCode; pub fn code_hash(address_ptr: *const u8, out_ptr: *mut u8); pub fn own_code_hash(out_ptr: *mut u8); @@ -453,7 +454,7 @@ impl HostFn for HostFnImpl { impl_wrapper_for! { [u8; 32] => block_number, balance, value_transferred, now, minimum_balance, chain_id; - [u8; 20] => address, caller; + [u8; 20] => address, caller, origin; } fn weight_left(output: &mut &mut [u8]) { From 9584dbda9ed5fc91b1837f35f401659239fdaff1 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:51:36 +0000 Subject: [PATCH 2/5] Use frame umbrella crate in `pallet-proxy` and `pallet-multisig` (#5995) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A step towards https://github.com/paritytech/polkadot-sdk/issues/4782 In order to nail down the right preludes in `polkadot-sdk-frame`, we need to migrate a number of pallets to be written with it. Moreover, migrating our pallets to this simpler patter will encourage the ecosystem to also follow along. If this PR is approved and has no unwanted negative consequences, I will make a tracking issue to migrate all pallets to this umbrella crate. TODO: - [x] fix frame benchmarking template. Can we detect the umbrella crate in there and have an `if else`? cc @ggwpez - [x] Migrate benchmarking to v2 @re-gius a good candidate for you, you can open a PR against my branch. - [x] tracking issue with follow-ups --------- Co-authored-by: Guillaume Thiolliere Co-authored-by: Giuseppe Re Co-authored-by: Dónal Murray Co-authored-by: Shawn Tabrizi Co-authored-by: Oliver Tale-Yazdi --- .github/scripts/cmd/cmd.py | 25 +- Cargo.lock | 13 +- prdoc/pr_5995.prdoc | 21 ++ .../frame-umbrella-weight-template.hbs | 120 +++++++++ .../frame/migrations/src/benchmarking.rs | 2 +- substrate/frame/multisig/Cargo.toml | 22 +- substrate/frame/multisig/src/benchmarking.rs | 228 +++++++++++------ substrate/frame/multisig/src/lib.rs | 33 +-- substrate/frame/multisig/src/migrations.rs | 21 +- substrate/frame/multisig/src/tests.rs | 15 +- substrate/frame/multisig/src/weights.rs | 5 +- substrate/frame/proxy/Cargo.toml | 25 +- substrate/frame/proxy/src/benchmarking.rs | 238 ++++++++++++------ substrate/frame/proxy/src/lib.rs | 34 +-- substrate/frame/proxy/src/tests.rs | 26 +- substrate/frame/proxy/src/weights.rs | 3 +- substrate/frame/src/lib.rs | 209 +++++++++++++-- substrate/scripts/run_all_benchmarks.sh | 14 +- templates/minimal/pallets/template/src/lib.rs | 4 + templates/minimal/runtime/Cargo.toml | 1 - templates/minimal/runtime/src/lib.rs | 13 +- 21 files changed, 735 insertions(+), 337 deletions(-) create mode 100644 prdoc/pr_5995.prdoc create mode 100644 substrate/.maintain/frame-umbrella-weight-template.hbs diff --git a/.github/scripts/cmd/cmd.py b/.github/scripts/cmd/cmd.py index 6a624bf4237b..9da05cac17b9 100755 --- a/.github/scripts/cmd/cmd.py +++ b/.github/scripts/cmd/cmd.py @@ -6,6 +6,7 @@ import argparse import _help import importlib.util +import re _HelpAction = _help._HelpAction @@ -40,20 +41,20 @@ def setup_logging(): setup_logging() """ -BENCH +BENCH """ bench_example = '''**Examples**: - Runs all benchmarks + Runs all benchmarks %(prog)s Runs benchmarks for pallet_balances and pallet_multisig for all runtimes which have these pallets. **--quiet** makes it to output nothing to PR but reactions %(prog)s --pallet pallet_balances pallet_xcm_benchmarks::generic --quiet - + Runs bench for all pallets for westend runtime and fails fast on first failed benchmark %(prog)s --runtime westend --fail-fast - - Does not output anything and cleans up the previous bot's & author command triggering comments in PR + + Does not output anything and cleans up the previous bot's & author command triggering comments in PR %(prog)s --runtime westend rococo --pallet pallet_balances pallet_multisig --quiet --clean ''' @@ -67,14 +68,14 @@ def setup_logging(): parser_bench.add_argument('--fail-fast', help='Fail fast on first failed benchmark', action='store_true') """ -FMT +FMT """ parser_fmt = subparsers.add_parser('fmt', help='Formats code (cargo +nightly-VERSION fmt) and configs (taplo format)') for arg, config in common_args.items(): parser_fmt.add_argument(arg, **config) """ -Update UI +Update UI """ parser_ui = subparsers.add_parser('update-ui', help='Updates UI tests') for arg, config in common_args.items(): @@ -175,7 +176,15 @@ def main(): print(f'-- package_dir: {package_dir}') print(f'-- manifest_path: {manifest_path}') output_path = os.path.join(package_dir, "src", "weights.rs") + # TODO: we can remove once all pallets in dev runtime are migrated to polkadot-sdk-frame + try: + uses_polkadot_sdk_frame = "true" in os.popen(f"cargo metadata --locked --format-version 1 --no-deps | jq -r '.packages[] | select(.name == \"{pallet.replace('_', '-')}\") | .dependencies | any(.name == \"polkadot-sdk-frame\")'").read() + # Empty output from the previous os.popen command + except StopIteration: + uses_polkadot_sdk_frame = False template = config['template'] + if uses_polkadot_sdk_frame and re.match(r"frame-(:?umbrella-)?weight-template\.hbs", os.path.normpath(template).split(os.path.sep)[-1]): + template = "substrate/.maintain/frame-umbrella-weight-template.hbs" else: default_path = f"./{config['path']}/src/weights" xcm_path = f"./{config['path']}/src/weights/xcm" @@ -251,4 +260,4 @@ def main(): print('🚀 Done') if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/Cargo.lock b/Cargo.lock index dfa70250e30f..127e30d666af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12099,15 +12099,11 @@ dependencies = [ name = "pallet-multisig" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", "log", "pallet-balances", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", - "sp-io 30.0.0", - "sp-runtime 31.0.1", ] [[package]] @@ -12418,16 +12414,11 @@ dependencies = [ name = "pallet-proxy" version = "28.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", "pallet-balances", "pallet-utility", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", - "sp-core 28.0.0", - "sp-io 30.0.0", - "sp-runtime 31.0.1", ] [[package]] diff --git a/prdoc/pr_5995.prdoc b/prdoc/pr_5995.prdoc new file mode 100644 index 000000000000..fdd754057bd1 --- /dev/null +++ b/prdoc/pr_5995.prdoc @@ -0,0 +1,21 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Use frame umbrella crate in pallet-proxy and pallet-multisig + +doc: + - audience: Runtime Dev + description: | + Extends the FRAME umbrella crate and uses it in pallet-proxy and pallet-multisig. + Migrates benchmarking from v1 to v2 for pallet-proxy and pallet-multisig. + Allows CI to pick the umbrella crate weights template to run benchmarks. + +crates: + - name: pallet-multisig + bump: minor + - name: pallet-proxy + bump: minor + - name: polkadot-sdk-frame + bump: major + - name: pallet-migrations + bump: patch diff --git a/substrate/.maintain/frame-umbrella-weight-template.hbs b/substrate/.maintain/frame-umbrella-weight-template.hbs new file mode 100644 index 000000000000..0f26fae1d8f1 --- /dev/null +++ b/substrate/.maintain/frame-umbrella-weight-template.hbs @@ -0,0 +1,120 @@ +{{header}} +//! Autogenerated weights for `{{pallet}}` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} +//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}` +//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` +//! WASM-EXECUTION: `{{cmd.wasm_execution}}`, CHAIN: `{{cmd.chain}}`, DB CACHE: `{{cmd.db_cache}}` + +// Executed Command: +{{#each args as |arg|}} +// {{arg}} +{{/each}} + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame::weights_prelude::*; + +/// Weight functions needed for `{{pallet}}`. +pub trait WeightInfo { + {{#each benchmarks as |benchmark|}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{c.name}}: u32, {{/each~}} + ) -> Weight; + {{/each}} +} + +/// Weights for `{{pallet}}` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +{{#if (eq pallet "frame_system")}} +impl WeightInfo for SubstrateWeight { +{{else}} +impl WeightInfo for SubstrateWeight { +{{/if}} + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} + /// {{comment}} + {{/each}} + {{#each benchmark.component_ranges as |range|}} + /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. + {{/each}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) + {{/each}} + {{#if (ne benchmark.base_reads "0")}} + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}}_u64)) + {{/if}} + {{#each benchmark.component_reads as |cr|}} + .saturating_add(T::DbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) + {{/each}} + {{#if (ne benchmark.base_writes "0")}} + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}}_u64)) + {{/if}} + {{#each benchmark.component_writes as |cw|}} + .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) + {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} + } + {{/each}} +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} + /// {{comment}} + {{/each}} + {{#each benchmark.component_ranges as |range|}} + /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. + {{/each}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) + {{/each}} + {{#if (ne benchmark.base_reads "0")}} + .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}}_u64)) + {{/if}} + {{#each benchmark.component_reads as |cr|}} + .saturating_add(RocksDbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) + {{/each}} + {{#if (ne benchmark.base_writes "0")}} + .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}}_u64)) + {{/if}} + {{#each benchmark.component_writes as |cw|}} + .saturating_add(RocksDbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) + {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} + } + {{/each}} +} diff --git a/substrate/frame/migrations/src/benchmarking.rs b/substrate/frame/migrations/src/benchmarking.rs index 8ad1fa50d149..c076d40bb05c 100644 --- a/substrate/frame/migrations/src/benchmarking.rs +++ b/substrate/frame/migrations/src/benchmarking.rs @@ -158,7 +158,7 @@ mod benches { fn on_init_loop() { T::Migrations::set_fail_after(0); // Should not be called anyway. System::::set_block_number(1u32.into()); - Pallet::::on_runtime_upgrade(); + as Hooks>>::on_runtime_upgrade(); #[block] { diff --git a/substrate/frame/multisig/Cargo.toml b/substrate/frame/multisig/Cargo.toml index b24df856bcd7..c96be908faef 100644 --- a/substrate/frame/multisig/Cargo.toml +++ b/substrate/frame/multisig/Cargo.toml @@ -18,11 +18,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { workspace = true } scale-info = { features = ["derive"], workspace = true } -frame-benchmarking = { optional = true, workspace = true } -frame-support = { workspace = true } -frame-system = { workspace = true } -sp-io = { workspace = true } -sp-runtime = { workspace = true } +frame = { workspace = true, features = ["experimental", "runtime"] } # third party log = { workspace = true } @@ -34,25 +30,15 @@ pallet-balances = { workspace = true, default-features = true } default = ["std"] std = [ "codec/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", + "frame/std", "log/std", - "pallet-balances/std", "scale-info/std", - "sp-io/std", - "sp-runtime/std", ] runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", + "frame/runtime-benchmarks", "pallet-balances/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", + "frame/try-runtime", "pallet-balances/try-runtime", - "sp-runtime/try-runtime", ] diff --git a/substrate/frame/multisig/src/benchmarking.rs b/substrate/frame/multisig/src/benchmarking.rs index ebe19df5dc43..ccaa1ceab66e 100644 --- a/substrate/frame/multisig/src/benchmarking.rs +++ b/substrate/frame/multisig/src/benchmarking.rs @@ -20,9 +20,7 @@ #![cfg(feature = "runtime-benchmarks")] use super::*; -use frame_benchmarking::v1::{account, benchmarks}; -use frame_system::RawOrigin; -use sp_runtime::traits::Bounded; +use frame::benchmarking::prelude::*; use crate::Pallet as Multisig; @@ -47,48 +45,59 @@ fn setup_multi( Ok((signatories, Box::new(call))) } -benchmarks! { - as_multi_threshold_1 { - // Transaction Length - let z in 0 .. 10_000; +#[benchmarks] +mod benchmarks { + use super::*; + + /// `z`: Transaction Length + #[benchmark] + fn as_multi_threshold_1(z: Linear<0, 10_000>) -> Result<(), BenchmarkError> { let max_signatories = T::MaxSignatories::get().into(); let (mut signatories, _) = setup_multi::(max_signatories, z)?; - let call: ::RuntimeCall = frame_system::Call::::remark { - remark: vec![0; z as usize] - }.into(); - let call_hash = call.using_encoded(blake2_256); - let multi_account_id = Multisig::::multi_account_id(&signatories, 1); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![0; z as usize] }.into(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: _(RawOrigin::Signed(caller.clone()), signatories, Box::new(call)) - verify { + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), signatories, Box::new(call)); + // If the benchmark resolves, then the call was dispatched successfully. + Ok(()) } - as_multi_create { - // Signatories, need at least 2 total people - let s in 2 .. T::MaxSignatories::get(); - // Transaction Length - let z in 0 .. 10_000; + /// `z`: Transaction Length + /// `s`: Signatories, need at least 2 people + #[benchmark] + fn as_multi_create( + s: Linear<2, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, Weight::zero()) - verify { + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, Weight::zero()); + assert!(Multisigs::::contains_key(multi_account_id, call_hash)); + + Ok(()) } - as_multi_approve { - // Signatories, need at least 3 people (so we don't complete the multisig) - let s in 3 .. T::MaxSignatories::get(); - // Transaction Length - let z in 0 .. 10_000; + /// `z`: Transaction Length + /// `s`: Signatories, need at least 3 people (so we don't complete the multisig) + #[benchmark] + fn as_multi_approve( + s: Linear<3, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); @@ -97,22 +106,43 @@ benchmarks! { // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?; + Multisig::::as_multi( + RawOrigin::Signed(caller).into(), + s as u16, + signatories, + None, + call.clone(), + Weight::zero(), + )?; let caller2 = signatories2.remove(0); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::zero()) - verify { - let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + as_multi( + RawOrigin::Signed(caller2), + s as u16, + signatories2, + Some(timepoint), + call, + Weight::zero(), + ); + + let multisig = + Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; assert_eq!(multisig.approvals.len(), 2); + + Ok(()) } - as_multi_complete { - // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get(); - // Transaction Length - let z in 0 .. 10_000; + /// `z`: Transaction Length + /// `s`: Signatories, need at least 2 people + #[benchmark] + fn as_multi_complete( + s: Linear<2, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); @@ -121,47 +151,87 @@ benchmarks! { // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?; + Multisig::::as_multi( + RawOrigin::Signed(caller).into(), + s as u16, + signatories, + None, + call.clone(), + Weight::zero(), + )?; // Everyone except the first person approves - for i in 1 .. s - 1 { + for i in 1..s - 1 { let mut signatories_loop = signatories2.clone(); let caller_loop = signatories_loop.remove(i as usize); let o = RawOrigin::Signed(caller_loop).into(); - Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), Weight::zero())?; + Multisig::::as_multi( + o, + s as u16, + signatories_loop, + Some(timepoint), + call.clone(), + Weight::zero(), + )?; } let caller2 = signatories2.remove(0); assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::MAX) - verify { + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + as_multi( + RawOrigin::Signed(caller2), + s as u16, + signatories2, + Some(timepoint), + call, + Weight::MAX, + ); + assert!(!Multisigs::::contains_key(&multi_account_id, call_hash)); + + Ok(()) } - approve_as_multi_create { - // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get(); - // Transaction Length, not a component - let z = 10_000; + /// `z`: Transaction Length, not a component + /// `s`: Signatories, need at least 2 people + #[benchmark] + fn approve_as_multi_create( + s: Linear<2, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; let call_hash = call.using_encoded(blake2_256); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); + add_to_whitelist(caller_key.into()); + // Create the multi - }: approve_as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call_hash, Weight::zero()) - verify { + #[extrinsic_call] + approve_as_multi( + RawOrigin::Signed(caller), + s as u16, + signatories, + None, + call_hash, + Weight::zero(), + ); + assert!(Multisigs::::contains_key(multi_account_id, call_hash)); + + Ok(()) } - approve_as_multi_approve { - // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get(); - // Transaction Length, not a component - let z = 10_000; + /// `z`: Transaction Length, not a component + /// `s`: Signatories, need at least 2 people + #[benchmark] + fn approve_as_multi_approve( + s: Linear<2, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let mut signatories2 = signatories.clone(); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); @@ -176,23 +246,37 @@ benchmarks! { signatories, None, call, - Weight::zero() + Weight::zero(), )?; let caller2 = signatories2.remove(0); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: approve_as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call_hash, Weight::zero()) - verify { - let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + approve_as_multi( + RawOrigin::Signed(caller2), + s as u16, + signatories2, + Some(timepoint), + call_hash, + Weight::zero(), + ); + + let multisig = + Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; assert_eq!(multisig.approvals.len(), 2); + + Ok(()) } - cancel_as_multi { - // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get(); - // Transaction Length, not a component - let z = 10_000; + /// `z`: Transaction Length, not a component + /// `s`: Signatories, need at least 2 people + #[benchmark] + fn cancel_as_multi( + s: Linear<2, { T::MaxSignatories::get() }>, + z: Linear<0, 10_000>, + ) -> Result<(), BenchmarkError> { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; @@ -204,10 +288,14 @@ benchmarks! { assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: _(RawOrigin::Signed(caller), s as u16, signatories, timepoint, call_hash) - verify { + add_to_whitelist(caller_key.into()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), s as u16, signatories, timepoint, call_hash); + assert!(!Multisigs::::contains_key(multi_account_id, call_hash)); + + Ok(()) } impl_benchmark_test_suite!(Multisig, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/substrate/frame/multisig/src/lib.rs b/substrate/frame/multisig/src/lib.rs index 8faae73c7161..4a30b5c119b9 100644 --- a/substrate/frame/multisig/src/lib.rs +++ b/substrate/frame/multisig/src/lib.rs @@ -49,28 +49,15 @@ mod tests; pub mod weights; extern crate alloc; - use alloc::{boxed::Box, vec, vec::Vec}; -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - dispatch::{ - DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo, - PostDispatchInfo, - }, - ensure, - traits::{Currency, Get, ReservableCurrency}, - weights::Weight, - BoundedVec, -}; -use frame_system::{self as system, pallet_prelude::BlockNumberFor, RawOrigin}; -use scale_info::TypeInfo; -use sp_io::hashing::blake2_256; -use sp_runtime::{ - traits::{Dispatchable, TrailingZeroInput, Zero}, - DispatchError, RuntimeDebug, +use frame::{ + prelude::*, + traits::{Currency, ReservableCurrency}, }; +use frame_system::RawOrigin; pub use weights::WeightInfo; +/// Re-export all pallet items. pub use pallet::*; /// The log target of this pallet. @@ -127,11 +114,9 @@ enum CallOrHash { Hash([u8; 32]), } -#[frame_support::pallet] +#[frame::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; #[pallet::config] pub trait Config: frame_system::Config { @@ -167,7 +152,7 @@ pub mod pallet { type MaxSignatories: Get; /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; + type WeightInfo: weights::WeightInfo; } /// The in-code storage version. @@ -641,8 +626,8 @@ impl Pallet { /// The current `Timepoint`. pub fn timepoint() -> Timepoint> { Timepoint { - height: >::block_number(), - index: >::extrinsic_index().unwrap_or_default(), + height: >::block_number(), + index: >::extrinsic_index().unwrap_or_default(), } } diff --git a/substrate/frame/multisig/src/migrations.rs b/substrate/frame/multisig/src/migrations.rs index e6402600d0d3..8d6e77813673 100644 --- a/substrate/frame/multisig/src/migrations.rs +++ b/substrate/frame/multisig/src/migrations.rs @@ -17,21 +17,15 @@ // Migrations for Multisig Pallet -use super::*; -use frame_support::{ - traits::{GetStorageVersion, OnRuntimeUpgrade, WrapperKeepOpaque}, - Identity, -}; - -#[cfg(feature = "try-runtime")] -use frame_support::ensure; +use crate::*; +use frame::prelude::*; pub mod v1 { use super::*; - type OpaqueCall = WrapperKeepOpaque<::RuntimeCall>; + type OpaqueCall = frame::traits::WrapperKeepOpaque<::RuntimeCall>; - #[frame_support::storage_alias] + #[frame::storage_alias] type Calls = StorageMap< Pallet, Identity, @@ -42,15 +36,14 @@ pub mod v1 { pub struct MigrateToV1(core::marker::PhantomData); impl OnRuntimeUpgrade for MigrateToV1 { #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + fn pre_upgrade() -> Result, frame::try_runtime::TryRuntimeError> { log!(info, "Number of calls to refund and delete: {}", Calls::::iter().count()); Ok(Vec::new()) } fn on_runtime_upgrade() -> Weight { - use sp_runtime::Saturating; - + use frame::traits::ReservableCurrency as _; let current = Pallet::::in_code_storage_version(); let onchain = Pallet::::on_chain_storage_version(); @@ -76,7 +69,7 @@ pub mod v1 { } #[cfg(feature = "try-runtime")] - fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + fn post_upgrade(_state: Vec) -> Result<(), frame::try_runtime::TryRuntimeError> { ensure!( Calls::::iter().count() == 0, "there are some dangling calls that need to be destroyed and refunded" diff --git a/substrate/frame/multisig/src/tests.rs b/substrate/frame/multisig/src/tests.rs index 4f8a7a44243c..c5a98845270c 100644 --- a/substrate/frame/multisig/src/tests.rs +++ b/substrate/frame/multisig/src/tests.rs @@ -20,18 +20,13 @@ #![cfg(test)] use super::*; - use crate as pallet_multisig; -use frame_support::{ - assert_noop, assert_ok, derive_impl, - traits::{ConstU32, ConstU64, Contains}, -}; -use sp_runtime::{BuildStorage, TokenError}; +use frame::{prelude::*, runtime::prelude::*, testing_prelude::*}; type Block = frame_system::mocking::MockBlockU32; -frame_support::construct_runtime!( - pub enum Test { +construct_runtime!( + pub struct Test { System: frame_system, Balances: pallet_balances, Multisig: pallet_multisig, @@ -75,14 +70,14 @@ impl Config for Test { use pallet_balances::Call as BalancesCall; -pub fn new_test_ext() -> sp_io::TestExternalities { +pub fn new_test_ext() -> TestState { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![(1, 10), (2, 10), (3, 10), (4, 10), (5, 2)], } .assimilate_storage(&mut t) .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); + let mut ext = TestState::new(t); ext.execute_with(|| System::set_block_number(1)); ext } diff --git a/substrate/frame/multisig/src/weights.rs b/substrate/frame/multisig/src/weights.rs index ac1c1b23b030..fb263116ea62 100644 --- a/substrate/frame/multisig/src/weights.rs +++ b/substrate/frame/multisig/src/weights.rs @@ -46,9 +46,8 @@ #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - +// TODO update this in frame-weight-template.hbs +use frame::weights_prelude::*; /// Weight functions needed for `pallet_multisig`. pub trait WeightInfo { fn as_multi_threshold_1(z: u32, ) -> Weight; diff --git a/substrate/frame/proxy/Cargo.toml b/substrate/frame/proxy/Cargo.toml index 40c1c9750614..8897c66419c7 100644 --- a/substrate/frame/proxy/Cargo.toml +++ b/substrate/frame/proxy/Cargo.toml @@ -18,43 +18,26 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { features = ["max-encoded-len"], workspace = true } scale-info = { features = ["derive"], workspace = true } -frame-benchmarking = { optional = true, workspace = true } -frame-support = { workspace = true } -frame-system = { workspace = true } -sp-io = { workspace = true } -sp-runtime = { workspace = true } +frame = { workspace = true, features = ["experimental", "runtime"] } [dev-dependencies] pallet-balances = { workspace = true, default-features = true } pallet-utility = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } [features] default = ["std"] std = [ "codec/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", - "pallet-balances/std", - "pallet-utility/std", + "frame/std", "scale-info/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", ] runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", + "frame/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-utility/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", + "frame/try-runtime", "pallet-balances/try-runtime", "pallet-utility/try-runtime", - "sp-runtime/try-runtime", ] diff --git a/substrate/frame/proxy/src/benchmarking.rs b/substrate/frame/proxy/src/benchmarking.rs index 4081af49c243..eebb506bf374 100644 --- a/substrate/frame/proxy/src/benchmarking.rs +++ b/substrate/frame/proxy/src/benchmarking.rs @@ -22,9 +22,7 @@ use super::*; use crate::Pallet as Proxy; use alloc::{boxed::Box, vec}; -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; -use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; -use sp_runtime::traits::Bounded; +use frame::benchmarking::prelude::*; const SEED: u32 = 0; @@ -80,24 +78,36 @@ fn add_announcements( Ok(()) } -benchmarks! { - proxy { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn proxy(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); - }: _(RawOrigin::Signed(caller), real_lookup, Some(T::ProxyType::default()), Box::new(call)) - verify { - assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), real_lookup, Some(T::ProxyType::default()), Box::new(call)); + + assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()); + + Ok(()) } - proxy_announced { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn proxy_announced( + a: Linear<0, { T::MaxPending::get() - 1 }>, + p: Linear<1, { T::MaxProxies::get() - 1 }>, + ) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("pure", 0, SEED); let delegate: T::AccountId = account("target", p - 1, SEED); @@ -106,43 +116,65 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(delegate.clone()).into(), real_lookup.clone(), T::CallHasher::hash_of(&call), )?; add_announcements::(a, Some(delegate.clone()), None)?; - }: _(RawOrigin::Signed(caller), delegate_lookup, real_lookup, Some(T::ProxyType::default()), Box::new(call)) - verify { - assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) + + #[extrinsic_call] + _( + RawOrigin::Signed(caller), + delegate_lookup, + real_lookup, + Some(T::ProxyType::default()), + Box::new(call), + ); + + assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()); + + Ok(()) } - remove_announcement { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn remove_announcement( + a: Linear<0, { T::MaxPending::get() - 1 }>, + p: Linear<1, { T::MaxProxies::get() - 1 }>, + ) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), real_lookup.clone(), T::CallHasher::hash_of(&call), )?; add_announcements::(a, Some(caller.clone()), None)?; - }: _(RawOrigin::Signed(caller.clone()), real_lookup, T::CallHasher::hash_of(&call)) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), real_lookup, T::CallHasher::hash_of(&call)); + let (announcements, _) = Announcements::::get(&caller); assert_eq!(announcements.len() as u32, a); + + Ok(()) } - reject_announcement { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn reject_announcement( + a: Linear<0, { T::MaxPending::get() - 1 }>, + p: Linear<1, { T::MaxProxies::get() - 1 }>, + ) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); let caller_lookup = T::Lookup::unlookup(caller.clone()); @@ -150,22 +182,30 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real.clone()); - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), real_lookup, T::CallHasher::hash_of(&call), )?; add_announcements::(a, Some(caller.clone()), None)?; - }: _(RawOrigin::Signed(real), caller_lookup, T::CallHasher::hash_of(&call)) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(real), caller_lookup, T::CallHasher::hash_of(&call)); + let (announcements, _) = Announcements::::get(&caller); assert_eq!(announcements.len() as u32, a); + + Ok(()) } - announce { - let a in 0 .. T::MaxPending::get() - 1; - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn announce( + a: Linear<0, { T::MaxPending::get() - 1 }>, + p: Linear<1, { T::MaxProxies::get() - 1 }>, + ) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; // In this case the caller is the "target" proxy let caller: T::AccountId = account("target", p - 1, SEED); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value() / 2u32.into()); @@ -173,74 +213,101 @@ benchmarks! { let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real.clone()); add_announcements::(a, Some(caller.clone()), None)?; - let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = + frame_system::Call::::remark { remark: vec![] }.into(); let call_hash = T::CallHasher::hash_of(&call); - }: _(RawOrigin::Signed(caller.clone()), real_lookup, call_hash) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), real_lookup, call_hash); + assert_last_event::(Event::Announced { real, proxy: caller, call_hash }.into()); + + Ok(()) } - add_proxy { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn add_proxy(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); let real = T::Lookup::unlookup(account("target", T::MaxProxies::get(), SEED)); - }: _( - RawOrigin::Signed(caller.clone()), - real, - T::ProxyType::default(), - BlockNumberFor::::zero() - ) - verify { + + #[extrinsic_call] + _( + RawOrigin::Signed(caller.clone()), + real, + T::ProxyType::default(), + BlockNumberFor::::zero(), + ); + let (proxies, _) = Proxies::::get(caller); assert_eq!(proxies.len() as u32, p + 1); + + Ok(()) } - remove_proxy { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn remove_proxy(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); let delegate = T::Lookup::unlookup(account("target", 0, SEED)); - }: _( - RawOrigin::Signed(caller.clone()), - delegate, - T::ProxyType::default(), - BlockNumberFor::::zero() - ) - verify { + + #[extrinsic_call] + _( + RawOrigin::Signed(caller.clone()), + delegate, + T::ProxyType::default(), + BlockNumberFor::::zero(), + ); + let (proxies, _) = Proxies::::get(caller); assert_eq!(proxies.len() as u32, p - 1); + + Ok(()) } - remove_proxies { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn remove_proxies(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); - }: _(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone())); + let (proxies, _) = Proxies::::get(caller); assert_eq!(proxies.len() as u32, 0); + + Ok(()) } - create_pure { - let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; + #[benchmark] + fn create_pure(p: Linear<1, { T::MaxProxies::get() - 1 }>) -> Result<(), BenchmarkError> { + add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); - }: _( - RawOrigin::Signed(caller.clone()), - T::ProxyType::default(), - BlockNumberFor::::zero(), - 0 - ) - verify { + + #[extrinsic_call] + _( + RawOrigin::Signed(caller.clone()), + T::ProxyType::default(), + BlockNumberFor::::zero(), + 0, + ); + let pure_account = Pallet::::pure_account(&caller, &T::ProxyType::default(), 0, None); - assert_last_event::(Event::PureCreated { - pure: pure_account, - who: caller, - proxy_type: T::ProxyType::default(), - disambiguation_index: 0, - }.into()); - } + assert_last_event::( + Event::PureCreated { + pure: pure_account, + who: caller, + proxy_type: T::ProxyType::default(), + disambiguation_index: 0, + } + .into(), + ); - kill_pure { - let p in 0 .. (T::MaxProxies::get() - 2); + Ok(()) + } + #[benchmark] + fn kill_pure(p: Linear<0, { T::MaxProxies::get() - 2 }>) -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); @@ -248,17 +315,28 @@ benchmarks! { RawOrigin::Signed(whitelisted_caller()).into(), T::ProxyType::default(), BlockNumberFor::::zero(), - 0 + 0, )?; - let height = system::Pallet::::block_number(); - let ext_index = system::Pallet::::extrinsic_index().unwrap_or(0); + let height = frame_system::Pallet::::block_number(); + let ext_index = frame_system::Pallet::::extrinsic_index().unwrap_or(0); let pure_account = Pallet::::pure_account(&caller, &T::ProxyType::default(), 0, None); add_proxies::(p, Some(pure_account.clone()))?; ensure!(Proxies::::contains_key(&pure_account), "pure proxy not created"); - }: _(RawOrigin::Signed(pure_account.clone()), caller_lookup, T::ProxyType::default(), 0, height, ext_index) - verify { + + #[extrinsic_call] + _( + RawOrigin::Signed(pure_account.clone()), + caller_lookup, + T::ProxyType::default(), + 0, + height, + ext_index, + ); + assert!(!Proxies::::contains_key(&pure_account)); + + Ok(()) } impl_benchmark_test_suite!(Proxy, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/substrate/frame/proxy/src/lib.rs b/substrate/frame/proxy/src/lib.rs index c041880a59df..cc8aeedcc5f9 100644 --- a/substrate/frame/proxy/src/lib.rs +++ b/substrate/frame/proxy/src/lib.rs @@ -34,23 +34,12 @@ mod tests; pub mod weights; extern crate alloc; - use alloc::{boxed::Box, vec}; -use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - dispatch::GetDispatchInfo, - ensure, - traits::{Currency, Get, InstanceFilter, IsSubType, IsType, OriginTrait, ReservableCurrency}, - BoundedVec, +use frame::{ + prelude::*, + traits::{Currency, ReservableCurrency}, }; -use frame_system::{self as system, ensure_signed, pallet_prelude::BlockNumberFor}; pub use pallet::*; -use scale_info::TypeInfo; -use sp_io::hashing::blake2_256; -use sp_runtime::{ - traits::{Dispatchable, Hash, Saturating, StaticLookup, TrailingZeroInput, Zero}, - DispatchError, DispatchResult, RuntimeDebug, -}; pub use weights::WeightInfo; type CallHashOf = <::CallHasher as Hash>::Output; @@ -96,11 +85,9 @@ pub struct Announcement { height: BlockNumber, } -#[frame_support::pallet] +#[frame::pallet] pub mod pallet { - use super::{DispatchResult, *}; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; + use super::*; #[pallet::pallet] pub struct Pallet(_); @@ -130,7 +117,7 @@ pub mod pallet { + Member + Ord + PartialOrd - + InstanceFilter<::RuntimeCall> + + frame::traits::InstanceFilter<::RuntimeCall> + Default + MaxEncodedLen; @@ -392,7 +379,7 @@ pub mod pallet { let announcement = Announcement { real: real.clone(), call_hash, - height: system::Pallet::::block_number(), + height: frame_system::Pallet::::block_number(), }; Announcements::::try_mutate(&who, |(ref mut pending, ref mut deposit)| { @@ -503,7 +490,7 @@ pub mod pallet { let def = Self::find_proxy(&real, &delegate, force_proxy_type)?; let call_hash = T::CallHasher::hash_of(&call); - let now = system::Pallet::::block_number(); + let now = frame_system::Pallet::::block_number(); Self::edit_announcements(&delegate, |ann| { ann.real != real || ann.call_hash != call_hash || @@ -639,8 +626,8 @@ impl Pallet { ) -> T::AccountId { let (height, ext_index) = maybe_when.unwrap_or_else(|| { ( - system::Pallet::::block_number(), - system::Pallet::::extrinsic_index().unwrap_or_default(), + frame_system::Pallet::::block_number(), + frame_system::Pallet::::extrinsic_index().unwrap_or_default(), ) }); let entropy = (b"modlpy/proxy____", who, height, ext_index, proxy_type, index) @@ -796,6 +783,7 @@ impl Pallet { real: T::AccountId, call: ::RuntimeCall, ) { + use frame::traits::{InstanceFilter as _, OriginTrait as _}; // This is a freshly authenticated new account, the origin restrictions doesn't apply. let mut origin: T::RuntimeOrigin = frame_system::RawOrigin::Signed(real).into(); origin.add_filter(move |c: &::RuntimeCall| { diff --git a/substrate/frame/proxy/src/tests.rs b/substrate/frame/proxy/src/tests.rs index 3edb96026a82..5baf9bb9e838 100644 --- a/substrate/frame/proxy/src/tests.rs +++ b/substrate/frame/proxy/src/tests.rs @@ -20,22 +20,14 @@ #![cfg(test)] use super::*; - use crate as proxy; use alloc::{vec, vec::Vec}; -use codec::{Decode, Encode}; -use frame_support::{ - assert_noop, assert_ok, derive_impl, - traits::{ConstU32, ConstU64, Contains}, -}; -use sp_core::H256; -use sp_runtime::{traits::BlakeTwo256, BuildStorage, DispatchError, RuntimeDebug}; +use frame::testing_prelude::*; type Block = frame_system::mocking::MockBlock; -frame_support::construct_runtime!( - pub enum Test - { +construct_runtime!( + pub struct Test { System: frame_system, Balances: pallet_balances, Proxy: proxy, @@ -86,7 +78,7 @@ impl Default for ProxyType { Self::Any } } -impl InstanceFilter for ProxyType { +impl frame::traits::InstanceFilter for ProxyType { fn filter(&self, c: &RuntimeCall) -> bool { match self { ProxyType::Any => true, @@ -136,20 +128,20 @@ use pallet_utility::{Call as UtilityCall, Event as UtilityEvent}; type SystemError = frame_system::Error; -pub fn new_test_ext() -> sp_io::TestExternalities { +pub fn new_test_ext() -> TestState { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![(1, 10), (2, 10), (3, 10), (4, 10), (5, 3)], } .assimilate_storage(&mut t) .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); + let mut ext = TestState::new(t); ext.execute_with(|| System::set_block_number(1)); ext } fn last_events(n: usize) -> Vec { - system::Pallet::::events() + frame_system::Pallet::::events() .into_iter() .rev() .take(n) @@ -286,7 +278,7 @@ fn delayed_requires_pre_announcement() { assert_noop!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 2, 1, None, call.clone()), e); let call_hash = BlakeTwo256::hash_of(&call); assert_ok!(Proxy::announce(RuntimeOrigin::signed(2), 1, call_hash)); - system::Pallet::::set_block_number(2); + frame_system::Pallet::::set_block_number(2); assert_ok!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 2, 1, None, call.clone())); }); } @@ -304,7 +296,7 @@ fn proxy_announced_removes_announcement_and_returns_deposit() { let e = Error::::Unannounced; assert_noop!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 3, 1, None, call.clone()), e); - system::Pallet::::set_block_number(2); + frame_system::Pallet::::set_block_number(2); assert_ok!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 3, 1, None, call.clone())); let announcements = Announcements::::get(3); assert_eq!(announcements.0, vec![Announcement { real: 2, call_hash, height: 1 }]); diff --git a/substrate/frame/proxy/src/weights.rs b/substrate/frame/proxy/src/weights.rs index 3093298e3e54..eab2cb4b2683 100644 --- a/substrate/frame/proxy/src/weights.rs +++ b/substrate/frame/proxy/src/weights.rs @@ -46,8 +46,7 @@ #![allow(unused_imports)] #![allow(missing_docs)] -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; +use frame::weights_prelude::*; /// Weight functions needed for `pallet_proxy`. pub trait WeightInfo { diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index ade1095cc504..a8d2c0b3fc56 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -32,10 +32,17 @@ //! //! ## Usage //! -//! The main intended use of this crate is for it to be imported with its preludes: +//! This crate is organized into 3 stages: +//! +//! 1. preludes: `prelude`, `testing_prelude` and `runtime::prelude`, `benchmarking`, +//! `weights_prelude`, `try_runtime`. +//! 2. domain-specific modules: `traits`, `hashing`, `arithmetic` and `derive`. +//! 3. Accessing frame/substrate dependencies directly: `deps`. +//! +//! The main intended use of this crate is for it to be used with the former, preludes: //! //! ``` -//! # use polkadot_sdk_frame as frame; +//! use polkadot_sdk_frame as frame; //! #[frame::pallet] //! pub mod pallet { //! # use polkadot_sdk_frame as frame; @@ -49,36 +56,98 @@ //! pub struct Pallet(_); //! } //! +//! #[cfg(test)] //! pub mod tests { //! # use polkadot_sdk_frame as frame; //! use frame::testing_prelude::*; //! } //! +//! #[cfg(feature = "runtime-benchmarks")] +//! pub mod benchmarking { +//! # use polkadot_sdk_frame as frame; +//! use frame::benchmarking::prelude::*; +//! } +//! //! pub mod runtime { //! # use polkadot_sdk_frame as frame; //! use frame::runtime::prelude::*; //! } //! ``` //! -//! See: [`prelude`], [`testing_prelude`] and [`runtime::prelude`]. +//! If not in preludes, one can look into the domain-specific modules. Finally, if an import is +//! still not feasible, one can look into `deps`. //! -//! Please note that this crate can only be imported as `polkadot-sdk-frame` or `frame`. +//! This crate also uses a `runtime` feature to include all of the types and tools needed to build +//! FRAME-based runtimes. So, if you want to build a runtime with this, import it as //! -//! ## Documentation +//! ```text +//! polkadot-sdk-frame = { version = "foo", features = ["runtime"] } +//! ``` //! -//! See [`polkadot_sdk::frame`](../polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html). +//! If you just want to build a pallet instead, import it as //! -//! ## Underlying dependencies +//! ```text +//! polkadot-sdk-frame = { version = "foo" } +//! ``` //! -//! This crate is an amalgamation of multiple other crates that are often used together to compose a -//! pallet. It is not necessary to use it, and it may fall short for certain purposes. +//! Notice that the preludes overlap since they have imports in common. More in detail: +//! - `testing_prelude` brings in frame `prelude` and `runtime::prelude`; +//! - `runtime::prelude` brings in frame `prelude`; +//! - `benchmarking` brings in frame `prelude`. //! -//! In short, this crate only re-exports types and traits from multiple sources. All of these -//! sources are listed (and re-exported again) in [`deps`]. +//! ## Naming +//! +//! Please note that this crate can only be imported as `polkadot-sdk-frame` or `frame`. This is due +//! to compatibility matters with `frame-support`. +//! +//! A typical pallet's `Cargo.toml` using this crate looks like: +//! +//! ```ignore +//! [dependencies] +//! codec = { features = ["max-encoded-len"], workspace = true } +//! scale-info = { features = ["derive"], workspace = true } +//! frame = { workspace = true, features = ["experimental", "runtime"] } +//! +//! [features] +//! default = ["std"] +//! std = [ +//! "codec/std", +//! "scale-info/std", +//! "frame/std", +//! ] +//! runtime-benchmarks = [ +//! "frame/runtime-benchmarks", +//! ] +//! try-runtime = [ +//! "frame/try-runtime", +//! ] +//! ``` +//! +//! ## Documentation +//! +//! See [`polkadot_sdk::frame`](../polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html). //! //! ## WARNING: Experimental //! //! **This crate and all of its content is experimental, and should not yet be used in production.** +//! +//! ## Maintenance Note +//! +//! > Notes for the maintainers of this crate, describing how the re-exports and preludes should +//! > work. +//! +//! * Preludes should be extensive. The goal of this pallet is to be ONLY used with the preludes. +//! The domain-specific modules are just a backup, aiming to keep things organized. Don't hesitate +//! in adding more items to the main prelude. +//! * The only non-module, non-prelude items exported from the top level crate is the `pallet` +//! macro, such that we can have the `#[frame::pallet] mod pallet { .. }` syntax working. +//! * In most cases, you might want to create a domain-specific module, but also add it to the +//! preludes, such as `hashing`. +//! * The only items that should NOT be in preludes are those that have been placed in +//! `frame-support`/`sp-runtime`, but in truth are related to just one pallet. +//! * The currency related traits are kept out of the preludes to encourage a deliberate choice of +//! one over the other. +//! * `runtime::apis` should expose all common runtime APIs that all FRAME-based runtimes need. #![cfg_attr(not(feature = "std"), no_std)] #![cfg(feature = "experimental")] @@ -92,6 +161,9 @@ pub use frame_support::pallet_macros::{import_section, pallet_section}; /// The logging library of the runtime. Can normally be the classic `log` crate. pub use log; +#[doc(inline)] +pub use frame_support::storage_alias; + /// Macros used within the main [`pallet`] macro. /// /// Note: All of these macros are "stubs" and not really usable outside `#[pallet] mod pallet { .. @@ -128,6 +200,11 @@ pub mod prelude { #[doc(no_inline)] pub use frame_support::pallet_prelude::*; + /// Dispatch types from `frame-support`, other fundamental traits + #[doc(no_inline)] + pub use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; + pub use frame_support::traits::{Contains, IsSubType, OnRuntimeUpgrade}; + /// Pallet prelude of `frame-system`. #[doc(no_inline)] pub use frame_system::pallet_prelude::*; @@ -135,6 +212,78 @@ pub mod prelude { /// All FRAME-relevant derive macros. #[doc(no_inline)] pub use super::derive::*; + + /// All hashing related things + pub use super::hashing::*; + + /// Runtime traits + #[doc(no_inline)] + pub use sp_runtime::traits::{ + Bounded, DispatchInfoOf, Dispatchable, SaturatedConversion, Saturating, StaticLookup, + TrailingZeroInput, + }; + + /// Other error/result types for runtime + #[doc(no_inline)] + pub use sp_runtime::{DispatchErrorWithPostInfo, DispatchResultWithInfo, TokenError}; +} + +#[cfg(any(feature = "try-runtime", test))] +pub mod try_runtime { + pub use sp_runtime::TryRuntimeError; +} + +/// Prelude to be included in the `benchmarking.rs` of a pallet. +/// +/// It supports both the `benchmarking::v1::benchmarks` and `benchmarking::v2::benchmark` syntax. +/// +/// ``` +/// use polkadot_sdk_frame::benchmarking::prelude::*; +/// // rest of your code. +/// ``` +/// +/// It already includes `polkadot_sdk_frame::prelude::*` and `polkadot_sdk_frame::testing_prelude`. +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking { + mod shared { + pub use frame_benchmarking::{add_benchmark, v1::account, whitelist, whitelisted_caller}; + // all benchmarking functions. + pub use frame_benchmarking::benchmarking::*; + // The system origin, which is very often needed in benchmarking code. Might be tricky only + // if the pallet defines its own `#[pallet::origin]` and call it `RawOrigin`. + pub use frame_system::RawOrigin; + } + + #[deprecated( + note = "'The V1 benchmarking syntax is deprecated. Please use the V2 syntax. This warning may become a hard error any time after April 2025. For more info, see: https://github.com/paritytech/polkadot-sdk/pull/5995" + )] + pub mod v1 { + pub use super::shared::*; + pub use frame_benchmarking::benchmarks; + } + + pub mod prelude { + pub use super::shared::*; + pub use crate::prelude::*; + pub use frame_benchmarking::v2::*; + } +} + +/// Prelude to be included in the `weight.rs` of each pallet. +/// +/// ``` +/// pub use polkadot_sdk_frame::weights_prelude::*; +/// ``` +pub mod weights_prelude { + pub use core::marker::PhantomData; + pub use frame_support::{ + traits::Get, + weights::{ + constants::{ParityDbWeight, RocksDbWeight}, + Weight, + }, + }; + pub use frame_system; } /// The main testing prelude of FRAME. @@ -145,9 +294,13 @@ pub mod prelude { /// use polkadot_sdk_frame::testing_prelude::*; /// // rest of your test setup. /// ``` +/// +/// This automatically brings in `polkadot_sdk_frame::prelude::*` and +/// `polkadot_sdk_frame::runtime::prelude::*`. #[cfg(feature = "std")] pub mod testing_prelude { - pub use super::prelude::*; + pub use crate::{prelude::*, runtime::prelude::*}; + /// Testing includes building a runtime, so we bring in all preludes related to runtimes as /// well. pub use super::runtime::testing_prelude::*; @@ -159,6 +312,10 @@ pub mod testing_prelude { }; pub use frame_system::{self, mocking::*}; + + #[deprecated(note = "Use `frame::testing_prelude::TestExternalities` instead.")] + pub use sp_io::TestExternalities; + pub use sp_io::TestExternalities as TestState; } @@ -170,9 +327,13 @@ pub mod runtime { /// A runtime typically starts with: /// /// ``` - /// use polkadot_sdk_frame::{prelude::*, runtime::prelude::*}; + /// use polkadot_sdk_frame::runtime::prelude::*; /// ``` + /// + /// This automatically brings in `polkadot_sdk_frame::prelude::*`. pub mod prelude { + pub use crate::prelude::*; + /// All of the types related to the FRAME runtime executive. pub use frame_executive::*; @@ -328,7 +489,6 @@ pub mod runtime { /// counter part of `runtime::prelude`. #[cfg(feature = "std")] pub mod testing_prelude { - pub use super::prelude::*; pub use sp_core::storage::Storage; pub use sp_runtime::BuildStorage; } @@ -350,12 +510,6 @@ pub mod arithmetic { pub use sp_arithmetic::{traits::*, *}; } -/// Low level primitive types used in FRAME pallets. -pub mod primitives { - pub use sp_core::{H160, H256, H512, U256, U512}; - pub use sp_runtime::traits::{BlakeTwo256, Hash, Keccak256}; -} - /// All derive macros used in frame. /// /// This is already part of the [`prelude`]. @@ -370,12 +524,17 @@ pub mod derive { pub use sp_runtime::RuntimeDebug; } -/// Access to all of the dependencies of this crate. In case the re-exports are not enough, this -/// module can be used. +pub mod hashing { + pub use sp_core::{hashing::*, H160, H256, H512, U256, U512}; + pub use sp_runtime::traits::{BlakeTwo256, Hash, Keccak256}; +} + +/// Access to all of the dependencies of this crate. In case the prelude re-exports are not enough, +/// this module can be used. /// -/// Any time one uses this module to access a dependency, you can have a moment to think about -/// whether this item could have been placed in any of the other modules and preludes in this crate. -/// In most cases, hopefully the answer is yes. +/// Note for maintainers: Any time one uses this module to access a dependency, you can have a +/// moment to think about whether this item could have been placed in any of the other modules and +/// preludes in this crate. In most cases, hopefully the answer is yes. pub mod deps { // TODO: It would be great to somehow instruct RA to prefer *not* suggesting auto-imports from // these. For example, we prefer `polkadot_sdk_frame::derive::CloneNoBound` rather than diff --git a/substrate/scripts/run_all_benchmarks.sh b/substrate/scripts/run_all_benchmarks.sh index fe5f89a5b56e..053c230fedb4 100755 --- a/substrate/scripts/run_all_benchmarks.sh +++ b/substrate/scripts/run_all_benchmarks.sh @@ -108,6 +108,13 @@ for PALLET in "${PALLETS[@]}"; do FOLDER="$(echo "${PALLET#*_}" | tr '_' '-')"; WEIGHT_FILE="./frame/${FOLDER}/src/weights.rs" + TEMPLATE_FILE_NAME="frame-weight-template.hbs" + if [ $(cargo metadata --locked --format-version 1 --no-deps | jq --arg pallet "${PALLET//_/-}" -r '.packages[] | select(.name == $pallet) | .dependencies | any(.name == "polkadot-sdk-frame")') = true ] + then + TEMPLATE_FILE_NAME="frame-umbrella-weight-template.hbs" + fi + TEMPLATE_FILE="./.maintain/${TEMPLATE_FILE_NAME}" + # Special handling of custom weight paths. if [ "$PALLET" == "frame_system_extensions" ] || [ "$PALLET" == "frame-system-extensions" ] then @@ -118,6 +125,9 @@ for PALLET in "${PALLETS[@]}"; do elif [ "$PALLET" == "pallet_asset_tx_payment" ] || [ "$PALLET" == "pallet-asset-tx-payment" ] then WEIGHT_FILE="./frame/transaction-payment/asset-tx-payment/src/weights.rs" + elif [ "$PALLET" == "pallet_asset_conversion_ops" ] || [ "$PALLET" == "pallet-asset-conversion-ops" ] + then + WEIGHT_FILE="./frame/asset-conversion/ops/src/weights.rs" fi echo "[+] Benchmarking $PALLET with weight file $WEIGHT_FILE"; @@ -133,7 +143,7 @@ for PALLET in "${PALLETS[@]}"; do --heap-pages=4096 \ --output="$WEIGHT_FILE" \ --header="./HEADER-APACHE2" \ - --template=./.maintain/frame-weight-template.hbs 2>&1 + --template="$TEMPLATE_FILE" 2>&1 ) if [ $? -ne 0 ]; then echo "$OUTPUT" >> "$ERR_FILE" @@ -173,4 +183,4 @@ if [ -f "$ERR_FILE" ]; then else echo "[+] All benchmarks passed." exit 0 -fi +fi \ No newline at end of file diff --git a/templates/minimal/pallets/template/src/lib.rs b/templates/minimal/pallets/template/src/lib.rs index b8a8614932a6..722b606079f9 100644 --- a/templates/minimal/pallets/template/src/lib.rs +++ b/templates/minimal/pallets/template/src/lib.rs @@ -5,6 +5,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +use frame::prelude::*; use polkadot_sdk::polkadot_sdk_frame as frame; // Re-export all pallet parts, this is needed to properly import the pallet into the runtime. @@ -19,4 +20,7 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(_); + + #[pallet::storage] + pub type Value = StorageValue; } diff --git a/templates/minimal/runtime/Cargo.toml b/templates/minimal/runtime/Cargo.toml index 74a09b9396e5..b803c74539ef 100644 --- a/templates/minimal/runtime/Cargo.toml +++ b/templates/minimal/runtime/Cargo.toml @@ -13,7 +13,6 @@ publish = false codec = { workspace = true } scale-info = { workspace = true } polkadot-sdk = { workspace = true, features = [ - "experimental", "pallet-balances", "pallet-sudo", "pallet-timestamp", diff --git a/templates/minimal/runtime/src/lib.rs b/templates/minimal/runtime/src/lib.rs index 4f914a823bf6..304e50af2508 100644 --- a/templates/minimal/runtime/src/lib.rs +++ b/templates/minimal/runtime/src/lib.rs @@ -30,7 +30,7 @@ use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; use polkadot_sdk::{ polkadot_sdk_frame::{ self as frame, - prelude::*, + deps::sp_genesis_builder, runtime::{apis, prelude::*}, }, *, @@ -38,15 +38,14 @@ use polkadot_sdk::{ /// Provides getters for genesis configuration presets. pub mod genesis_config_presets { + use super::*; use crate::{ interface::{Balance, MinimumBalance}, - sp_genesis_builder::PresetId, sp_keyring::AccountKeyring, BalancesConfig, RuntimeGenesisConfig, SudoConfig, }; use alloc::{vec, vec::Vec}; - use polkadot_sdk::{sp_core::Get, sp_genesis_builder}; use serde_json::Value; /// Returns a development genesis config preset. @@ -314,17 +313,17 @@ impl_runtime_apis! { } } - impl sp_genesis_builder::GenesisBuilder for Runtime { + impl apis::GenesisBuilder for Runtime { fn build_state(config: Vec) -> sp_genesis_builder::Result { build_state::(config) } - fn get_preset(id: &Option) -> Option> { + fn get_preset(id: &Option) -> Option> { get_preset::(id, self::genesis_config_presets::get_preset) } - fn preset_names() -> Vec { - crate::genesis_config_presets::preset_names() + fn preset_names() -> Vec { + self::genesis_config_presets::preset_names() } } } From 1497635148bb017182be35cdf95f21605545d6f6 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Tue, 29 Oct 2024 21:21:48 +0800 Subject: [PATCH 3/5] Migrate pallet-vesting benchmark to v2 (#6254) Part of: - #6202. --- substrate/frame/vesting/src/benchmarking.rs | 348 ++++++++++-------- substrate/primitives/panic-handler/src/lib.rs | 4 +- 2 files changed, 192 insertions(+), 160 deletions(-) diff --git a/substrate/frame/vesting/src/benchmarking.rs b/substrate/frame/vesting/src/benchmarking.rs index 736dd6eac1a8..503655243fb4 100644 --- a/substrate/frame/vesting/src/benchmarking.rs +++ b/substrate/frame/vesting/src/benchmarking.rs @@ -19,13 +19,12 @@ #![cfg(feature = "runtime-benchmarks")] -use frame_benchmarking::v1::{account, benchmarks, whitelisted_caller}; +use frame_benchmarking::{v2::*, BenchmarkError}; use frame_support::assert_ok; -use frame_system::{pallet_prelude::BlockNumberFor, Pallet as System, RawOrigin}; +use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use sp_runtime::traits::{Bounded, CheckedDiv, CheckedMul}; -use super::{Vesting as VestingStorage, *}; -use crate::Pallet as Vesting; +use crate::*; const SEED: u32 = 0; @@ -35,7 +34,7 @@ type BalanceOf = fn add_locks(who: &T::AccountId, n: u8) { for id in 0..n { let lock_id = [id; 8]; - let locked = 256u32; + let locked = 256_u32; let reasons = WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE; T::Currency::set_lock(lock_id, who, locked.into(), reasons); } @@ -46,12 +45,12 @@ fn add_vesting_schedules( n: u32, ) -> Result, &'static str> { let min_transfer = T::MinVestedTransfer::get(); - let locked = min_transfer.checked_mul(&20u32.into()).unwrap(); + let locked = min_transfer.checked_mul(&20_u32.into()).unwrap(); // Schedule has a duration of 20. let per_block = min_transfer; - let starting_block = 1u32; + let starting_block = 1_u32; - let source: T::AccountId = account("source", 0, SEED); + let source = account("source", 0, SEED); T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); T::BlockNumberProvider::set_block_number(BlockNumberFor::::zero()); @@ -61,7 +60,7 @@ fn add_vesting_schedules( total_locked += locked; let schedule = VestingInfo::new(locked, per_block, starting_block.into()); - assert_ok!(Vesting::::do_vested_transfer(&source, target, schedule)); + assert_ok!(Pallet::::do_vested_transfer(&source, target, schedule)); // Top up to guarantee we can always transfer another schedule. T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); @@ -70,66 +69,76 @@ fn add_vesting_schedules( Ok(total_locked) } -benchmarks! { - vest_locked { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 1 .. T::MAX_VESTING_SCHEDULES; +#[benchmarks] +mod benchmarks { + use super::*; - let caller: T::AccountId = whitelisted_caller(); + #[benchmark] + fn vest_locked( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<1, T::MAX_VESTING_SCHEDULES>, + ) -> Result<(), BenchmarkError> { + let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); let expected_balance = add_vesting_schedules::(&caller, s)?; // At block zero, everything is vested. - assert_eq!(System::::block_number(), BlockNumberFor::::zero()); + assert_eq!(frame_system::Pallet::::block_number(), BlockNumberFor::::zero()); assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting schedule not added", ); - }: vest(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + vest(RawOrigin::Signed(caller.clone())); + // Nothing happened since everything is still vested. assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting schedule was removed", ); - } - vest_unlocked { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 1 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } - let caller: T::AccountId = whitelisted_caller(); + #[benchmark] + fn vest_unlocked( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<1, T::MAX_VESTING_SCHEDULES>, + ) -> Result<(), BenchmarkError> { + let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); add_vesting_schedules::(&caller, s)?; // At block 21, everything is unlocked. - T::BlockNumberProvider::set_block_number(21u32.into()); + T::BlockNumberProvider::set_block_number(21_u32.into()); assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(BalanceOf::::zero()), "Vesting schedule still active", ); - }: vest(RawOrigin::Signed(caller.clone())) - verify { + + #[extrinsic_call] + vest(RawOrigin::Signed(caller.clone())); + // Vesting schedule is removed! - assert_eq!( - Vesting::::vesting_balance(&caller), - None, - "Vesting schedule was not removed", - ); - } + assert_eq!(Pallet::::vesting_balance(&caller), None, "Vesting schedule was not removed",); - vest_other_locked { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 1 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } - let other: T::AccountId = account("other", 0, SEED); + #[benchmark] + fn vest_other_locked( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<1, T::MAX_VESTING_SCHEDULES>, + ) -> Result<(), BenchmarkError> { + let other = account::("other", 0, SEED); let other_lookup = T::Lookup::unlookup(other.clone()); T::Currency::make_free_balance_be(&other, T::Currency::minimum_balance()); @@ -137,64 +146,70 @@ benchmarks! { let expected_balance = add_vesting_schedules::(&other, s)?; // At block zero, everything is vested. - assert_eq!(System::::block_number(), BlockNumberFor::::zero()); + assert_eq!(frame_system::Pallet::::block_number(), BlockNumberFor::::zero()); assert_eq!( - Vesting::::vesting_balance(&other), + Pallet::::vesting_balance(&other), Some(expected_balance), "Vesting schedule not added", ); - let caller: T::AccountId = whitelisted_caller(); - }: vest_other(RawOrigin::Signed(caller.clone()), other_lookup) - verify { + let caller = whitelisted_caller::(); + + #[extrinsic_call] + vest_other(RawOrigin::Signed(caller.clone()), other_lookup); + // Nothing happened since everything is still vested. assert_eq!( - Vesting::::vesting_balance(&other), + Pallet::::vesting_balance(&other), Some(expected_balance), "Vesting schedule was removed", ); - } - vest_other_unlocked { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 1 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } - let other: T::AccountId = account("other", 0, SEED); + #[benchmark] + fn vest_other_unlocked( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<1, { T::MAX_VESTING_SCHEDULES }>, + ) -> Result<(), BenchmarkError> { + let other = account::("other", 0, SEED); let other_lookup = T::Lookup::unlookup(other.clone()); T::Currency::make_free_balance_be(&other, T::Currency::minimum_balance()); add_locks::(&other, l as u8); add_vesting_schedules::(&other, s)?; // At block 21 everything is unlocked. - T::BlockNumberProvider::set_block_number(21u32.into()); + T::BlockNumberProvider::set_block_number(21_u32.into()); assert_eq!( - Vesting::::vesting_balance(&other), + Pallet::::vesting_balance(&other), Some(BalanceOf::::zero()), "Vesting schedule still active", ); - let caller: T::AccountId = whitelisted_caller(); - }: vest_other(RawOrigin::Signed(caller.clone()), other_lookup) - verify { + let caller = whitelisted_caller::(); + + #[extrinsic_call] + vest_other(RawOrigin::Signed(caller.clone()), other_lookup); + // Vesting schedule is removed. - assert_eq!( - Vesting::::vesting_balance(&other), - None, - "Vesting schedule was not removed", - ); - } + assert_eq!(Pallet::::vesting_balance(&other), None, "Vesting schedule was not removed",); - vested_transfer { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 0 .. T::MAX_VESTING_SCHEDULES - 1; + Ok(()) + } - let caller: T::AccountId = whitelisted_caller(); + #[benchmark] + fn vested_transfer( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<0, { T::MAX_VESTING_SCHEDULES - 1 }>, + ) -> Result<(), BenchmarkError> { + let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let target: T::AccountId = account("target", 0, SEED); + let target = account::("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - // Give target existing locks + // Give target existing locks. T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); add_locks::(&target, l as u8); // Add one vesting schedules. @@ -202,74 +217,75 @@ benchmarks! { let mut expected_balance = add_vesting_schedules::(&target, s)?; let transfer_amount = T::MinVestedTransfer::get(); - let per_block = transfer_amount.checked_div(&20u32.into()).unwrap(); + let per_block = transfer_amount.checked_div(&20_u32.into()).unwrap(); expected_balance += transfer_amount; - let vesting_schedule = VestingInfo::new( - transfer_amount, - per_block, - 1u32.into(), - ); - }: _(RawOrigin::Signed(caller), target_lookup, vesting_schedule) - verify { + let vesting_schedule = VestingInfo::new(transfer_amount, per_block, 1_u32.into()); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), target_lookup, vesting_schedule); + assert_eq!( orig_balance + expected_balance, T::Currency::free_balance(&target), "Transfer didn't happen", ); assert_eq!( - Vesting::::vesting_balance(&target), + Pallet::::vesting_balance(&target), Some(expected_balance), "Lock not correctly updated", ); - } - force_vested_transfer { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 0 .. T::MAX_VESTING_SCHEDULES - 1; + Ok(()) + } - let source: T::AccountId = account("source", 0, SEED); + #[benchmark] + fn force_vested_transfer( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<0, { T::MAX_VESTING_SCHEDULES - 1 }>, + ) -> Result<(), BenchmarkError> { + let source = account::("source", 0, SEED); let source_lookup = T::Lookup::unlookup(source.clone()); T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); - let target: T::AccountId = account("target", 0, SEED); + let target = account::("target", 0, SEED); let target_lookup = T::Lookup::unlookup(target.clone()); - // Give target existing locks + // Give target existing locks. T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); add_locks::(&target, l as u8); - // Add one less than max vesting schedules + // Add one less than max vesting schedules. let orig_balance = T::Currency::free_balance(&target); let mut expected_balance = add_vesting_schedules::(&target, s)?; let transfer_amount = T::MinVestedTransfer::get(); - let per_block = transfer_amount.checked_div(&20u32.into()).unwrap(); + let per_block = transfer_amount.checked_div(&20_u32.into()).unwrap(); expected_balance += transfer_amount; - let vesting_schedule = VestingInfo::new( - transfer_amount, - per_block, - 1u32.into(), - ); - }: _(RawOrigin::Root, source_lookup, target_lookup, vesting_schedule) - verify { + let vesting_schedule = VestingInfo::new(transfer_amount, per_block, 1_u32.into()); + + #[extrinsic_call] + _(RawOrigin::Root, source_lookup, target_lookup, vesting_schedule); + assert_eq!( orig_balance + expected_balance, T::Currency::free_balance(&target), "Transfer didn't happen", ); assert_eq!( - Vesting::::vesting_balance(&target), + Pallet::::vesting_balance(&target), Some(expected_balance), - "Lock not correctly updated", - ); - } + "Lock not correctly updated", + ); - not_unlocking_merge_schedules { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 2 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } - let caller: T::AccountId = account("caller", 0, SEED); - let caller_lookup = T::Lookup::unlookup(caller.clone()); + #[benchmark] + fn not_unlocking_merge_schedules( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<2, { T::MAX_VESTING_SCHEDULES }>, + ) -> Result<(), BenchmarkError> { + let caller = whitelisted_caller::(); // Give target existing locks. T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); @@ -277,115 +293,127 @@ benchmarks! { let expected_balance = add_vesting_schedules::(&caller, s)?; // Schedules are not vesting at block 0. - assert_eq!(System::::block_number(), BlockNumberFor::::zero()); + assert_eq!(frame_system::Pallet::::block_number(), BlockNumberFor::::zero()); assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting balance should equal sum locked of all schedules", ); assert_eq!( - VestingStorage::::get(&caller).unwrap().len(), + Vesting::::get(&caller).unwrap().len(), s as usize, "There should be exactly max vesting schedules" ); - }: merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1) - verify { + + #[extrinsic_call] + merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1); + let expected_schedule = VestingInfo::new( - T::MinVestedTransfer::get() * 20u32.into() * 2u32.into(), - T::MinVestedTransfer::get() * 2u32.into(), - 1u32.into(), + T::MinVestedTransfer::get() * 20_u32.into() * 2_u32.into(), + T::MinVestedTransfer::get() * 2_u32.into(), + 1_u32.into(), ); let expected_index = (s - 2) as usize; + assert_eq!(Vesting::::get(&caller).unwrap()[expected_index], expected_schedule); assert_eq!( - VestingStorage::::get(&caller).unwrap()[expected_index], - expected_schedule - ); - assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting balance should equal total locked of all schedules", ); assert_eq!( - VestingStorage::::get(&caller).unwrap().len(), + Vesting::::get(&caller).unwrap().len(), (s - 1) as usize, "Schedule count should reduce by 1" ); - } - unlocking_merge_schedules { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 2 .. T::MAX_VESTING_SCHEDULES; + Ok(()) + } + #[benchmark] + fn unlocking_merge_schedules( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<2, { T::MAX_VESTING_SCHEDULES }>, + ) -> Result<(), BenchmarkError> { // Destination used just for currency transfers in asserts. let test_dest: T::AccountId = account("test_dest", 0, SEED); - let caller: T::AccountId = account("caller", 0, SEED); - let caller_lookup = T::Lookup::unlookup(caller.clone()); - // Give target other locks. + let caller = whitelisted_caller::(); + // Give target existing locks. T::Currency::make_free_balance_be(&caller, T::Currency::minimum_balance()); add_locks::(&caller, l as u8); // Add max vesting schedules. let total_transferred = add_vesting_schedules::(&caller, s)?; - // Go to about half way through all the schedules duration. (They all start at 1, and have a duration of 20 or 21). - T::BlockNumberProvider::set_block_number(11u32.into()); - // We expect half the original locked balance (+ any remainder that vests on the last block). - let expected_balance = total_transferred / 2u32.into(); + // Go to about half way through all the schedules duration. (They all start at 1, and have a + // duration of 20 or 21). + T::BlockNumberProvider::set_block_number(11_u32.into()); + // We expect half the original locked balance (+ any remainder that vests on the last + // block). + let expected_balance = total_transferred / 2_u32.into(); assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting balance should reflect that we are half way through all schedules duration", ); assert_eq!( - VestingStorage::::get(&caller).unwrap().len(), + Vesting::::get(&caller).unwrap().len(), s as usize, "There should be exactly max vesting schedules" ); // The balance is not actually transferable because it has not been unlocked. - assert!(T::Currency::transfer(&caller, &test_dest, expected_balance, ExistenceRequirement::AllowDeath).is_err()); - }: merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1) - verify { + assert!(T::Currency::transfer( + &caller, + &test_dest, + expected_balance, + ExistenceRequirement::AllowDeath + ) + .is_err()); + + #[extrinsic_call] + merge_schedules(RawOrigin::Signed(caller.clone()), 0, s - 1); + let expected_schedule = VestingInfo::new( - T::MinVestedTransfer::get() * 2u32.into() * 10u32.into(), - T::MinVestedTransfer::get() * 2u32.into(), - 11u32.into(), + T::MinVestedTransfer::get() * 2_u32.into() * 10_u32.into(), + T::MinVestedTransfer::get() * 2_u32.into(), + 11_u32.into(), ); let expected_index = (s - 2) as usize; assert_eq!( - VestingStorage::::get(&caller).unwrap()[expected_index], + Vesting::::get(&caller).unwrap()[expected_index], expected_schedule, "New schedule is properly created and placed" ); assert_eq!( - VestingStorage::::get(&caller).unwrap()[expected_index], - expected_schedule - ); - assert_eq!( - Vesting::::vesting_balance(&caller), + Pallet::::vesting_balance(&caller), Some(expected_balance), "Vesting balance should equal half total locked of all schedules", ); assert_eq!( - VestingStorage::::get(&caller).unwrap().len(), + Vesting::::get(&caller).unwrap().len(), (s - 1) as usize, "Schedule count should reduce by 1" ); // Since merge unlocks all schedules we can now transfer the balance. - assert_ok!( - T::Currency::transfer(&caller, &test_dest, expected_balance, ExistenceRequirement::AllowDeath) - ); + assert_ok!(T::Currency::transfer( + &caller, + &test_dest, + expected_balance, + ExistenceRequirement::AllowDeath + )); + + Ok(()) } -force_remove_vesting_schedule { - let l in 0 .. MaxLocksOf::::get() - 1; - let s in 2 .. T::MAX_VESTING_SCHEDULES; - - let source: T::AccountId = account("source", 0, SEED); - let source_lookup: ::Source = T::Lookup::unlookup(source.clone()); + #[benchmark] + fn force_remove_vesting_schedule( + l: Linear<0, { MaxLocksOf::::get() - 1 }>, + s: Linear<2, { T::MAX_VESTING_SCHEDULES }>, + ) -> Result<(), BenchmarkError> { + let source = account::("source", 0, SEED); T::Currency::make_free_balance_be(&source, BalanceOf::::max_value()); - let target: T::AccountId = account("target", 0, SEED); - let target_lookup: ::Source = T::Lookup::unlookup(target.clone()); + let target = account::("target", 0, SEED); + let target_lookup = T::Lookup::unlookup(target.clone()); T::Currency::make_free_balance_be(&target, T::Currency::minimum_balance()); // Give target existing locks. @@ -394,18 +422,22 @@ force_remove_vesting_schedule { // The last vesting schedule. let schedule_index = s - 1; - }: _(RawOrigin::Root, target_lookup, schedule_index) - verify { + + #[extrinsic_call] + _(RawOrigin::Root, target_lookup, schedule_index); + assert_eq!( - VestingStorage::::get(&target).unwrap().len(), + Vesting::::get(&target).unwrap().len(), schedule_index as usize, "Schedule count should reduce by 1" ); + + Ok(()) } - impl_benchmark_test_suite!( - Vesting, + impl_benchmark_test_suite! { + Pallet, crate::mock::ExtBuilder::default().existential_deposit(256).build(), - crate::mock::Test, - ); + crate::mock::Test + } } diff --git a/substrate/primitives/panic-handler/src/lib.rs b/substrate/primitives/panic-handler/src/lib.rs index c4a7eb8dc67c..81ccaaee828e 100644 --- a/substrate/primitives/panic-handler/src/lib.rs +++ b/substrate/primitives/panic-handler/src/lib.rs @@ -30,7 +30,7 @@ use std::{ cell::Cell, io::{self, Write}, marker::PhantomData, - panic::{self, PanicInfo}, + panic::{self, PanicHookInfo}, sync::LazyLock, thread, }; @@ -149,7 +149,7 @@ fn strip_control_codes(input: &str) -> std::borrow::Cow { } /// Function being called when a panic happens. -fn panic_hook(info: &PanicInfo, report_url: &str, version: &str) { +fn panic_hook(info: &PanicHookInfo, report_url: &str, version: &str) { let location = info.location(); let file = location.as_ref().map(|l| l.file()).unwrap_or(""); let line = location.as_ref().map(|l| l.line()).unwrap_or(0); From 80cd5fd5db629a76f2c78ec8c27e9a19fba5b580 Mon Sep 17 00:00:00 2001 From: Xavier Lau Date: Tue, 29 Oct 2024 21:29:15 +0800 Subject: [PATCH 4/5] Migrate pallet-timestamp benchmark to v2 (#6258) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of: - #6202 --------- Co-authored-by: Dónal Murray --- substrate/frame/timestamp/src/benchmarking.rs | 60 ++++++++++++------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/substrate/frame/timestamp/src/benchmarking.rs b/substrate/frame/timestamp/src/benchmarking.rs index d8c27b4967af..1ba8c4195de9 100644 --- a/substrate/frame/timestamp/src/benchmarking.rs +++ b/substrate/frame/timestamp/src/benchmarking.rs @@ -19,43 +19,63 @@ #![cfg(feature = "runtime-benchmarks")] -use super::*; -use frame_benchmarking::v1::benchmarks; -use frame_support::{ensure, traits::OnFinalize}; +use frame_benchmarking::{benchmarking::add_to_whitelist, v2::*}; +use frame_support::traits::OnFinalize; use frame_system::RawOrigin; use sp_storage::TrackedStorageKey; -use crate::{Now, Pallet as Timestamp}; +use crate::*; const MAX_TIME: u32 = 100; -benchmarks! { - set { +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn set() { let t = MAX_TIME; // Ignore write to `DidUpdate` since it transient. - let did_update_key = crate::DidUpdate::::hashed_key().to_vec(); - frame_benchmarking::benchmarking::add_to_whitelist(TrackedStorageKey { + let did_update_key = DidUpdate::::hashed_key().to_vec(); + add_to_whitelist(TrackedStorageKey { key: did_update_key, reads: 0, writes: 1, whitelisted: false, }); - }: _(RawOrigin::None, t.into()) - verify { - ensure!(Now::::get() == t.into(), "Time was not set."); + + #[extrinsic_call] + _(RawOrigin::None, t.into()); + + assert_eq!(Now::::get(), t.into(), "Time was not set."); } - on_finalize { + #[benchmark] + fn on_finalize() { let t = MAX_TIME; - Timestamp::::set(RawOrigin::None.into(), t.into())?; - ensure!(DidUpdate::::exists(), "Time was not set."); + Pallet::::set(RawOrigin::None.into(), t.into()).unwrap(); + assert!(DidUpdate::::exists(), "Time was not set."); + // Ignore read/write to `DidUpdate` since it is transient. - let did_update_key = crate::DidUpdate::::hashed_key().to_vec(); - frame_benchmarking::benchmarking::add_to_whitelist(did_update_key.into()); - }: { Timestamp::::on_finalize(t.into()); } - verify { - ensure!(!DidUpdate::::exists(), "Time was not removed."); + let did_update_key = DidUpdate::::hashed_key().to_vec(); + add_to_whitelist(TrackedStorageKey { + key: did_update_key, + reads: 0, + writes: 1, + whitelisted: false, + }); + + #[block] + { + Pallet::::on_finalize(t.into()); + } + + assert!(!DidUpdate::::exists(), "Time was not removed."); } - impl_benchmark_test_suite!(Timestamp, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite! { + Pallet, + mock::new_test_ext(), + mock::Test + } } From cc4fe1ec1eee5d2141e8d6160d89bda2a9cf34b0 Mon Sep 17 00:00:00 2001 From: georgepisaltu <52418509+georgepisaltu@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:07:09 +0200 Subject: [PATCH 5/5] [Identity] Decouple usernames from identities (#5554) This PR refactors `pallet-identity` to decouple usernames from identities. Main changes in this PR: - Separate usernames from identities in storage, allowing for correct deposit accounting - Introduce the option for username authorities to put up a deposit to issue a username - Allow authorities to remove usernames by declaring the intent to do so, then removing the username after the grace period expires - Refactor the authority storage to be keyed by suffix rather than owner account. - Introduce the concept of a system provider for a username, different from a governance allocation, allowing for usernames set by the system and not a specific authority - Implement multi-block migration to enable all of the changes described above --------- Signed-off-by: georgepisaltu Co-authored-by: Ankan <10196091+Ank4n@users.noreply.github.com> --- Cargo.lock | 4 + .../runtimes/people/people-rococo/Cargo.toml | 4 + .../runtimes/people/people-rococo/src/lib.rs | 24 + .../people/people-rococo/src/people.rs | 3 + .../people/people-rococo/src/weights/mod.rs | 1 + .../src/weights/pallet_identity.rs | 43 +- .../src/weights/pallet_migrations.rs | 172 +++ .../runtimes/people/people-westend/Cargo.toml | 4 + .../runtimes/people/people-westend/src/lib.rs | 24 + .../people/people-westend/src/people.rs | 3 + .../people/people-westend/src/weights/mod.rs | 1 + .../src/weights/pallet_identity.rs | 43 +- .../src/weights/pallet_migrations.rs | 172 +++ .../runtime/common/src/integration_tests.rs | 2 + polkadot/runtime/rococo/Cargo.toml | 4 + polkadot/runtime/rococo/src/lib.rs | 27 + polkadot/runtime/rococo/src/weights/mod.rs | 1 + .../rococo/src/weights/pallet_identity.rs | 45 +- .../rococo/src/weights/pallet_migrations.rs | 173 +++ polkadot/runtime/westend/Cargo.toml | 4 + polkadot/runtime/westend/src/lib.rs | 28 + polkadot/runtime/westend/src/weights/mod.rs | 1 + .../westend/src/weights/pallet_identity.rs | 43 +- .../westend/src/weights/pallet_migrations.rs | 173 +++ prdoc/pr_5554.prdoc | 31 + substrate/bin/node/runtime/src/impls.rs | 2 +- substrate/bin/node/runtime/src/lib.rs | 3 + substrate/frame/alliance/src/mock.rs | 6 +- substrate/frame/identity/README.md | 27 +- substrate/frame/identity/src/benchmarking.rs | 263 +++- substrate/frame/identity/src/lib.rs | 568 +++++---- substrate/frame/identity/src/migration.rs | 764 +++++++++++- substrate/frame/identity/src/tests.rs | 1066 ++++++++++++----- substrate/frame/identity/src/types.rs | 39 +- substrate/frame/identity/src/weights.rs | 98 +- 35 files changed, 3217 insertions(+), 649 deletions(-) create mode 100644 cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs create mode 100644 cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs create mode 100644 polkadot/runtime/rococo/src/weights/pallet_migrations.rs create mode 100644 polkadot/runtime/westend/src/weights/pallet_migrations.rs create mode 100644 prdoc/pr_5554.prdoc diff --git a/Cargo.lock b/Cargo.lock index 127e30d666af..d091e46e9bf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13721,6 +13721,7 @@ dependencies = [ "pallet-collator-selection", "pallet-identity", "pallet-message-queue", + "pallet-migrations", "pallet-multisig", "pallet-proxy", "pallet-session", @@ -13821,6 +13822,7 @@ dependencies = [ "pallet-collator-selection", "pallet-identity", "pallet-message-queue", + "pallet-migrations", "pallet-multisig", "pallet-proxy", "pallet-session", @@ -17958,6 +17960,7 @@ dependencies = [ "pallet-indices", "pallet-membership", "pallet-message-queue", + "pallet-migrations", "pallet-mmr", "pallet-multisig", "pallet-nis", @@ -26626,6 +26629,7 @@ dependencies = [ "pallet-indices", "pallet-membership", "pallet-message-queue", + "pallet-migrations", "pallet-mmr", "pallet-multisig", "pallet-nomination-pools", diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index 373b82639def..34458c2352fb 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -30,6 +30,7 @@ pallet-authorship = { workspace = true } pallet-balances = { workspace = true } pallet-identity = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-multisig = { workspace = true } pallet-proxy = { workspace = true } pallet-session = { workspace = true } @@ -104,6 +105,7 @@ std = [ "pallet-collator-selection/std", "pallet-identity/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-multisig/std", "pallet-proxy/std", "pallet-session/std", @@ -154,6 +156,7 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", @@ -185,6 +188,7 @@ try-runtime = [ "pallet-collator-selection/try-runtime", "pallet-identity/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-multisig/try-runtime", "pallet-proxy/try-runtime", "pallet-session/try-runtime", diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index f9499f9d1ebe..bb290c0af97d 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -193,6 +193,7 @@ impl frame_system::Config for Runtime { type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } impl pallet_timestamp::Config for Runtime { @@ -536,6 +537,25 @@ impl identity_migrator::Config for Runtime { type WeightInfo = weights::polkadot_runtime_common_identity_migrator::WeightInfo; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -571,6 +591,9 @@ construct_runtime!( // The main stage. Identity: pallet_identity = 50, + // Migrations pallet + MultiBlockMigrations: pallet_migrations = 98, + // To migrate deposits IdentityMigrator: identity_migrator = 248, } @@ -589,6 +612,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_migrations, MultiBlockMigrations] [pallet_transaction_payment, TransactionPayment] // Polkadot [polkadot_runtime_common::identity_migrator, IdentityMigrator] diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/people.rs b/cumulus/parachains/runtimes/people/people-rococo/src/people.rs index 8211447d68c8..690bb974bd17 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/people.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/people.rs @@ -36,6 +36,7 @@ parameter_types! { // 17 | Min size without `IdentityInfo` (accounted for in byte deposit) pub const BasicDeposit: Balance = deposit(1, 17); pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = deposit(1, 53); pub RelayTreasuryAccount: AccountId = parachains_common::TREASURY_PALLET_ID.into_account_truncating(); @@ -46,6 +47,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = ConstU32<100>; type IdentityInformation = IdentityInfo; @@ -57,6 +59,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 3 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs index 58480231f068..fab3c629ab3f 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs @@ -25,6 +25,7 @@ pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_identity; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_multisig; pub mod pallet_proxy; pub mod pallet_session; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs index 1e8ba87e2510..dfc522ab3b51 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_identity.rs @@ -340,7 +340,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -368,7 +368,7 @@ impl pallet_identity::WeightInfo for WeightInfo { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3542` @@ -392,18 +392,31 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() } } diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..61857ac8202a --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_migrations.rs @@ -0,0 +1,172 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_completed() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 5_868_000 picoseconds. + Weight::from_parts(6_143_000, 3599) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_skipped_historic() -> Weight { + // Proof Size summary in bytes: + // Measured: `330` + // Estimated: `3795` + // Minimum execution time: 10_283_000 picoseconds. + Weight::from_parts(10_964_000, 3795) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_advance() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 9_900_000 picoseconds. + Weight::from_parts(10_396_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_complete() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 11_411_000 picoseconds. + Weight::from_parts(11_956_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 12_398_000 picoseconds. + Weight::from_parts(12_910_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1122 + n * (271 ±0)` + // Estimated: `3834 + n * (2740 ±0)` + // Minimum execution time: 15_952_000 picoseconds. + Weight::from_parts(14_358_665, 3834) + // Standard Error: 3_358 + .saturating_add(Weight::from_parts(1_323_674, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index efb67adba49d..6840b97d8c3f 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -30,6 +30,7 @@ pallet-authorship = { workspace = true } pallet-balances = { workspace = true } pallet-identity = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-multisig = { workspace = true } pallet-proxy = { workspace = true } pallet-session = { workspace = true } @@ -104,6 +105,7 @@ std = [ "pallet-collator-selection/std", "pallet-identity/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-multisig/std", "pallet-proxy/std", "pallet-session/std", @@ -154,6 +156,7 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-identity/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", @@ -185,6 +188,7 @@ try-runtime = [ "pallet-collator-selection/try-runtime", "pallet-identity/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-multisig/try-runtime", "pallet-proxy/try-runtime", "pallet-session/try-runtime", diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 7e3cd1670fe5..7a586504badb 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -192,6 +192,7 @@ impl frame_system::Config for Runtime { type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } impl pallet_timestamp::Config for Runtime { @@ -535,6 +536,25 @@ impl identity_migrator::Config for Runtime { type WeightInfo = weights::polkadot_runtime_common_identity_migrator::WeightInfo; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -570,6 +590,9 @@ construct_runtime!( // The main stage. Identity: pallet_identity = 50, + // Migrations pallet + MultiBlockMigrations: pallet_migrations = 98, + // To migrate deposits IdentityMigrator: identity_migrator = 248, } @@ -588,6 +611,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_migrations, MultiBlockMigrations] // Polkadot [polkadot_runtime_common::identity_migrator, IdentityMigrator] // Cumulus diff --git a/cumulus/parachains/runtimes/people/people-westend/src/people.rs b/cumulus/parachains/runtimes/people/people-westend/src/people.rs index 0255fd074b11..47551f6d4bdc 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/people.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/people.rs @@ -36,6 +36,7 @@ parameter_types! { // 17 | Min size without `IdentityInfo` (accounted for in byte deposit) pub const BasicDeposit: Balance = deposit(1, 17); pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = deposit(1, 53); pub RelayTreasuryAccount: AccountId = parachains_common::TREASURY_PALLET_ID.into_account_truncating(); @@ -46,6 +47,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = ConstU32<100>; type IdentityInformation = IdentityInfo; @@ -57,6 +59,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 3 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs index 58480231f068..fab3c629ab3f 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs @@ -25,6 +25,7 @@ pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_identity; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_multisig; pub mod pallet_proxy; pub mod pallet_session; diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs index 1e8ba87e2510..dfc522ab3b51 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_identity.rs @@ -340,7 +340,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -368,7 +368,7 @@ impl pallet_identity::WeightInfo for WeightInfo { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3542` @@ -392,18 +392,31 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() } } diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..61857ac8202a --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_migrations.rs @@ -0,0 +1,172 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_completed() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 5_868_000 picoseconds. + Weight::from_parts(6_143_000, 3599) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_skipped_historic() -> Weight { + // Proof Size summary in bytes: + // Measured: `330` + // Estimated: `3795` + // Minimum execution time: 10_283_000 picoseconds. + Weight::from_parts(10_964_000, 3795) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_advance() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 9_900_000 picoseconds. + Weight::from_parts(10_396_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_complete() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 11_411_000 picoseconds. + Weight::from_parts(11_956_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 12_398_000 picoseconds. + Weight::from_parts(12_910_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1122 + n * (271 ±0)` + // Estimated: `3834 + n * (2740 ±0)` + // Minimum execution time: 15_952_000 picoseconds. + Weight::from_parts(14_358_665, 3834) + // Standard Error: 3_358 + .saturating_add(Weight::from_parts(1_323_674, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/polkadot/runtime/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index bfeed04a919f..8a76a138305e 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -288,6 +288,7 @@ impl pallet_identity::Config for Test { type Slashed = (); type BasicDeposit = ConstU32<100>; type ByteDeposit = ConstU32<10>; + type UsernameDeposit = ConstU32<10>; type SubAccountDeposit = ConstU32<100>; type MaxSubAccounts = ConstU32<2>; type IdentityInformation = IdentityInfo>; @@ -298,6 +299,7 @@ impl pallet_identity::Config for Test { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<100>; + type UsernameGracePeriod = ConstU32<10>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = (); diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index 6bcb0da3d999..3b11c977edf3 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -66,6 +66,7 @@ pallet-identity = { workspace = true } pallet-indices = { workspace = true } pallet-membership = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-mmr = { workspace = true } pallet-multisig = { workspace = true } pallet-nis = { workspace = true } @@ -157,6 +158,7 @@ std = [ "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-mmr/std", "pallet-multisig/std", "pallet-nis/std", @@ -239,6 +241,7 @@ runtime-benchmarks = [ "pallet-indices/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nis/runtime-benchmarks", @@ -297,6 +300,7 @@ try-runtime = [ "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", "pallet-nis/try-runtime", diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 44dd820f8c3c..5bcde612cf1b 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -224,6 +224,7 @@ impl frame_system::Config for Runtime { type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type MaxConsumers = frame_support::traits::ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } parameter_types! { @@ -712,6 +713,7 @@ parameter_types! { // Minimum 100 bytes/ROC deposited (1 CENT/byte) pub const BasicDeposit: Balance = 1000 * CENTS; // 258 bytes on-chain pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = 200 * CENTS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -723,6 +725,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -734,6 +737,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 30 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; @@ -1393,6 +1397,25 @@ impl validator_manager::Config for Runtime { type PrivilegedOrigin = EnsureRoot; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + impl pallet_sudo::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -1525,6 +1548,9 @@ construct_runtime! { Crowdloan: crowdloan = 73, Coretime: coretime = 74, + // Migrations pallet + MultiBlockMigrations: pallet_migrations = 98, + // Pallet for sending XCM. XcmPallet: pallet_xcm = 99, @@ -1790,6 +1816,7 @@ mod benches { [pallet_identity, Identity] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] + [pallet_migrations, MultiBlockMigrations] [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_parameters, Parameters] diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 99477baeb281..1c030c444ac5 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -27,6 +27,7 @@ pub mod pallet_conviction_voting; pub mod pallet_identity; pub mod pallet_indices; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_mmr; pub mod pallet_multisig; pub mod pallet_nis; diff --git a/polkadot/runtime/rococo/src/weights/pallet_identity.rs b/polkadot/runtime/rococo/src/weights/pallet_identity.rs index 6df16351f2c2..8b0bf7ce826a 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_identity.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_identity.rs @@ -369,7 +369,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -396,8 +396,8 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `3550` @@ -421,18 +421,31 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `11037` - // Minimum execution time: 10_829_000 picoseconds. - Weight::from_parts(11_113_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_migrations.rs b/polkadot/runtime/rococo/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..4fa07a23bb8a --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_migrations.rs @@ -0,0 +1,173 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_completed() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 5_868_000 picoseconds. + Weight::from_parts(6_143_000, 3599) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_skipped_historic() -> Weight { + // Proof Size summary in bytes: + // Measured: `330` + // Estimated: `3795` + // Minimum execution time: 10_283_000 picoseconds. + Weight::from_parts(10_964_000, 3795) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_advance() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 9_900_000 picoseconds. + Weight::from_parts(10_396_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_complete() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 11_411_000 picoseconds. + Weight::from_parts(11_956_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 12_398_000 picoseconds. + Weight::from_parts(12_910_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1122 + n * (271 ±0)` + // Estimated: `3834 + n * (2740 ±0)` + // Minimum execution time: 15_952_000 picoseconds. + Weight::from_parts(14_358_665, 3834) + // Standard Error: 3_358 + .saturating_add(Weight::from_parts(1_323_674, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/polkadot/runtime/westend/Cargo.toml b/polkadot/runtime/westend/Cargo.toml index fcb5719de895..f94301baab09 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -69,6 +69,7 @@ pallet-identity = { workspace = true } pallet-indices = { workspace = true } pallet-membership = { workspace = true } pallet-message-queue = { workspace = true } +pallet-migrations = { workspace = true } pallet-mmr = { workspace = true } pallet-multisig = { workspace = true } pallet-nomination-pools = { workspace = true } @@ -169,6 +170,7 @@ std = [ "pallet-indices/std", "pallet-membership/std", "pallet-message-queue/std", + "pallet-migrations/std", "pallet-mmr/std", "pallet-multisig/std", "pallet-nomination-pools-benchmarking?/std", @@ -259,6 +261,7 @@ runtime-benchmarks = [ "pallet-indices/runtime-benchmarks", "pallet-membership/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", + "pallet-migrations/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-nomination-pools-benchmarking/runtime-benchmarks", @@ -321,6 +324,7 @@ try-runtime = [ "pallet-indices/try-runtime", "pallet-membership/try-runtime", "pallet-message-queue/try-runtime", + "pallet-migrations/try-runtime", "pallet-mmr/try-runtime", "pallet-multisig/try-runtime", "pallet-nomination-pools/try-runtime", diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index 4941d91df57d..970ef5318994 100644 --- a/polkadot/runtime/westend/src/lib.rs +++ b/polkadot/runtime/westend/src/lib.rs @@ -224,6 +224,7 @@ impl frame_system::Config for Runtime { type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type MaxConsumers = frame_support::traits::ConstU32<16>; + type MultiBlockMigrator = MultiBlockMigrations; } parameter_types! { @@ -948,6 +949,7 @@ parameter_types! { // Minimum 100 bytes/KSM deposited (1 CENT/byte) pub const BasicDeposit: Balance = 1000 * CENTS; // 258 bytes on-chain pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = 200 * CENTS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -960,6 +962,7 @@ impl pallet_identity::Config for Runtime { type Slashed = (); type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -970,6 +973,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 30 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = weights::pallet_identity::WeightInfo; @@ -1531,6 +1535,25 @@ impl pallet_root_testing::Config for Runtime { type RuntimeEvent = RuntimeEvent; } +parameter_types! { + pub MbmServiceWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; +} + +impl pallet_migrations::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2; + // Benchmarks need mocked migrations to guarantee that they succeed. + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_migrations::mock_helpers::MockedMigrations; + type CursorMaxLen = ConstU32<65_536>; + type IdentifierMaxLen = ConstU32<256>; + type MigrationStatusHandler = (); + type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration; + type MaxServiceWeight = MbmServiceWeight; + type WeightInfo = weights::pallet_migrations::WeightInfo; +} + parameter_types! { // The deposit configuration for the singed migration. Specially if you want to allow any signed account to do the migration (see `SignedFilter`, these deposits should be high) pub const MigrationSignedDepositPerItem: Balance = 1 * CENTS; @@ -1730,6 +1753,10 @@ mod runtime { #[runtime::pallet_index(66)] pub type Coretime = coretime; + // Migrations pallet + #[runtime::pallet_index(98)] + pub type MultiBlockMigrations = pallet_migrations; + // Pallet for sending XCM. #[runtime::pallet_index(99)] pub type XcmPallet = pallet_xcm; @@ -1866,6 +1893,7 @@ mod benches { [pallet_identity, Identity] [pallet_indices, Indices] [pallet_message_queue, MessageQueue] + [pallet_migrations, MultiBlockMigrations] [pallet_mmr, Mmr] [pallet_multisig, Multisig] [pallet_nomination_pools, NominationPoolsBench::] diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index 8c12c1adb9ca..efd18b38545a 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -28,6 +28,7 @@ pub mod pallet_fast_unstake; pub mod pallet_identity; pub mod pallet_indices; pub mod pallet_message_queue; +pub mod pallet_migrations; pub mod pallet_mmr; pub mod pallet_multisig; pub mod pallet_nomination_pools; diff --git a/polkadot/runtime/westend/src/weights/pallet_identity.rs b/polkadot/runtime/westend/src/weights/pallet_identity.rs index dc7061615c95..60899dd4d173 100644 --- a/polkadot/runtime/westend/src/weights/pallet_identity.rs +++ b/polkadot/runtime/westend/src/weights/pallet_identity.rs @@ -366,7 +366,7 @@ impl pallet_identity::WeightInfo for WeightInfo { /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -394,7 +394,7 @@ impl pallet_identity::WeightInfo for WeightInfo { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `106` // Estimated: `3542` @@ -418,18 +418,31 @@ impl pallet_identity::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `126` - // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) - .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32, ) -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() } } diff --git a/polkadot/runtime/westend/src/weights/pallet_migrations.rs b/polkadot/runtime/westend/src/weights/pallet_migrations.rs new file mode 100644 index 000000000000..4fa07a23bb8a --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_migrations.rs @@ -0,0 +1,173 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot 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. + +// Polkadot 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 Polkadot. If not, see . + +// Need to rerun! + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_migrations`. +pub struct WeightInfo(PhantomData); +impl pallet_migrations::WeightInfo for WeightInfo { + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn onboard_new_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `67035` + // Minimum execution time: 7_762_000 picoseconds. + Weight::from_parts(8_100_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn progress_mbms_none() -> Weight { + // Proof Size summary in bytes: + // Measured: `142` + // Estimated: `67035` + // Minimum execution time: 2_077_000 picoseconds. + Weight::from_parts(2_138_000, 67035) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_completed() -> Weight { + // Proof Size summary in bytes: + // Measured: `134` + // Estimated: `3599` + // Minimum execution time: 5_868_000 picoseconds. + Weight::from_parts(6_143_000, 3599) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_skipped_historic() -> Weight { + // Proof Size summary in bytes: + // Measured: `330` + // Estimated: `3795` + // Minimum execution time: 10_283_000 picoseconds. + Weight::from_parts(10_964_000, 3795) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_advance() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 9_900_000 picoseconds. + Weight::from_parts(10_396_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:1) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + fn exec_migration_complete() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 11_411_000 picoseconds. + Weight::from_parts(11_956_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Storage: `MultiBlockMigrations::Historic` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn exec_migration_fail() -> Weight { + // Proof Size summary in bytes: + // Measured: `276` + // Estimated: `3741` + // Minimum execution time: 12_398_000 picoseconds. + Weight::from_parts(12_910_000, 3741) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + fn on_init_loop() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 166_000 picoseconds. + Weight::from_parts(193_000, 0) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_686_000 picoseconds. + Weight::from_parts(2_859_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:0 w:1) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + fn force_set_active_cursor() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_070_000 picoseconds. + Weight::from_parts(3_250_000, 0) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: `MultiBlockMigrations::Cursor` (r:1 w:0) + /// Proof: `MultiBlockMigrations::Cursor` (`max_values`: Some(1), `max_size`: Some(65550), added: 66045, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + /// Proof: UNKNOWN KEY `0x583359fe0e84d953a9dd84e8addb08a5` (r:1 w:0) + fn force_onboard_mbms() -> Weight { + // Proof Size summary in bytes: + // Measured: `251` + // Estimated: `67035` + // Minimum execution time: 5_901_000 picoseconds. + Weight::from_parts(6_320_000, 67035) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } + /// Storage: `MultiBlockMigrations::Historic` (r:256 w:256) + /// Proof: `MultiBlockMigrations::Historic` (`max_values`: None, `max_size`: Some(266), added: 2741, mode: `MaxEncodedLen`) + /// The range of component `n` is `[0, 256]`. + fn clear_historic(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1122 + n * (271 ±0)` + // Estimated: `3834 + n * (2740 ±0)` + // Minimum execution time: 15_952_000 picoseconds. + Weight::from_parts(14_358_665, 3834) + // Standard Error: 3_358 + .saturating_add(Weight::from_parts(1_323_674, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2740).saturating_mul(n.into())) + } +} \ No newline at end of file diff --git a/prdoc/pr_5554.prdoc b/prdoc/pr_5554.prdoc new file mode 100644 index 000000000000..3ebf00b38ed7 --- /dev/null +++ b/prdoc/pr_5554.prdoc @@ -0,0 +1,31 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Identity Decouple usernames from identities + +doc: + - audience: [Runtime Dev, Runtime User] + description: | + This PR refactors pallet-identity to decouple usernames from identities. Usernames are now + separated from identities in storage, allowing for correct deposit accounting and for + authorities to put up their own deposit to create a username and remove usernames. Various + storage maps had to be refactored and migrated to allow this to happen. The call to remove a + dangling username is now replaced by the permissioned `kill_username` call. + +crates: + - name: pallet-alliance + bump: major + - name: pallet-identity + bump: major + - name: rococo-runtime + bump: major + - name: westend-runtime + bump: major + - name: people-rococo-runtime + bump: major + - name: people-westend-runtime + bump: major + - name: polkadot-runtime-common + bump: major + - name: kitchensink-runtime + bump: major \ No newline at end of file diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs index 43e7a766e0e8..2e096342451d 100644 --- a/substrate/bin/node/runtime/src/impls.rs +++ b/substrate/bin/node/runtime/src/impls.rs @@ -65,7 +65,7 @@ impl IdentityVerifier for AllianceIdentityVerifier { fn has_good_judgement(who: &AccountId) -> bool { use pallet_identity::{IdentityOf, Judgement}; IdentityOf::::get(who) - .map(|(registration, _)| registration.judgements) + .map(|registration| registration.judgements) .map_or(false, |judgements| { judgements .iter() diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 2dbc6ab39e73..12e8dc3e5077 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1570,6 +1570,7 @@ parameter_types! { // information, already accounted for by the byte deposit pub const BasicDeposit: Balance = deposit(1, 17); pub const ByteDeposit: Balance = deposit(0, 1); + pub const UsernameDeposit: Balance = deposit(0, 32); pub const SubAccountDeposit: Balance = 2 * DOLLARS; // 53 bytes on-chain pub const MaxSubAccounts: u32 = 100; pub const MaxAdditionalFields: u32 = 100; @@ -1581,6 +1582,7 @@ impl pallet_identity::Config for Runtime { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -1592,6 +1594,7 @@ impl pallet_identity::Config for Runtime { type SigningPublicKey = ::Signer; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>; + type UsernameGracePeriod = ConstU32<{ 30 * DAYS }>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = pallet_identity::weights::SubstrateWeight; diff --git a/substrate/frame/alliance/src/mock.rs b/substrate/frame/alliance/src/mock.rs index 5442e8779020..625cabf3457f 100644 --- a/substrate/frame/alliance/src/mock.rs +++ b/substrate/frame/alliance/src/mock.rs @@ -85,11 +85,13 @@ impl pallet_collective::Config for Test { parameter_types! { pub const BasicDeposit: u64 = 100; pub const ByteDeposit: u64 = 10; + pub const UsernameDeposit: u64 = 10; pub const SubAccountDeposit: u64 = 100; pub const MaxSubAccounts: u32 = 2; pub const MaxAdditionalFields: u32 = 2; pub const MaxRegistrars: u32 = 20; pub const PendingUsernameExpiration: u64 = 100; + pub const UsernameGracePeriod: u64 = 10; } ord_parameter_types! { pub const One: u64 = 1; @@ -106,6 +108,7 @@ impl pallet_identity::Config for Test { type Currency = Balances; type BasicDeposit = BasicDeposit; type ByteDeposit = ByteDeposit; + type UsernameDeposit = UsernameDeposit; type SubAccountDeposit = SubAccountDeposit; type MaxSubAccounts = MaxSubAccounts; type IdentityInformation = IdentityInfo; @@ -117,6 +120,7 @@ impl pallet_identity::Config for Test { type SigningPublicKey = AccountU64; type UsernameAuthorityOrigin = EnsureOneOrRoot; type PendingUsernameExpiration = PendingUsernameExpiration; + type UsernameGracePeriod = UsernameGracePeriod; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = (); @@ -149,7 +153,7 @@ impl IdentityVerifier for AllianceIdentityVerifier { fn has_good_judgement(who: &AccountId) -> bool { if let Some(judgements) = - IdentityOf::::get(who).map(|(registration, _)| registration.judgements) + IdentityOf::::get(who).map(|registration| registration.judgements) { judgements .iter() diff --git a/substrate/frame/identity/README.md b/substrate/frame/identity/README.md index 94b2ae0231d7..32b75d159a9b 100644 --- a/substrate/frame/identity/README.md +++ b/substrate/frame/identity/README.md @@ -27,15 +27,24 @@ no state-bloat attack is viable. #### Usernames -The pallet provides functionality for username authorities to issue usernames. When an account -receives a username, they get a default instance of `IdentityInfo`. Usernames also serve as a -reverse lookup from username to account. +The pallet provides functionality for username authorities to issue usernames, which are independent +of the identity information functionality; an account can set: +- an identity without setting a username +- a username without setting an identity +- an identity and a username -Username authorities are given an allocation by governance to prevent state bloat. Usernames -impose no cost or deposit on the user. +The username functionality implemented in this pallet is meant to be a user friendly lookup of +accounts. There are mappings in both directions, "account -> username" and "username -> account". -Users can have multiple usernames that map to the same `AccountId`, however one `AccountId` can -only map to a single username, known as the *primary*. +To grant a username, a username authority can either: +- be given an allocation by governance of a specific amount of usernames to issue for free, + without any deposit associated with storage costs; +- put up a deposit for each username it issues (usually a subsidized, reduced deposit, relative + to other deposits in the system). + +Users can have multiple usernames that map to the same `AccountId`, however one `AccountId` can only +map to a single username, known as the _primary_. This primary username will be the result of a +lookup in the `UsernameOf` map for any given account. ### Interface @@ -50,7 +59,7 @@ only map to a single username, known as the *primary*. - `accept_username` - Accept a username issued by a username authority. - `remove_expired_approval` - Remove a username that was issued but never accepted. - `set_primary_username` - Set a given username as an account's primary. -- `remove_dangling_username` - Remove a username that maps to an account without an identity. +- `remove_username` - Remove a username after its grace period has ended. ##### For General Users with Sub-Identities - `set_subs` - Set the sub-accounts of an identity. @@ -66,12 +75,14 @@ only map to a single username, known as the *primary*. ##### For Username Authorities - `set_username_for` - Set a username for a given account. The account must approve it. +- `unbind_username` - Start the grace period for a username. ##### For Superusers - `add_registrar` - Add a new registrar to the system. - `kill_identity` - Forcibly remove the associated identity; the deposit is lost. - `add_username_authority` - Add an account with the ability to issue usernames. - `remove_username_authority` - Remove an account with the ability to issue usernames. +- `kill_username` - Forcibly remove a username. [`Call`]: ./enum.Call.html [`Config`]: ./trait.Config.html diff --git a/substrate/frame/identity/src/benchmarking.rs b/substrate/frame/identity/src/benchmarking.rs index ab04000c2281..bab581e92540 100644 --- a/substrate/frame/identity/src/benchmarking.rs +++ b/substrate/frame/identity/src/benchmarking.rs @@ -21,7 +21,7 @@ use super::*; -use crate::Pallet as Identity; +use crate::{migration::v2::LazyMigrationV1ToV2, Pallet as Identity}; use alloc::{vec, vec::Vec}; use frame_benchmarking::{account, v2::*, whitelisted_caller, BenchmarkError}; use frame_support::{ @@ -593,19 +593,19 @@ mod benchmarks { assert_ok!(Identity::::add_username_authority( origin.clone(), authority_lookup.clone(), - suffix, + suffix.clone(), allocation )); #[extrinsic_call] - _(origin as T::RuntimeOrigin, authority_lookup); + _(origin as T::RuntimeOrigin, suffix.into(), authority_lookup); assert_last_event::(Event::::AuthorityRemoved { authority }.into()); Ok(()) } #[benchmark] - fn set_username_for() -> Result<(), BenchmarkError> { + fn set_username_for(p: Linear<0, 1>) -> Result<(), BenchmarkError> { // Set up a username authority. let auth_origin = T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); @@ -613,6 +613,7 @@ mod benchmarks { let authority_lookup = T::Lookup::unlookup(authority.clone()); let suffix = bench_suffix(); let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); Identity::::add_username_authority( auth_origin, @@ -634,9 +635,20 @@ mod benchmarks { // Verify signature here to avoid surprise errors at runtime assert!(signature.verify(&bounded_username[..], &public.into())); + let use_allocation = match p { + 0 => false, + 1 => true, + _ => unreachable!(), + }; #[extrinsic_call] - _(RawOrigin::Signed(authority.clone()), who_lookup, username, Some(signature.into())); + set_username_for( + RawOrigin::Signed(authority.clone()), + who_lookup, + bounded_username.clone().into(), + Some(signature.into()), + use_allocation, + ); assert_has_event::( Event::::UsernameSet { @@ -648,6 +660,15 @@ mod benchmarks { assert_has_event::( Event::::PrimaryUsernameSet { who: who_account, username: bounded_username }.into(), ); + if use_allocation { + let suffix: Suffix = suffix.try_into().unwrap(); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); + } else { + assert_eq!( + T::Currency::free_balance(&authority), + BalanceOf::::max_value() - T::UsernameDeposit::get() + ); + } Ok(()) } @@ -656,7 +677,7 @@ mod benchmarks { let caller: T::AccountId = whitelisted_caller(); let username = bounded_username::(bench_username(), bench_suffix()); - Identity::::queue_acceptance(&caller, username.clone()); + Identity::::queue_acceptance(&caller, username.clone(), Provider::Allocation); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), username.clone()); @@ -666,10 +687,35 @@ mod benchmarks { } #[benchmark] - fn remove_expired_approval() -> Result<(), BenchmarkError> { + fn remove_expired_approval(p: Linear<0, 1>) -> Result<(), BenchmarkError> { + // Set up a username authority. + let auth_origin = + T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); + let authority: T::AccountId = account("authority", 0, SEED); + let authority_lookup = T::Lookup::unlookup(authority.clone()); + let suffix = bench_suffix(); + let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); + + Identity::::add_username_authority( + auth_origin, + authority_lookup, + suffix.clone(), + allocation, + )?; + let caller: T::AccountId = whitelisted_caller(); - let username = bounded_username::(bench_username(), bench_suffix()); - Identity::::queue_acceptance(&caller, username.clone()); + let username = bounded_username::(bench_username(), suffix.clone()); + let username_deposit = T::UsernameDeposit::get(); + let provider = match p { + 0 => { + let _ = T::Currency::reserve(&authority, username_deposit); + Provider::AuthorityDeposit(username_deposit) + }, + 1 => Provider::Allocation, + _ => unreachable!(), + }; + Identity::::queue_acceptance(&caller, username.clone(), provider); let expected_expiration = frame_system::Pallet::::block_number() + T::PendingUsernameExpiration::get(); @@ -680,6 +726,16 @@ mod benchmarks { _(RawOrigin::Signed(caller.clone()), username); assert_last_event::(Event::::PreapprovalExpired { whose: caller }.into()); + match p { + 0 => { + assert_eq!(T::Currency::free_balance(&authority), BalanceOf::::max_value()); + }, + 1 => { + let suffix: Suffix = suffix.try_into().unwrap(); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); + }, + _ => unreachable!(), + } Ok(()) } @@ -690,8 +746,8 @@ mod benchmarks { let second_username = bounded_username::(b"slowbenchmark".to_vec(), bench_suffix()); // First one will be set as primary. Second will not be. - Identity::::insert_username(&caller, first_username); - Identity::::insert_username(&caller, second_username.clone()); + Identity::::insert_username(&caller, first_username, Provider::Allocation); + Identity::::insert_username(&caller, second_username.clone(), Provider::Allocation); #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), second_username.clone()); @@ -703,24 +759,185 @@ mod benchmarks { } #[benchmark] - fn remove_dangling_username() -> Result<(), BenchmarkError> { - let caller: T::AccountId = whitelisted_caller(); - let first_username = bounded_username::(bench_username(), bench_suffix()); - let second_username = bounded_username::(b"slowbenchmark".to_vec(), bench_suffix()); + fn unbind_username() -> Result<(), BenchmarkError> { + // Set up a username authority. + let auth_origin = + T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); + let authority: T::AccountId = account("authority", 0, SEED); + let authority_lookup = T::Lookup::unlookup(authority.clone()); + let suffix = bench_suffix(); + let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); - // First one will be set as primary. Second will not be. - Identity::::insert_username(&caller, first_username); - Identity::::insert_username(&caller, second_username.clone()); + Identity::::add_username_authority( + auth_origin, + authority_lookup, + suffix.clone(), + allocation, + )?; - // User calls `clear_identity`, leaving their second username as "dangling" - Identity::::clear_identity(RawOrigin::Signed(caller.clone()).into())?; + let caller: T::AccountId = whitelisted_caller(); + let username = bounded_username::(bench_username(), suffix.clone()); + + let username_deposit = T::UsernameDeposit::get(); + Identity::::insert_username( + &caller, + username.clone(), + Provider::AuthorityDeposit(username_deposit), + ); #[extrinsic_call] - _(RawOrigin::Signed(caller.clone()), second_username.clone()); + _(RawOrigin::Signed(authority), username.clone()); - assert_last_event::( - Event::::DanglingUsernameRemoved { who: caller, username: second_username }.into(), + assert_last_event::(Event::::UsernameUnbound { username }.into()); + Ok(()) + } + + #[benchmark] + fn remove_username() -> Result<(), BenchmarkError> { + // Set up a username authority. + let authority: T::AccountId = account("authority", 0, SEED); + let suffix = bench_suffix(); + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); + let caller: T::AccountId = whitelisted_caller(); + let username = bounded_username::(bench_username(), suffix.clone()); + + let username_deposit = T::UsernameDeposit::get(); + Identity::::insert_username( + &caller, + username.clone(), + Provider::AuthorityDeposit(username_deposit), ); + let now = frame_system::Pallet::::block_number(); + let expiry = now + T::UsernameGracePeriod::get(); + UnbindingUsernames::::insert(&username, expiry); + + frame_system::Pallet::::set_block_number(expiry); + + #[extrinsic_call] + _(RawOrigin::Signed(caller), username.clone()); + + assert_last_event::(Event::::UsernameRemoved { username }.into()); + Ok(()) + } + + #[benchmark] + fn kill_username(p: Linear<0, 1>) -> Result<(), BenchmarkError> { + // Set up a username authority. + let auth_origin = + T::UsernameAuthorityOrigin::try_successful_origin().expect("can generate origin"); + let authority: T::AccountId = account("authority", 0, SEED); + let authority_lookup = T::Lookup::unlookup(authority.clone()); + let suffix = bench_suffix(); + let allocation = 10; + let _ = T::Currency::make_free_balance_be(&authority, BalanceOf::::max_value()); + + Identity::::add_username_authority( + auth_origin, + authority_lookup, + suffix.clone(), + allocation, + )?; + + let caller: T::AccountId = whitelisted_caller(); + let username = bounded_username::(bench_username(), suffix.clone()); + let username_deposit = T::UsernameDeposit::get(); + let provider = match p { + 0 => { + let _ = T::Currency::reserve(&authority, username_deposit); + Provider::AuthorityDeposit(username_deposit) + }, + 1 => Provider::Allocation, + _ => unreachable!(), + }; + Identity::::insert_username(&caller, username.clone(), provider); + UnbindingUsernames::::insert(&username, frame_system::Pallet::::block_number()); + + #[extrinsic_call] + _(RawOrigin::Root, username.clone()); + + assert_last_event::(Event::::UsernameKilled { username }.into()); + match p { + 0 => { + assert_eq!( + T::Currency::free_balance(&authority), + BalanceOf::::max_value() - username_deposit + ); + }, + 1 => { + let suffix: Suffix = suffix.try_into().unwrap(); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); + }, + _ => unreachable!(), + } + Ok(()) + } + + #[benchmark] + fn migration_v2_authority_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); + assert_eq!(AuthorityOf::::iter().count(), 0); + #[block] + { + LazyMigrationV1ToV2::::authority_step(None); + } + assert_eq!(AuthorityOf::::get(&setup.suffix).unwrap().account_id, setup.authority); + Ok(()) + } + + #[benchmark] + fn migration_v2_username_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); + assert_eq!(UsernameInfoOf::::iter().count(), 0); + #[block] + { + LazyMigrationV1ToV2::::username_step(None); + } + assert_eq!(UsernameInfoOf::::iter().next().unwrap().1.owner, setup.account); + Ok(()) + } + + #[benchmark] + fn migration_v2_identity_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); + #[block] + { + LazyMigrationV1ToV2::::identity_step(None); + } + assert!(IdentityOf::::get(&setup.account).is_some()); + Ok(()) + } + + #[benchmark] + fn migration_v2_pending_username_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_migration(); + #[block] + { + LazyMigrationV1ToV2::::pending_username_step(None); + } + assert!(PendingUsernames::::get(&setup.username).is_some()); + Ok(()) + } + + #[benchmark] + fn migration_v2_cleanup_authority_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_cleanup(); + #[block] + { + LazyMigrationV1ToV2::::cleanup_authority_step(None); + } + LazyMigrationV1ToV2::::check_authority_cleanup_validity(setup.suffix, setup.authority); + Ok(()) + } + + #[benchmark] + fn migration_v2_cleanup_username_step() -> Result<(), BenchmarkError> { + let setup = LazyMigrationV1ToV2::::setup_benchmark_env_for_cleanup(); + #[block] + { + LazyMigrationV1ToV2::::cleanup_username_step(None); + } + LazyMigrationV1ToV2::::check_username_cleanup_validity(setup.username, setup.account); Ok(()) } diff --git a/substrate/frame/identity/src/lib.rs b/substrate/frame/identity/src/lib.rs index 08e29ddffd12..11b43f958c4e 100644 --- a/substrate/frame/identity/src/lib.rs +++ b/substrate/frame/identity/src/lib.rs @@ -42,15 +42,26 @@ //! //! ### Usernames //! -//! The pallet provides functionality for username authorities to issue usernames. When an account -//! receives a username, they get a default instance of `IdentityInfo`. Usernames also serve as a -//! reverse lookup from username to account. +//! The pallet provides functionality for username authorities to issue usernames, which are +//! independent of the identity information functionality; an account can set: +//! - an identity without setting a username +//! - a username without setting an identity +//! - an identity and a username //! -//! Username authorities are given an allocation by governance to prevent state bloat. Usernames -//! impose no cost or deposit on the user. +//! The username functionality implemented in this pallet is meant to be a user friendly lookup of +//! accounts. There are mappings in both directions, "account -> username" and "username -> +//! account". +//! +//! Usernames are granted by authorities and grouped by suffix, with each suffix being administered +//! by one authority. To grant a username, a username authority can either: +//! - be given an allocation by governance of a specific amount of usernames to issue for free, +//! without any deposit associated with storage costs; +//! - put up a deposit for each username it issues (usually a subsidized, reduced deposit, relative +//! to other deposits in the system) //! //! Users can have multiple usernames that map to the same `AccountId`, however one `AccountId` can -//! only map to a single username, known as the _primary_. +//! only map to a single username, known as the _primary_. This primary username will be the result +//! of a lookup in the [UsernameOf] map for any given account. //! //! ## Interface //! @@ -65,7 +76,7 @@ //! * `accept_username` - Accept a username issued by a username authority. //! * `remove_expired_approval` - Remove a username that was issued but never accepted. //! * `set_primary_username` - Set a given username as an account's primary. -//! * `remove_dangling_username` - Remove a username that maps to an account without an identity. +//! * `remove_username` - Remove a username after its grace period has ended. //! //! #### For General Users with Sub-Identities //! * `set_subs` - Set the sub-accounts of an identity. @@ -81,12 +92,14 @@ //! //! #### For Username Authorities //! * `set_username_for` - Set a username for a given account. The account must approve it. +//! * `unbind_username` - Start the grace period for a username. //! //! #### For Superusers //! * `add_registrar` - Add a new registrar to the system. //! * `kill_identity` - Forcibly remove the associated identity; the deposit is lost. //! * `add_username_authority` - Add an account with the ability to issue usernames. //! * `remove_username_authority` - Remove an account with the ability to issue usernames. +//! * `kill_username` - Forcibly remove a username. //! //! [`Call`]: ./enum.Call.html //! [`Config`]: ./trait.Config.html @@ -103,13 +116,15 @@ pub mod weights; extern crate alloc; -use crate::types::{AuthorityPropertiesOf, Suffix, Username}; +use crate::types::{AuthorityProperties, Provider, Suffix, Username, UsernameInformation}; use alloc::{boxed::Box, vec::Vec}; use codec::Encode; use frame_support::{ ensure, pallet_prelude::{DispatchError, DispatchResult}, - traits::{BalanceStatus, Currency, Get, OnUnbalanced, ReservableCurrency, StorageVersion}, + traits::{ + BalanceStatus, Currency, Defensive, Get, OnUnbalanced, ReservableCurrency, StorageVersion, + }, BoundedVec, }; use frame_system::pallet_prelude::*; @@ -128,6 +143,7 @@ type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; +type ProviderOf = Provider>; #[frame_support::pallet] pub mod pallet { @@ -150,6 +166,11 @@ pub mod pallet { #[pallet::constant] type ByteDeposit: Get>; + /// The amount held on deposit per registered username. This value should change only in + /// runtime upgrades with proper migration of existing deposits. + #[pallet::constant] + type UsernameDeposit: Get>; + /// The amount held on deposit for a registered subaccount. This should account for the fact /// that one storage item's value will increase by the size of an account ID, and there will /// be another trie item whose value is the size of an account ID plus 32 bytes. @@ -192,6 +213,11 @@ pub mod pallet { #[pallet::constant] type PendingUsernameExpiration: Get>; + /// The number of blocks that must pass to enable the permanent deletion of a username by + /// its respective authority. + #[pallet::constant] + type UsernameGracePeriod: Get>; + /// The maximum length of a suffix. #[pallet::constant] type MaxSuffixLength: Get; @@ -204,7 +230,7 @@ pub mod pallet { type WeightInfo: WeightInfo; } - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -219,10 +245,15 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - (Registration, T::MaxRegistrars, T::IdentityInformation>, Option>), + Registration, T::MaxRegistrars, T::IdentityInformation>, OptionQuery, >; + /// Identifies the primary username of an account. + #[pallet::storage] + pub type UsernameOf = + StorageMap<_, Twox64Concat, T::AccountId, Username, OptionQuery>; + /// The super-identity of an alternative "sub" identity together with its name, within that /// context. If the account is not some other account's sub-identity, then just `None`. #[pallet::storage] @@ -265,22 +296,28 @@ pub mod pallet { /// A map of the accounts who are authorized to grant usernames. #[pallet::storage] - pub type UsernameAuthorities = - StorageMap<_, Twox64Concat, T::AccountId, AuthorityPropertiesOf, OptionQuery>; + pub type AuthorityOf = + StorageMap<_, Twox64Concat, Suffix, AuthorityProperties, OptionQuery>; - /// Reverse lookup from `username` to the `AccountId` that has registered it. The value should - /// be a key in the `IdentityOf` map, but it may not if the user has cleared their identity. + /// Reverse lookup from `username` to the `AccountId` that has registered it and the provider of + /// the username. The `owner` value should be a key in the `UsernameOf` map, but it may not if + /// the user has cleared their username or it has been removed. /// - /// Multiple usernames may map to the same `AccountId`, but `IdentityOf` will only map to one + /// Multiple usernames may map to the same `AccountId`, but `UsernameOf` will only map to one /// primary username. #[pallet::storage] - pub type AccountOfUsername = - StorageMap<_, Blake2_128Concat, Username, T::AccountId, OptionQuery>; + pub type UsernameInfoOf = StorageMap< + _, + Blake2_128Concat, + Username, + UsernameInformation>, + OptionQuery, + >; /// Usernames that an authority has granted, but that the account controller has not confirmed /// that they want it. Used primarily in cases where the `AccountId` cannot provide a signature /// because they are a pure proxy, multisig, etc. In order to confirm it, they should call - /// [`Call::accept_username`]. + /// [accept_username](`Call::accept_username`). /// /// First tuple item is the account and second is the acceptance deadline. #[pallet::storage] @@ -288,10 +325,18 @@ pub mod pallet { _, Blake2_128Concat, Username, - (T::AccountId, BlockNumberFor), + (T::AccountId, BlockNumberFor, ProviderOf), OptionQuery, >; + /// Usernames for which the authority that granted them has started the removal process by + /// unbinding them. Each unbinding username maps to its grace period expiry, which is the first + /// block in which the username could be deleted through a + /// [remove_username](`Call::remove_username`) call. + #[pallet::storage] + pub type UnbindingUsernames = + StorageMap<_, Blake2_128Concat, Username, BlockNumberFor, OptionQuery>; + #[pallet::error] pub enum Error { /// Too many subs-accounts. @@ -346,6 +391,15 @@ pub mod pallet { NoUsername, /// The username cannot be forcefully removed because it can still be accepted. NotExpired, + /// The username cannot be removed because it's still in the grace period. + TooEarly, + /// The username cannot be removed because it is not unbinding. + NotUnbinding, + /// The username cannot be unbound because it is already unbinding. + AlreadyUnbinding, + /// The action cannot be performed because of insufficient privileges (e.g. authority + /// trying to unbind a username provided by the system). + InsufficientPrivileges, } #[pallet::event] @@ -387,6 +441,12 @@ pub mod pallet { /// A dangling username (as in, a username corresponding to an account that has removed its /// identity) has been removed. DanglingUsernameRemoved { who: T::AccountId, username: Username }, + /// A username has been unbound. + UsernameUnbound { username: Username }, + /// A username has been removed. + UsernameRemoved { username: Username }, + /// A username has been killed. + UsernameKilled { username: Username }, } #[pallet::call] @@ -444,24 +504,18 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - let (mut id, username) = match IdentityOf::::get(&sender) { - Some((mut id, maybe_username)) => ( - { - // Only keep non-positive judgements. - id.judgements.retain(|j| j.1.is_sticky()); - id.info = *info; - id - }, - maybe_username, - ), - None => ( - Registration { - info: *info, - judgements: BoundedVec::default(), - deposit: Zero::zero(), - }, - None, - ), + let mut id = match IdentityOf::::get(&sender) { + Some(mut id) => { + // Only keep non-positive judgements. + id.judgements.retain(|j| j.1.is_sticky()); + id.info = *info; + id + }, + None => Registration { + info: *info, + judgements: BoundedVec::default(), + deposit: Zero::zero(), + }, }; let new_deposit = Self::calculate_identity_deposit(&id.info); @@ -470,7 +524,7 @@ pub mod pallet { id.deposit = new_deposit; let judgements = id.judgements.len(); - IdentityOf::::insert(&sender, (id, username)); + IdentityOf::::insert(&sender, id); Self::deposit_event(Event::IdentitySet { who: sender }); Ok(Some(T::WeightInfo::set_identity(judgements as u32)).into()) @@ -562,15 +616,11 @@ pub mod pallet { let sender = ensure_signed(origin)?; let (subs_deposit, sub_ids) = SubsOf::::take(&sender); - let (id, maybe_username) = - IdentityOf::::take(&sender).ok_or(Error::::NoIdentity)?; + let id = IdentityOf::::take(&sender).ok_or(Error::::NoIdentity)?; let deposit = id.total_deposit().saturating_add(subs_deposit); for sub in sub_ids.iter() { SuperOf::::remove(sub); } - if let Some(username) = maybe_username { - AccountOfUsername::::remove(username); - } let err_amount = T::Currency::unreserve(&sender, deposit); debug_assert!(err_amount.is_zero()); @@ -615,7 +665,7 @@ pub mod pallet { .and_then(Option::as_ref) .ok_or(Error::::EmptyIndex)?; ensure!(max_fee >= registrar.fee, Error::::FeeChanged); - let (mut id, username) = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; + let mut id = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; let item = (reg_index, Judgement::FeePaid(registrar.fee)); match id.judgements.binary_search_by_key(®_index, |x| x.0) { @@ -632,7 +682,7 @@ pub mod pallet { T::Currency::reserve(&sender, registrar.fee)?; let judgements = id.judgements.len(); - IdentityOf::::insert(&sender, (id, username)); + IdentityOf::::insert(&sender, id); Self::deposit_event(Event::JudgementRequested { who: sender, @@ -659,7 +709,7 @@ pub mod pallet { reg_index: RegistrarIndex, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; - let (mut id, username) = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; + let mut id = IdentityOf::::get(&sender).ok_or(Error::::NoIdentity)?; let pos = id .judgements @@ -674,7 +724,7 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&sender, fee); debug_assert!(err_amount.is_zero()); let judgements = id.judgements.len(); - IdentityOf::::insert(&sender, (id, username)); + IdentityOf::::insert(&sender, id); Self::deposit_event(Event::JudgementUnrequested { who: sender, @@ -813,8 +863,7 @@ pub mod pallet { .and_then(Option::as_ref) .filter(|r| r.account == sender) .ok_or(Error::::InvalidIndex)?; - let (mut id, username) = - IdentityOf::::get(&target).ok_or(Error::::InvalidTarget)?; + let mut id = IdentityOf::::get(&target).ok_or(Error::::InvalidTarget)?; if T::Hashing::hash_of(&id.info) != identity { return Err(Error::::JudgementForDifferentIdentity.into()) @@ -841,7 +890,7 @@ pub mod pallet { } let judgements = id.judgements.len(); - IdentityOf::::insert(&target, (id, username)); + IdentityOf::::insert(&target, id); Self::deposit_event(Event::JudgementGiven { target, registrar_index: reg_index }); Ok(Some(T::WeightInfo::provide_judgement(judgements as u32)).into()) @@ -874,15 +923,11 @@ pub mod pallet { let target = T::Lookup::lookup(target)?; // Grab their deposit (and check that they have one). let (subs_deposit, sub_ids) = SubsOf::::take(&target); - let (id, maybe_username) = - IdentityOf::::take(&target).ok_or(Error::::NoIdentity)?; + let id = IdentityOf::::take(&target).ok_or(Error::::NoIdentity)?; let deposit = id.total_deposit().saturating_add(subs_deposit); for sub in sub_ids.iter() { SuperOf::::remove(sub); } - if let Some(username) = maybe_username { - AccountOfUsername::::remove(username); - } // Slash their deposit from them. T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit).0); @@ -1010,8 +1055,9 @@ pub mod pallet { /// Add an `AccountId` with permission to grant usernames with a given `suffix` appended. /// - /// The authority can grant up to `allocation` usernames. To top up their allocation, they - /// should just issue (or request via governance) a new `add_username_authority` call. + /// The authority can grant up to `allocation` usernames. To top up the allocation or + /// change the account used to grant usernames, this call can be used with the updated + /// parameters to overwrite the existing configuration. #[pallet::call_index(15)] #[pallet::weight(T::WeightInfo::add_username_authority())] pub fn add_username_authority( @@ -1024,13 +1070,12 @@ pub mod pallet { let authority = T::Lookup::lookup(authority)?; // We don't need to check the length because it gets checked when casting into a // `BoundedVec`. - Self::validate_username(&suffix, None).map_err(|_| Error::::InvalidSuffix)?; + Self::validate_suffix(&suffix)?; let suffix = Suffix::::try_from(suffix).map_err(|_| Error::::InvalidSuffix)?; - // The authority may already exist, but we don't need to check. They might be changing - // their suffix or adding allocation, so we just want to overwrite whatever was there. - UsernameAuthorities::::insert( - &authority, - AuthorityPropertiesOf:: { suffix, allocation }, + // The call is `UsernameAuthorityOrigin` guarded, overwrite the old entry if it exists. + AuthorityOf::::insert( + &suffix, + AuthorityProperties:: { account_id: authority.clone(), allocation }, ); Self::deposit_event(Event::AuthorityAdded { authority }); Ok(()) @@ -1041,18 +1086,26 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::remove_username_authority())] pub fn remove_username_authority( origin: OriginFor, + suffix: Vec, authority: AccountIdLookupOf, ) -> DispatchResult { T::UsernameAuthorityOrigin::ensure_origin(origin)?; + let suffix = Suffix::::try_from(suffix).map_err(|_| Error::::InvalidSuffix)?; let authority = T::Lookup::lookup(authority)?; - UsernameAuthorities::::take(&authority).ok_or(Error::::NotUsernameAuthority)?; + let properties = + AuthorityOf::::take(&suffix).ok_or(Error::::NotUsernameAuthority)?; + ensure!(properties.account_id == authority, Error::::InvalidSuffix); Self::deposit_event(Event::AuthorityRemoved { authority }); Ok(()) } /// Set the username for `who`. Must be called by a username authority. /// - /// The authority must have an `allocation`. Users can either pre-sign their usernames or + /// If `use_allocation` is set, the authority must have a username allocation available to + /// spend. Otherwise, the authority will need to put up a deposit for registering the + /// username. + /// + /// Users can either pre-sign their usernames or /// accept them later. /// /// Usernames must: @@ -1060,45 +1113,42 @@ pub mod pallet { /// - When combined with the suffix of the issuing authority be _less than_ the /// `MaxUsernameLength`. #[pallet::call_index(17)] - #[pallet::weight(T::WeightInfo::set_username_for())] + #[pallet::weight(T::WeightInfo::set_username_for(if *use_allocation { 1 } else { 0 }))] pub fn set_username_for( origin: OriginFor, who: AccountIdLookupOf, username: Vec, signature: Option, + use_allocation: bool, ) -> DispatchResult { // Ensure origin is a Username Authority and has an allocation. Decrement their // allocation by one. let sender = ensure_signed(origin)?; - let suffix = UsernameAuthorities::::try_mutate( - &sender, - |maybe_authority| -> Result, DispatchError> { + let suffix = Self::validate_username(&username)?; + let provider = AuthorityOf::::try_mutate( + &suffix, + |maybe_authority| -> Result, DispatchError> { let properties = maybe_authority.as_mut().ok_or(Error::::NotUsernameAuthority)?; - ensure!(properties.allocation > 0, Error::::NoAllocation); - properties.allocation.saturating_dec(); - Ok(properties.suffix.clone()) + ensure!(properties.account_id == sender, Error::::NotUsernameAuthority); + if use_allocation { + ensure!(properties.allocation > 0, Error::::NoAllocation); + properties.allocation.saturating_dec(); + Ok(Provider::new_with_allocation()) + } else { + let deposit = T::UsernameDeposit::get(); + T::Currency::reserve(&sender, deposit)?; + Ok(Provider::new_with_deposit(deposit)) + } }, )?; - // Ensure that the username only contains allowed characters. We already know the suffix - // does. - let username_length = username.len().saturating_add(suffix.len()) as u32; - Self::validate_username(&username, Some(username_length))?; - - // Concatenate the username with suffix and cast into a BoundedVec. Should be infallible - // since we already ensured it is below the max length. - let mut full_username = - Vec::with_capacity(username.len().saturating_add(suffix.len()).saturating_add(1)); - full_username.extend(username); - full_username.extend(b"."); - full_username.extend(suffix); let bounded_username = - Username::::try_from(full_username).map_err(|_| Error::::InvalidUsername)?; + Username::::try_from(username).map_err(|_| Error::::InvalidUsername)?; // Usernames must be unique. Ensure it's not taken. ensure!( - !AccountOfUsername::::contains_key(&bounded_username), + !UsernameInfoOf::::contains_key(&bounded_username), Error::::UsernameTaken ); ensure!( @@ -1112,10 +1162,10 @@ pub mod pallet { // Account has pre-signed an authorization. Verify the signature provided and grant // the username directly. Self::validate_signature(&bounded_username[..], &s, &who)?; - Self::insert_username(&who, bounded_username); + Self::insert_username(&who, bounded_username, provider); } else { // The user must accept the username, therefore, queue it. - Self::queue_acceptance(&who, bounded_username); + Self::queue_acceptance(&who, bounded_username, provider); } Ok(()) } @@ -1129,10 +1179,10 @@ pub mod pallet { username: Username, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; - let (approved_for, _) = + let (approved_for, _, provider) = PendingUsernames::::take(&username).ok_or(Error::::NoUsername)?; ensure!(approved_for == who.clone(), Error::::InvalidUsername); - Self::insert_username(&who, username.clone()); + Self::insert_username(&who, username.clone(), provider); Self::deposit_event(Event::UsernameSet { who: who.clone(), username }); Ok(Pays::No.into()) } @@ -1141,17 +1191,37 @@ pub mod pallet { /// accepted by the user and must now be beyond its expiration. The call must include the /// full username, as in `username.suffix`. #[pallet::call_index(19)] - #[pallet::weight(T::WeightInfo::remove_expired_approval())] + #[pallet::weight(T::WeightInfo::remove_expired_approval(0))] pub fn remove_expired_approval( origin: OriginFor, username: Username, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; - if let Some((who, expiration)) = PendingUsernames::::take(&username) { + if let Some((who, expiration, provider)) = PendingUsernames::::take(&username) { let now = frame_system::Pallet::::block_number(); ensure!(now > expiration, Error::::NotExpired); + let actual_weight = match provider { + Provider::AuthorityDeposit(deposit) => { + let suffix = Self::suffix_of_username(&username) + .ok_or(Error::::InvalidUsername)?; + let authority_account = AuthorityOf::::get(&suffix) + .map(|auth_info| auth_info.account_id) + .ok_or(Error::::NotUsernameAuthority)?; + let err_amount = T::Currency::unreserve(&authority_account, deposit); + debug_assert!(err_amount.is_zero()); + T::WeightInfo::remove_expired_approval(0) + }, + Provider::Allocation => { + // We don't refund the allocation, it is lost, but we refund some weight. + T::WeightInfo::remove_expired_approval(1) + }, + Provider::System => { + // Usernames added by the system shouldn't ever be expired. + return Err(Error::::InvalidTarget.into()); + }, + }; Self::deposit_event(Event::PreapprovalExpired { whose: who.clone() }); - Ok(Pays::No.into()) + Ok((Some(actual_weight), Pays::No).into()) } else { Err(Error::::NoUsername.into()) } @@ -1164,107 +1234,139 @@ pub mod pallet { // ensure `username` maps to `origin` (i.e. has already been set by an authority). let who = ensure_signed(origin)?; let account_of_username = - AccountOfUsername::::get(&username).ok_or(Error::::NoUsername)?; + UsernameInfoOf::::get(&username).ok_or(Error::::NoUsername)?.owner; ensure!(who == account_of_username, Error::::InvalidUsername); - let (registration, _maybe_username) = - IdentityOf::::get(&who).ok_or(Error::::NoIdentity)?; - IdentityOf::::insert(&who, (registration, Some(username.clone()))); + UsernameOf::::insert(&who, username.clone()); Self::deposit_event(Event::PrimaryUsernameSet { who: who.clone(), username }); Ok(()) } - /// Remove a username that corresponds to an account with no identity. Exists when a user - /// gets a username but then calls `clear_identity`. + /// Start the process of removing a username by placing it in the unbinding usernames map. + /// Once the grace period has passed, the username can be deleted by calling + /// [remove_username](crate::Call::remove_username). #[pallet::call_index(21)] - #[pallet::weight(T::WeightInfo::remove_dangling_username())] - pub fn remove_dangling_username( + #[pallet::weight(T::WeightInfo::unbind_username())] + pub fn unbind_username(origin: OriginFor, username: Username) -> DispatchResult { + let who = ensure_signed(origin)?; + let username_info = + UsernameInfoOf::::get(&username).ok_or(Error::::NoUsername)?; + let suffix = Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; + let authority_account = AuthorityOf::::get(&suffix) + .map(|auth_info| auth_info.account_id) + .ok_or(Error::::NotUsernameAuthority)?; + ensure!(who == authority_account, Error::::NotUsernameAuthority); + match username_info.provider { + Provider::AuthorityDeposit(_) | Provider::Allocation => { + let now = frame_system::Pallet::::block_number(); + let grace_period_expiry = now.saturating_add(T::UsernameGracePeriod::get()); + UnbindingUsernames::::try_mutate(&username, |maybe_init| { + if maybe_init.is_some() { + return Err(Error::::AlreadyUnbinding); + } + *maybe_init = Some(grace_period_expiry); + Ok(()) + })?; + }, + Provider::System => return Err(Error::::InsufficientPrivileges.into()), + } + Self::deposit_event(Event::UsernameUnbound { username }); + Ok(()) + } + + /// Permanently delete a username which has been unbinding for longer than the grace period. + /// Caller is refunded the fee if the username expired and the removal was successful. + #[pallet::call_index(22)] + #[pallet::weight(T::WeightInfo::remove_username())] + pub fn remove_username( origin: OriginFor, username: Username, ) -> DispatchResultWithPostInfo { - // ensure `username` maps to `origin` (i.e. has already been set by an authority). let _ = ensure_signed(origin)?; - let who = AccountOfUsername::::take(&username).ok_or(Error::::NoUsername)?; - ensure!(!IdentityOf::::contains_key(&who), Error::::InvalidUsername); - Self::deposit_event(Event::DanglingUsernameRemoved { who: who.clone(), username }); + let grace_period_expiry = + UnbindingUsernames::::take(&username).ok_or(Error::::NotUnbinding)?; + let now = frame_system::Pallet::::block_number(); + ensure!(now >= grace_period_expiry, Error::::TooEarly); + let username_info = UsernameInfoOf::::take(&username) + .defensive_proof("an unbinding username must exist") + .ok_or(Error::::NoUsername)?; + // If this is the primary username, remove the entry from the account -> username map. + UsernameOf::::mutate(&username_info.owner, |maybe_primary| { + if maybe_primary.as_ref().map_or(false, |primary| *primary == username) { + *maybe_primary = None; + } + }); + match username_info.provider { + Provider::AuthorityDeposit(username_deposit) => { + let suffix = Self::suffix_of_username(&username) + .defensive_proof("registered username must be valid") + .ok_or(Error::::InvalidUsername)?; + if let Some(authority_account) = + AuthorityOf::::get(&suffix).map(|auth_info| auth_info.account_id) + { + let err_amount = + T::Currency::unreserve(&authority_account, username_deposit); + debug_assert!(err_amount.is_zero()); + } + }, + Provider::Allocation => { + // We don't refund the allocation, it is lost. + }, + Provider::System => return Err(Error::::InsufficientPrivileges.into()), + } + Self::deposit_event(Event::UsernameRemoved { username }); Ok(Pays::No.into()) } + + /// Call with [ForceOrigin](crate::Config::ForceOrigin) privileges which deletes a username + /// and slashes any deposit associated with it. + #[pallet::call_index(23)] + #[pallet::weight(T::WeightInfo::kill_username(0))] + pub fn kill_username( + origin: OriginFor, + username: Username, + ) -> DispatchResultWithPostInfo { + T::ForceOrigin::ensure_origin(origin)?; + let username_info = + UsernameInfoOf::::take(&username).ok_or(Error::::NoUsername)?; + // If this is the primary username, remove the entry from the account -> username map. + UsernameOf::::mutate(&username_info.owner, |maybe_primary| { + if match maybe_primary { + Some(primary) if *primary == username => true, + _ => false, + } { + *maybe_primary = None; + } + }); + let _ = UnbindingUsernames::::take(&username); + let actual_weight = match username_info.provider { + Provider::AuthorityDeposit(username_deposit) => { + let suffix = + Self::suffix_of_username(&username).ok_or(Error::::InvalidUsername)?; + if let Some(authority_account) = + AuthorityOf::::get(&suffix).map(|auth_info| auth_info.account_id) + { + T::Slashed::on_unbalanced( + T::Currency::slash_reserved(&authority_account, username_deposit).0, + ); + } + T::WeightInfo::kill_username(0) + }, + Provider::Allocation => { + // We don't refund the allocation, it is lost, but we do refund some weight. + T::WeightInfo::kill_username(1) + }, + Provider::System => { + // Force origin can remove system usernames. + T::WeightInfo::kill_username(1) + }, + }; + Self::deposit_event(Event::UsernameKilled { username }); + Ok((Some(actual_weight), Pays::No).into()) + } } } impl Pallet { - /// Information that is pertinent to identify the entity behind an account. First item is the - /// registration, second is the account's primary username. - /// - /// TWOX-NOTE: OK ― `AccountId` is a secure hash. - pub fn identity( - who: T::AccountId, - ) -> Option<( - Registration, T::MaxRegistrars, T::IdentityInformation>, - Option>, - )> { - IdentityOf::::get(who) - } - - /// The super-identity of an alternative "sub" identity together with its name, within that - /// context. If the account is not some other account's sub-identity, then just `None`. - pub fn super_of(who: T::AccountId) -> Option<(T::AccountId, Data)> { - SuperOf::::get(who) - } - - /// Alternative "sub" identities of this account. - /// - /// The first item is the deposit, the second is a vector of the accounts. - /// - /// TWOX-NOTE: OK ― `AccountId` is a secure hash. - pub fn subs_of( - who: T::AccountId, - ) -> (BalanceOf, BoundedVec) { - SubsOf::::get(who) - } - - /// The set of registrars. Not expected to get very big as can only be added through a - /// special origin (likely a council motion). - /// - /// The index into this can be cast to `RegistrarIndex` to get a valid value. - pub fn registrars() -> BoundedVec< - Option< - RegistrarInfo< - BalanceOf, - T::AccountId, - ::FieldsIdentifier, - >, - >, - T::MaxRegistrars, - > { - Registrars::::get() - } - - /// A map of the accounts who are authorized to grant usernames. - pub fn authority(who: T::AccountId) -> Option> { - UsernameAuthorities::::get(who) - } - - /// Reverse lookup from `username` to the `AccountId` that has registered it. The value should - /// be a key in the `IdentityOf` map, but it may not if the user has cleared their identity. - /// - /// Multiple usernames may map to the same `AccountId`, but `IdentityOf` will only map to one - /// primary username. - pub fn username(username: Username) -> Option { - AccountOfUsername::::get(username) - } - - /// Usernames that an authority has granted, but that the account controller has not confirmed - /// that they want it. Used primarily in cases where the `AccountId` cannot provide a signature - /// because they are a pure proxy, multisig, etc. In order to confirm it, they should call - /// [`Call::accept_username`]. - /// - /// First tuple item is the account and second is the acceptance deadline. - pub fn preapproved_usernames( - username: Username, - ) -> Option<(T::AccountId, BlockNumberFor)> { - PendingUsernames::::get(username) - } - /// Get the subs of an account. pub fn subs(who: &T::AccountId) -> Vec<(T::AccountId, Data)> { SubsOf::::get(who) @@ -1300,7 +1402,7 @@ impl Pallet { fields: ::FieldsIdentifier, ) -> bool { IdentityOf::::get(who) - .map_or(false, |(registration, _username)| (registration.info.has_identity(fields))) + .map_or(false, |registration| (registration.info.has_identity(fields))) } /// Calculate the deposit required for an identity. @@ -1312,23 +1414,56 @@ impl Pallet { /// Validate that a username conforms to allowed characters/format. /// - /// The function will validate the characters in `username` and that `length` (if `Some`) - /// conforms to the limit. It is not expected to pass a fully formatted username here (i.e. one - /// with any protocol-added characters included, such as a `.`). The suffix is also separately - /// validated by this function to ensure the full username conforms. - fn validate_username(username: &Vec, length: Option) -> DispatchResult { - // Verify input length before allocating a Vec with the user's input. `<` instead of `<=` - // because it needs one element for the point (`username` + `.` + `suffix`). - if let Some(l) = length { - ensure!(l < T::MaxUsernameLength::get(), Error::::InvalidUsername); - } + /// The function will validate the characters in `username`. It is expected to pass a fully + /// formatted username here (i.e. "username.suffix"). The suffix is also separately validated + /// and returned by this function. + fn validate_username(username: &Vec) -> Result, DispatchError> { + // Verify input length before allocating a Vec with the user's input. + ensure!( + username.len() <= T::MaxUsernameLength::get() as usize, + Error::::InvalidUsername + ); + // Usernames cannot be empty. ensure!(!username.is_empty(), Error::::InvalidUsername); + let separator_idx = + username.iter().rposition(|c| *c == b'.').ok_or(Error::::InvalidUsername)?; + ensure!(separator_idx > 0, Error::::InvalidUsername); + let suffix_start = separator_idx.checked_add(1).ok_or(Error::::InvalidUsername)?; + ensure!(suffix_start < username.len(), Error::::InvalidUsername); // Username must be lowercase and alphanumeric. ensure!( - username.iter().all(|byte| byte.is_ascii_digit() || byte.is_ascii_lowercase()), + username + .iter() + .take(separator_idx) + .all(|byte| byte.is_ascii_digit() || byte.is_ascii_lowercase()), Error::::InvalidUsername ); + let suffix: Suffix = (&username[suffix_start..]) + .to_vec() + .try_into() + .map_err(|_| Error::::InvalidUsername)?; + Ok(suffix) + } + + /// Return the suffix of a username, if it is valid. + fn suffix_of_username(username: &Username) -> Option> { + let separator_idx = username.iter().rposition(|c| *c == b'.')?; + let suffix_start = separator_idx.checked_add(1)?; + if suffix_start >= username.len() { + return None; + } + (&username[suffix_start..]).to_vec().try_into().ok() + } + + /// Validate that a suffix conforms to allowed characters/format. + fn validate_suffix(suffix: &Vec) -> Result<(), DispatchError> { + ensure!(suffix.len() <= T::MaxSuffixLength::get() as usize, Error::::InvalidSuffix); + ensure!(!suffix.is_empty(), Error::::InvalidSuffix); + ensure!( + suffix.iter().all(|byte| byte.is_ascii_digit() || byte.is_ascii_lowercase()), + Error::::InvalidSuffix + ); Ok(()) } @@ -1357,34 +1492,22 @@ impl Pallet { } /// A username has met all conditions. Insert the relevant storage items. - pub fn insert_username(who: &T::AccountId, username: Username) { + pub fn insert_username(who: &T::AccountId, username: Username, provider: ProviderOf) { // Check if they already have a primary. If so, leave it. If not, set it. // Likewise, check if they have an identity. If not, give them a minimal one. - let (reg, primary_username, new_is_primary) = match IdentityOf::::get(&who) { + let (primary_username, new_is_primary) = match UsernameOf::::get(&who) { // User has an existing Identity and a primary username. Leave it. - Some((reg, Some(primary))) => (reg, primary, false), + Some(primary) => (primary, false), // User has an Identity but no primary. Set the new one as primary. - Some((reg, None)) => (reg, username.clone(), true), - // User does not have an existing Identity. Give them a fresh default one and set - // their username as primary. - None => ( - Registration { - info: Default::default(), - judgements: Default::default(), - deposit: Zero::zero(), - }, - username.clone(), - true, - ), + None => (username.clone(), true), }; - // Enter in identity map. Note: In the case that the user did not have a pre-existing - // Identity, we have given them the storage item for free. If they ever call - // `set_identity` with identity info, then they will need to place the normal identity - // deposit. - IdentityOf::::insert(&who, (reg, Some(primary_username))); + if new_is_primary { + UsernameOf::::insert(&who, primary_username); + } + let username_info = UsernameInformation { owner: who.clone(), provider }; // Enter in username map. - AccountOfUsername::::insert(username.clone(), &who); + UsernameInfoOf::::insert(username.clone(), username_info); Self::deposit_event(Event::UsernameSet { who: who.clone(), username: username.clone() }); if new_is_primary { Self::deposit_event(Event::PrimaryUsernameSet { who: who.clone(), username }); @@ -1393,10 +1516,10 @@ impl Pallet { /// A username was granted by an authority, but must be accepted by `who`. Put the username /// into a queue for acceptance. - pub fn queue_acceptance(who: &T::AccountId, username: Username) { + pub fn queue_acceptance(who: &T::AccountId, username: Username, provider: ProviderOf) { let now = frame_system::Pallet::::block_number(); let expiration = now.saturating_add(T::PendingUsernameExpiration::get()); - PendingUsernames::::insert(&username, (who.clone(), expiration)); + PendingUsernames::::insert(&username, (who.clone(), expiration, provider)); Self::deposit_event(Event::UsernameQueued { who: who.clone(), username, expiration }); } @@ -1415,7 +1538,7 @@ impl Pallet { pub fn reap_identity(who: &T::AccountId) -> Result<(u32, u32, u32), DispatchError> { // `take` any storage items keyed by `target` // identity - let (id, _maybe_username) = IdentityOf::::take(&who).ok_or(Error::::NoIdentity)?; + let id = IdentityOf::::take(&who).ok_or(Error::::NoIdentity)?; let registrars = id.judgements.len() as u32; let encoded_byte_size = id.info.encoded_size() as u32; @@ -1449,7 +1572,7 @@ impl Pallet { let new_id_deposit = IdentityOf::::try_mutate( &target, |identity_of| -> Result, DispatchError> { - let (reg, _) = identity_of.as_mut().ok_or(Error::::NoIdentity)?; + let reg = identity_of.as_mut().ok_or(Error::::NoIdentity)?; // Calculate what deposit should be let encoded_byte_size = reg.info.encoded_size() as u32; let byte_deposit = @@ -1491,14 +1614,11 @@ impl Pallet { ) -> DispatchResult { IdentityOf::::insert( &who, - ( - Registration { - judgements: Default::default(), - deposit: Zero::zero(), - info: info.clone(), - }, - None::>, - ), + Registration { + judgements: Default::default(), + deposit: Zero::zero(), + info: info.clone(), + }, ); Ok(()) } diff --git a/substrate/frame/identity/src/migration.rs b/substrate/frame/identity/src/migration.rs index 8725bfd39df1..3a78692cfcd7 100644 --- a/substrate/frame/identity/src/migration.rs +++ b/substrate/frame/identity/src/migration.rs @@ -15,16 +15,23 @@ //! Storage migrations for the Identity pallet. +extern crate alloc; + use super::*; use frame_support::{ - migrations::VersionedMigration, pallet_prelude::*, traits::UncheckedOnRuntimeUpgrade, + migrations::VersionedMigration, pallet_prelude::*, storage_alias, + traits::UncheckedOnRuntimeUpgrade, IterableStorageMap, }; +#[cfg(feature = "try-runtime")] +use alloc::collections::BTreeMap; #[cfg(feature = "try-runtime")] use codec::{Decode, Encode}; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; +pub const PALLET_MIGRATIONS_ID: &[u8; 15] = b"pallet-identity"; + pub mod versioned { use super::*; @@ -37,31 +44,78 @@ pub mod versioned { >; } -pub mod v1 { +/// The old identity types in v0. +mod types_v0 { use super::*; - /// The log target. - const TARGET: &'static str = "runtime::identity::migration::v1"; + #[storage_alias] + pub type IdentityOf = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + OptionQuery, + >; +} - /// The old identity type, useful in pre-upgrade. - mod v0 { - use super::*; - use frame_support::storage_alias; +/// The old identity types in v1. +mod types_v1 { + use super::*; - #[storage_alias] - pub type IdentityOf = StorageMap< - Pallet, - Twox64Concat, - ::AccountId, + #[storage_alias] + pub type IdentityOf = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + ( Registration< BalanceOf, ::MaxRegistrars, ::IdentityInformation, >, - OptionQuery, - >; - } + Option>, + ), + OptionQuery, + >; + + #[storage_alias] + pub type UsernameAuthorities = StorageMap< + Pallet, + Twox64Concat, + ::AccountId, + AuthorityProperties>, + OptionQuery, + >; + + #[storage_alias] + pub type AccountOfUsername = StorageMap< + Pallet, + Blake2_128Concat, + Username, + ::AccountId, + OptionQuery, + >; + + #[cfg(feature = "try-runtime")] + #[storage_alias] + pub type PendingUsernames = StorageMap< + Pallet, + Blake2_128Concat, + Username, + (::AccountId, BlockNumberFor), + OptionQuery, + >; +} +pub mod v1 { + use super::*; + + /// The log target. + const TARGET: &'static str = "runtime::identity::migration::v1"; /// Migration to add usernames to Identity info. /// /// `T` is the runtime and `KL` is the key limit to migrate. This is just a safety guard to @@ -71,7 +125,7 @@ pub mod v1 { impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateV0ToV1 { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { - let identities = v0::IdentityOf::::iter().count(); + let identities = types_v0::IdentityOf::::iter().count(); log::info!( target: TARGET, "pre-upgrade state contains '{}' identities.", @@ -91,8 +145,8 @@ pub mod v1 { let mut translated: u64 = 0; let mut interrupted = false; - for (account, registration) in v0::IdentityOf::::iter() { - IdentityOf::::insert(account, (registration, None::>)); + for (account, registration) in types_v0::IdentityOf::::iter() { + types_v1::IdentityOf::::insert(account, (registration, None::>)); translated.saturating_inc(); if translated >= KL { log::warn!( @@ -116,7 +170,7 @@ pub mod v1 { fn post_upgrade(state: Vec) -> Result<(), TryRuntimeError> { let identities_to_migrate: u64 = Decode::decode(&mut &state[..]) .expect("failed to decode the state from pre-upgrade."); - let identities = IdentityOf::::iter().count() as u64; + let identities = types_v1::IdentityOf::::iter().count() as u64; log::info!("post-upgrade expects '{}' identities to have been migrated.", identities); ensure!(identities_to_migrate == identities, "must migrate all identities."); log::info!(target: TARGET, "migrated all identities."); @@ -124,3 +178,673 @@ pub mod v1 { } } } + +pub mod v2 { + use super::*; + use frame_support::{ + migrations::{MigrationId, SteppedMigration, SteppedMigrationError}, + weights::WeightMeter, + }; + + type HashedKey = BoundedVec>; + // The resulting state of the step and the actual weight consumed. + type StepResultOf = + MigrationState<::AccountId, Username, Suffix>; + + #[cfg(feature = "runtime-benchmarks")] + pub(crate) type BenchmarkingSetupOf = + BenchmarkingSetup, ::AccountId, Username>; + + /// Progressive states of a migration. The migration starts with the first variant and ends with + /// the last. + #[derive(Decode, Encode, MaxEncodedLen, Eq, PartialEq)] + pub enum MigrationState { + Authority(A), + FinishedAuthorities, + Identity(HashedKey), + FinishedIdentities, + Username(U), + FinishedUsernames, + PendingUsername(HashedKey), + FinishedPendingUsernames, + CleanupAuthorities(S), + FinishedCleanupAuthorities, + CleanupUsernames(U), + Finished, + } + + #[cfg(feature = "try-runtime")] + #[derive(Encode, Decode)] + struct TryRuntimeState { + authorities: BTreeMap, (T::AccountId, u32)>, + identities: BTreeMap< + T::AccountId, + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + >, + primary_usernames: BTreeMap>, + usernames: BTreeMap, T::AccountId>, + pending_usernames: BTreeMap, (T::AccountId, BlockNumberFor)>, + } + + pub struct LazyMigrationV1ToV2(PhantomData); + impl SteppedMigration for LazyMigrationV1ToV2 { + type Cursor = MigrationState, Suffix>; + type Identifier = MigrationId<15>; + + fn id() -> Self::Identifier { + MigrationId { pallet_id: *PALLET_MIGRATIONS_ID, version_from: 1, version_to: 2 } + } + + fn step( + mut cursor: Option, + meter: &mut WeightMeter, + ) -> Result, SteppedMigrationError> { + if Pallet::::on_chain_storage_version() != Self::id().version_from as u16 { + return Ok(None); + } + + // Check that we have enough weight for at least the next step. If we don't, then the + // migration cannot be complete. + let required = match &cursor { + Some(state) => Self::required_weight(&state), + // Worst case weight for `authority_step`. + None => T::WeightInfo::migration_v2_authority_step(), + }; + if meter.remaining().any_lt(required) { + return Err(SteppedMigrationError::InsufficientWeight { required }); + } + + loop { + // Check that we would have enough weight to perform this step in the worst case + // scenario. + let required_weight = match &cursor { + Some(state) => Self::required_weight(&state), + // Worst case weight for `authority_step`. + None => T::WeightInfo::migration_v2_authority_step(), + }; + if !meter.can_consume(required_weight) { + break; + } + + let next = match &cursor { + // At first, migrate any authorities. + None => Self::authority_step(None), + // Migrate any remaining authorities. + Some(MigrationState::Authority(maybe_last_authority)) => + Self::authority_step(Some(maybe_last_authority)), + // After the last authority was migrated, start migrating usernames from + // the former `AccountOfUsername` into `UsernameInfoOf`. + Some(MigrationState::FinishedAuthorities) => Self::username_step(None), + // Keep migrating usernames. + Some(MigrationState::Username(maybe_last_username)) => + Self::username_step(Some(maybe_last_username)), + // After the last username was migrated, start migrating all identities in + // `IdentityOf`, which currently hold the primary username of the owner account + // as well as any associated identity. Accounts which set a username but not an + // identity also have a zero deposit identity stored, which will be removed. + Some(MigrationState::FinishedUsernames) => Self::identity_step(None), + // Keep migrating identities. + Some(MigrationState::Identity(last_key)) => + Self::identity_step(Some(last_key.clone())), + // After the last identity was migrated, start migrating usernames pending + // approval from `PendingUsernames`. + Some(MigrationState::FinishedIdentities) => Self::pending_username_step(None), + // Keep migrating pending usernames. + Some(MigrationState::PendingUsername(last_key)) => + Self::pending_username_step(Some(last_key.clone())), + // After the last pending username was migrated, start clearing the storage + // previously associated with authorities in `UsernameAuthority`. + Some(MigrationState::FinishedPendingUsernames) => + Self::cleanup_authority_step(None), + // Keep clearing the obsolete authority storage. + Some(MigrationState::CleanupAuthorities(maybe_last_username)) => + Self::cleanup_authority_step(Some(maybe_last_username)), + // After the last obsolete authority was cleared from storage, start clearing + // the storage previously associated with usernames in `AccountOfUsername`. + Some(MigrationState::FinishedCleanupAuthorities) => + Self::cleanup_username_step(None), + // Keep clearing the obsolete username storage. + Some(MigrationState::CleanupUsernames(maybe_last_username)) => + Self::cleanup_username_step(Some(maybe_last_username)), + // After the last obsolete username was cleared from storage, the migration is + // done. + Some(MigrationState::Finished) => { + StorageVersion::new(Self::id().version_to as u16).put::>(); + return Ok(None) + }, + }; + + cursor = Some(next); + meter.consume(required_weight); + } + + Ok(cursor) + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + let authorities: BTreeMap, (T::AccountId, u32)> = + types_v1::UsernameAuthorities::::iter() + .map(|(account, authority_properties)| { + ( + authority_properties.account_id, + (account, authority_properties.allocation), + ) + }) + .collect(); + let mut primary_usernames: BTreeMap<_, _> = Default::default(); + let identities = types_v1::IdentityOf::::iter() + .map(|(account, (identity, maybe_username))| { + if let Some(username) = maybe_username { + primary_usernames.insert(account.clone(), username); + } + (account, identity) + }) + .collect::>(); + let usernames = types_v1::AccountOfUsername::::iter().collect::>(); + let pending_usernames: BTreeMap, (T::AccountId, BlockNumberFor)> = + types_v1::PendingUsernames::::iter().collect(); + let state: TryRuntimeState = TryRuntimeState { + authorities, + identities, + primary_usernames, + usernames, + pending_usernames, + }; + + Ok(state.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + let mut prev_state: TryRuntimeState = TryRuntimeState::::decode(&mut &state[..]) + .expect("Failed to decode the previous storage state"); + + for (suffix, authority_properties) in AuthorityOf::::iter() { + let (prev_account, prev_allocation) = prev_state + .authorities + .remove(&suffix) + .expect("should have authority in previous state"); + assert_eq!(prev_account, authority_properties.account_id); + assert_eq!(prev_allocation, authority_properties.allocation); + } + assert!(prev_state.authorities.is_empty()); + + for (account, identity) in IdentityOf::::iter() { + assert!(identity.deposit > 0u32.into()); + let prev_identity = prev_state + .identities + .remove(&account) + .expect("should have identity in previous state"); + assert_eq!(identity, prev_identity); + } + + for (account, free_identity) in prev_state.identities.iter() { + assert_eq!(free_identity.deposit, 0u32.into()); + assert!(UsernameOf::::contains_key(&account)); + } + prev_state.identities.clear(); + + for (account, primary_username) in UsernameOf::::iter() { + let prev_primary_username = prev_state + .primary_usernames + .remove(&account) + .expect("should have primary username in previous state"); + assert_eq!(prev_primary_username, primary_username); + } + + for (username, username_info) in UsernameInfoOf::::iter() { + let prev_account = prev_state + .usernames + .remove(&username) + .expect("should have username info in previous state"); + assert_eq!(prev_account, username_info.owner); + assert_eq!(username_info.provider, Provider::Allocation); + } + assert!(prev_state.usernames.is_empty()); + + for (username, (account, expiration, provider)) in PendingUsernames::::iter() { + let (prev_account, prev_expiration) = prev_state + .pending_usernames + .remove(&username) + .expect("should have pending username in previous state"); + assert_eq!(prev_account, account); + assert_eq!(prev_expiration, expiration); + assert_eq!(provider, Provider::Allocation); + } + assert!(prev_state.pending_usernames.is_empty()); + + Ok(()) + } + } + + impl LazyMigrationV1ToV2 { + pub(crate) fn required_weight( + step: &MigrationState, Suffix>, + ) -> Weight { + match step { + MigrationState::Authority(_) => T::WeightInfo::migration_v2_authority_step(), + MigrationState::FinishedAuthorities | MigrationState::Username(_) => + T::WeightInfo::migration_v2_username_step(), + MigrationState::FinishedUsernames | MigrationState::Identity(_) => + T::WeightInfo::migration_v2_identity_step(), + MigrationState::FinishedIdentities | MigrationState::PendingUsername(_) => + T::WeightInfo::migration_v2_pending_username_step(), + MigrationState::FinishedPendingUsernames | + MigrationState::CleanupAuthorities(_) => T::WeightInfo::migration_v2_cleanup_authority_step(), + MigrationState::FinishedCleanupAuthorities | + MigrationState::CleanupUsernames(_) => T::WeightInfo::migration_v2_cleanup_username_step(), + MigrationState::Finished => Weight::zero(), + } + } + + // Migrate one entry from `UsernameAuthorities` to `AuthorityOf`. + pub(crate) fn authority_step(maybe_last_key: Option<&T::AccountId>) -> StepResultOf { + let mut iter = if let Some(last_key) = maybe_last_key { + types_v1::UsernameAuthorities::::iter_from( + types_v1::UsernameAuthorities::::hashed_key_for(last_key), + ) + } else { + types_v1::UsernameAuthorities::::iter() + }; + if let Some((authority_account, properties)) = iter.next() { + let suffix = properties.account_id; + let allocation = properties.allocation; + let new_properties = + AuthorityProperties { account_id: authority_account.clone(), allocation }; + AuthorityOf::::insert(&suffix, new_properties); + MigrationState::Authority(authority_account) + } else { + MigrationState::FinishedAuthorities + } + } + + // Migrate one entry from `AccountOfUsername` to `UsernameInfoOf`. + pub(crate) fn username_step(maybe_last_key: Option<&Username>) -> StepResultOf { + let mut iter = if let Some(last_key) = maybe_last_key { + types_v1::AccountOfUsername::::iter_from( + types_v1::AccountOfUsername::::hashed_key_for(last_key), + ) + } else { + types_v1::AccountOfUsername::::iter() + }; + + if let Some((username, owner_account)) = iter.next() { + let username_info = UsernameInformation { + owner: owner_account, + provider: Provider::new_with_allocation(), + }; + UsernameInfoOf::::insert(&username, username_info); + + MigrationState::Username(username) + } else { + MigrationState::FinishedUsernames + } + } + + // Migrate one entry from `IdentityOf` to `UsernameOf`, if it has a username associated with + // it. Remove the entry if there was no real identity associated with the account. + pub(crate) fn identity_step(maybe_last_key: Option) -> StepResultOf { + if let Some(mut last_key) = + IdentityOf::::translate_next::< + ( + Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + >, + Option>, + ), + _, + >(maybe_last_key.map(|b| b.to_vec()), |account, (identity, maybe_username)| { + if let Some(primary_username) = maybe_username { + UsernameOf::::insert(&account, primary_username); + } + if identity.deposit > BalanceOf::::zero() { + Some(identity) + } else { + None + } + }) { + last_key.truncate(HashedKey::bound()); + MigrationState::Identity( + HashedKey::try_from(last_key) + .expect("truncated to bound so the conversion must succeed; qed"), + ) + } else { + MigrationState::FinishedIdentities + } + } + + // Migrate one entry from `PendingUsernames` to contain the new `Provider` field. + pub(crate) fn pending_username_step(maybe_last_key: Option) -> StepResultOf { + if let Some(mut last_key) = + PendingUsernames::::translate_next::<(T::AccountId, BlockNumberFor), _>( + maybe_last_key.map(|b| b.to_vec()), + |_, (owner_account, since)| { + Some((owner_account, since, Provider::new_with_allocation())) + }, + ) { + last_key.truncate(HashedKey::bound()); + MigrationState::PendingUsername( + HashedKey::try_from(last_key) + .expect("truncated to bound so the conversion must succeed; qed"), + ) + } else { + MigrationState::FinishedPendingUsernames + } + } + + // Remove one entry from `UsernameAuthorities`. + pub(crate) fn cleanup_authority_step( + maybe_last_key: Option<&Suffix>, + ) -> StepResultOf { + let mut iter = if let Some(last_key) = maybe_last_key { + AuthorityOf::::iter_from(AuthorityOf::::hashed_key_for(last_key)) + } else { + AuthorityOf::::iter() + }; + + if let Some((suffix, properties)) = iter.next() { + let _ = types_v1::UsernameAuthorities::::take(&properties.account_id); + MigrationState::CleanupAuthorities(suffix) + } else { + MigrationState::FinishedCleanupAuthorities + } + } + + // Remove one entry from `AccountOfUsername`. + pub(crate) fn cleanup_username_step( + maybe_last_key: Option<&Username>, + ) -> StepResultOf { + let mut iter = if let Some(last_key) = maybe_last_key { + UsernameInfoOf::::iter_from(UsernameInfoOf::::hashed_key_for(last_key)) + } else { + UsernameInfoOf::::iter() + }; + + if let Some((username, _)) = iter.next() { + let _ = types_v1::AccountOfUsername::::take(&username); + MigrationState::CleanupUsernames(username) + } else { + MigrationState::Finished + } + } + } + + #[cfg(feature = "runtime-benchmarks")] + pub(crate) struct BenchmarkingSetup { + pub(crate) suffix: S, + pub(crate) authority: A, + pub(crate) account: A, + pub(crate) username: U, + } + + #[cfg(feature = "runtime-benchmarks")] + impl LazyMigrationV1ToV2 { + pub(crate) fn setup_benchmark_env_for_migration() -> BenchmarkingSetupOf { + use frame_support::Hashable; + let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); + let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0); + let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0); + + let prop: AuthorityProperties> = + AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; + types_v1::UsernameAuthorities::::insert(&authority, &prop); + + let username: Username = b"account.bench".to_vec().try_into().unwrap(); + let info = T::IdentityInformation::create_identity_info(); + let registration: Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > = Registration { judgements: Default::default(), deposit: 10u32.into(), info }; + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), + (®istration, Some(username.clone())), + ); + types_v1::AccountOfUsername::::insert(&username, &account_id); + let since: BlockNumberFor = 0u32.into(); + frame_support::migration::put_storage_value( + b"Identity", + b"PendingUsernames", + &username.blake2_128_concat(), + (&account_id, since), + ); + BenchmarkingSetup { suffix, authority, account: account_id, username } + } + + pub(crate) fn setup_benchmark_env_for_cleanup() -> BenchmarkingSetupOf { + let suffix: Suffix = b"bench".to_vec().try_into().unwrap(); + let authority: T::AccountId = frame_benchmarking::account("authority", 0, 0); + let account_id: T::AccountId = frame_benchmarking::account("account", 1, 0); + + let prop: AuthorityProperties> = + AuthorityProperties { account_id: suffix.clone(), allocation: 10 }; + types_v1::UsernameAuthorities::::insert(&authority, &prop); + let prop: AuthorityProperties = + AuthorityProperties { account_id: authority.clone(), allocation: 10 }; + AuthorityOf::::insert(&suffix, &prop); + + let username: Username = b"account.bench".to_vec().try_into().unwrap(); + let info = T::IdentityInformation::create_identity_info(); + let registration: Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > = Registration { judgements: Default::default(), deposit: 10u32.into(), info }; + IdentityOf::::insert(&account_id, ®istration); + UsernameOf::::insert(&account_id, &username); + let username_info = UsernameInformation { + owner: account_id.clone(), + provider: Provider::new_with_allocation(), + }; + UsernameInfoOf::::insert(&username, username_info); + types_v1::AccountOfUsername::::insert(&username, &account_id); + let since: BlockNumberFor = 0u32.into(); + PendingUsernames::::insert( + &username, + (&account_id, since, Provider::new_with_allocation()), + ); + BenchmarkingSetup { suffix, authority, account: account_id, username } + } + + pub(crate) fn check_authority_cleanup_validity(suffix: Suffix, authority: T::AccountId) { + assert_eq!(types_v1::UsernameAuthorities::::iter().count(), 0); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().account_id, authority); + } + + pub(crate) fn check_username_cleanup_validity( + username: Username, + account_id: T::AccountId, + ) { + assert_eq!(types_v1::AccountOfUsername::::iter().count(), 0); + assert_eq!(UsernameInfoOf::::get(&username).unwrap().owner, account_id); + } + } + + #[cfg(test)] + mod tests { + use frame_support::Hashable; + + use super::*; + use crate::tests::{new_test_ext, Test}; + + fn registration( + with_deposit: bool, + ) -> Registration< + BalanceOf, + ::MaxRegistrars, + ::IdentityInformation, + > { + Registration { + judgements: Default::default(), + deposit: if with_deposit { 10u32.into() } else { 0u32.into() }, + info: Default::default(), + } + } + + fn account_from_u8(byte: u8) -> ::AccountId { + [byte; 32].into() + } + + #[test] + fn migrate_to_v2() { + new_test_ext().execute_with(|| { + StorageVersion::new(1).put::>(); + // Set up the first authority. + let authority_1 = account_from_u8(151); + let suffix_1: Suffix = b"evn".to_vec().try_into().unwrap(); + let prop = AuthorityProperties { account_id: suffix_1.clone(), allocation: 10 }; + types_v1::UsernameAuthorities::::insert(&authority_1, &prop); + // Set up the first authority. + let authority_2 = account_from_u8(152); + let suffix_2: Suffix = b"odd".to_vec().try_into().unwrap(); + let prop = AuthorityProperties { account_id: suffix_2.clone(), allocation: 10 }; + types_v1::UsernameAuthorities::::insert(&authority_2, &prop); + + // (owner_account, primary_username, maybe_secondary_username, has_identity) + // If `has_identity` is set, this `owner_account` will have a real identity + // associated and a non-zero deposit for it. + let mut usernames = vec![]; + for i in 0u8..100u8 { + let account_id = account_from_u8(i); + let bare_username = format!("acc{}.", i).as_bytes().to_vec(); + let mut username_1 = bare_username.clone(); + username_1.extend(suffix_1.iter()); + let username_1: Username = username_1.try_into().unwrap(); + types_v1::AccountOfUsername::::insert(&username_1, &account_id); + + if i % 2 == 0 { + let has_identity = i % 4 == 0; + let reg = registration(has_identity); + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), + (reg, Some(username_1.clone())), + ); + usernames.push((account_id, username_1, None, has_identity)); + } else { + let has_identity = i % 3 == 0; + let mut username_2 = bare_username.clone(); + username_2.extend(suffix_2.iter()); + let username_2: Username = username_2.try_into().unwrap(); + types_v1::AccountOfUsername::::insert(&username_2, &account_id); + let reg = registration(has_identity); + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), + (reg, Some(username_2.clone())), + ); + usernames.push((account_id, username_2, Some(username_1), has_identity)); + } + } + + // (username, owner_account, since) + let mut pending = vec![]; + for i in 100u8..110u8 { + let account_id = account_from_u8(i); + let mut bare_username = format!("acc{}.", i).as_bytes().to_vec(); + bare_username.extend(suffix_1.iter()); + let username: Username = bare_username.try_into().unwrap(); + let since: BlockNumberFor = i.into(); + frame_support::migration::put_storage_value( + b"Identity", + b"PendingUsernames", + &username.blake2_128_concat(), + (&account_id, since), + ); + pending.push((username, account_id, since)); + } + + let mut identity_only = vec![]; + for i in 120u8..130u8 { + let account_id = account_from_u8(i); + let reg = registration(true); + frame_support::migration::put_storage_value( + b"Identity", + b"IdentityOf", + &account_id.twox_64_concat(), + (reg, None::>), + ); + identity_only.push(account_id); + } + + // Run the actual migration. + let mut weight_meter = WeightMeter::new(); + let mut cursor = None; + while let Some(new_cursor) = + LazyMigrationV1ToV2::::step(cursor, &mut weight_meter).unwrap() + { + cursor = Some(new_cursor); + } + assert_eq!(Pallet::::on_chain_storage_version(), 2); + + // Check that the authorities were migrated. + let expected_prop = + AuthorityProperties { account_id: authority_1.clone(), allocation: 10 }; + assert_eq!(AuthorityOf::::get(&suffix_1), Some(expected_prop)); + + let expected_prop = + AuthorityProperties { account_id: authority_2.clone(), allocation: 10 }; + assert_eq!(AuthorityOf::::get(&suffix_2), Some(expected_prop)); + + // Check that the username information was migrated. + let count_of_usernames_without_identities = + usernames.iter().filter(|(_, _, _, has_id)| *has_id).count(); + assert_eq!(UsernameOf::::iter().count(), usernames.len()); + // All accounts have `evn` usernames, only half of them have `odd` usernames. + assert_eq!( + UsernameInfoOf::::iter().count(), + usernames.len() + usernames.len() / 2 + ); + for (owner, primary, maybe_secondary, has_identity) in usernames.iter() { + let username_info = UsernameInfoOf::::get(primary).unwrap(); + assert_eq!(&username_info.owner, owner); + let actual_primary = UsernameOf::::get(owner).unwrap(); + assert_eq!(primary, &actual_primary); + assert_eq!(IdentityOf::::contains_key(owner), *has_identity); + if let Some(secondary) = maybe_secondary { + let expected_info = UsernameInformation { + owner: owner.clone(), + provider: Provider::new_with_allocation(), + }; + assert_eq!(UsernameInfoOf::::get(secondary), Some(expected_info)); + } + } + + // Check that existing identities were preserved. + for id in identity_only.iter() { + let expected_reg = registration(true); + assert_eq!(IdentityOf::::get(id), Some(expected_reg)); + assert!(!UsernameOf::::contains_key(id)); + } + let identity_count = IdentityOf::::iter().count(); + assert_eq!( + identity_count, + count_of_usernames_without_identities + identity_only.len() + ); + + // Check that pending usernames were migrated. + let pending_count = PendingUsernames::::iter().count(); + assert_eq!(pending_count, pending.len()); + for (username, owner, since) in pending.iter() { + let expected_pending = (owner.clone(), *since, Provider::Allocation); + assert_eq!(PendingUsernames::::get(username), Some(expected_pending)); + } + + // Check that obsolete storage was cleared. + assert_eq!(types_v1::AccountOfUsername::::iter().count(), 0); + assert_eq!(types_v1::UsernameAuthorities::::iter().count(), 0); + }); + } + } +} diff --git a/substrate/frame/identity/src/tests.rs b/substrate/frame/identity/src/tests.rs index 3adb823ad5da..a095085a8188 100644 --- a/substrate/frame/identity/src/tests.rs +++ b/substrate/frame/identity/src/tests.rs @@ -77,6 +77,7 @@ impl pallet_identity::Config for Test { type Slashed = (); type BasicDeposit = ConstU64<100>; type ByteDeposit = ConstU64<10>; + type UsernameDeposit = ConstU64<10>; type SubAccountDeposit = ConstU64<100>; type MaxSubAccounts = ConstU32<2>; type IdentityInformation = IdentityInfo; @@ -87,6 +88,7 @@ impl pallet_identity::Config for Test { type SigningPublicKey = AccountPublic; type UsernameAuthorityOrigin = EnsureRoot; type PendingUsernameExpiration = ConstU64<100>; + type UsernameGracePeriod = ConstU64<2>; type MaxSuffixLength = ConstU32<7>; type MaxUsernameLength = ConstU32<32>; type WeightInfo = (); @@ -157,23 +159,21 @@ fn unfunded_accounts() -> [AccountIdOf; 2] { [account(100), account(101)] } -// First return value is a username that would be submitted as a parameter to the dispatchable. As -// in, it has no suffix attached. Second is a full BoundedVec username with suffix, which is what a -// user would need to sign. -fn test_username_of(int: Vec, suffix: Vec) -> (Vec, Username) { +// Returns a full BoundedVec username with suffix, which is what a user would need to sign. +fn test_username_of(int: Vec, suffix: Vec) -> Username { let base = b"testusername"; let mut username = Vec::with_capacity(base.len() + int.len()); username.extend(base); username.extend(int); let mut bounded_username = Vec::with_capacity(username.len() + suffix.len() + 1); - bounded_username.extend(username.clone()); + bounded_username.extend(username); bounded_username.extend(b"."); bounded_username.extend(suffix); let bounded_username = Username::::try_from(bounded_username) .expect("test usernames should fit within bounds"); - (username, bounded_username) + bounded_username } fn infoof_ten() -> IdentityInfo { @@ -401,7 +401,7 @@ fn registration_should_work() { RuntimeOrigin::signed(ten.clone()), Box::new(ten_info.clone()) )); - assert_eq!(IdentityOf::::get(ten.clone()).unwrap().0.info, ten_info); + assert_eq!(IdentityOf::::get(ten.clone()).unwrap().info, ten_info); assert_eq!(Balances::free_balance(ten.clone()), 1000 - id_deposit); assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(ten.clone()))); assert_eq!(Balances::free_balance(ten.clone()), 1000); @@ -485,7 +485,7 @@ fn uninvited_judgement_should_work() { identity_hash )); assert_eq!( - IdentityOf::::get(ten).unwrap().0.judgements, + IdentityOf::::get(ten).unwrap().judgements, vec![(0, Judgement::Reasonable)] ); }); @@ -875,20 +875,14 @@ fn poke_deposit_works() { // Set a custom registration with 0 deposit IdentityOf::::insert::< _, - ( - Registration>, - Option>, - ), + Registration>, >( &ten, - ( - Registration { - judgements: Default::default(), - deposit: Zero::zero(), - info: ten_info.clone(), - }, - None::>, - ), + Registration { + judgements: Default::default(), + deposit: Zero::zero(), + info: ten_info.clone(), + }, ); assert!(IdentityOf::::get(ten.clone()).is_some()); // Set a sub with zero deposit @@ -910,14 +904,11 @@ fn poke_deposit_works() { // new registration deposit is 10 assert_eq!( IdentityOf::::get(&ten), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit, - info: infoof_ten() - }, - None - )) + Some(Registration { + judgements: Default::default(), + deposit: id_deposit, + info: infoof_ten() + },) ); // new subs deposit is 10 vvvvvvvvvvvv assert_eq!(SubsOf::::get(ten), (subs_deposit, vec![twenty].try_into().unwrap())); @@ -932,20 +923,14 @@ fn poke_deposit_does_not_insert_new_subs_storage() { // Set a custom registration with 0 deposit IdentityOf::::insert::< _, - ( - Registration>, - Option>, - ), + Registration>, >( &ten, - ( - Registration { - judgements: Default::default(), - deposit: Zero::zero(), - info: ten_info.clone(), - }, - None::>, - ), + Registration { + judgements: Default::default(), + deposit: Zero::zero(), + info: ten_info.clone(), + }, ); assert!(IdentityOf::::get(ten.clone()).is_some()); @@ -961,14 +946,11 @@ fn poke_deposit_does_not_insert_new_subs_storage() { // new registration deposit is 10 assert_eq!( IdentityOf::::get(&ten), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit, - info: infoof_ten() - }, - None - )) + Some(Registration { + judgements: Default::default(), + deposit: id_deposit, + info: infoof_ten() + }) ); // No new subs storage item. assert!(!SubsOf::::contains_key(&ten)); @@ -989,10 +971,11 @@ fn adding_and_removing_authorities_should_work() { suffix.clone(), allocation )); + let suffix: Suffix = suffix.try_into().unwrap(); assert_eq!( - UsernameAuthorities::::get(&authority), - Some(AuthorityPropertiesOf:: { - suffix: suffix.clone().try_into().unwrap(), + AuthorityOf::::get(&suffix), + Some(AuthorityProperties::> { + account_id: authority.clone(), allocation }) ); @@ -1001,20 +984,24 @@ fn adding_and_removing_authorities_should_work() { assert_ok!(Identity::add_username_authority( RuntimeOrigin::root(), authority.clone(), - suffix.clone(), + suffix.clone().into(), 11u32 )); assert_eq!( - UsernameAuthorities::::get(&authority), - Some(AuthorityPropertiesOf:: { - suffix: suffix.try_into().unwrap(), + AuthorityOf::::get(&suffix), + Some(AuthorityProperties::> { + account_id: authority.clone(), allocation: 11 }) ); // remove - assert_ok!(Identity::remove_username_authority(RuntimeOrigin::root(), authority.clone(),)); - assert!(UsernameAuthorities::::get(&authority).is_none()); + assert_ok!(Identity::remove_username_authority( + RuntimeOrigin::root(), + suffix.clone().into(), + authority.clone(), + )); + assert!(AuthorityOf::::get(&suffix).is_none()); }); } @@ -1022,7 +1009,9 @@ fn adding_and_removing_authorities_should_work() { fn set_username_with_signature_without_existing_identity_should_work() { new_test_ext().execute_with(|| { // set up authority + let initial_authority_balance = 1000; let [authority, _] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1033,38 +1022,84 @@ fn set_username_with_signature_without_existing_identity_should_work() { )); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix); + let username = test_username_of(b"42".to_vec(), suffix.clone()); // set up user and sign message let public = sr25519_generate(0.into(), None); let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); - let signature = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_to_sign[..]).unwrap(), - ); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(authority.clone()), who_account.clone(), - username.clone(), - Some(signature) + username.clone().into(), + Some(signature), + true, )); - // Even though user has no balance and no identity, they get a default one for free. + // Even though user has no balance and no identity, the authority provides the username for + // free. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + // Lookup from username to account works. + let expected_user_info = + UsernameInformation { owner: who_account, provider: Provider::Allocation }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) + ); + // No balance was reserved. + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + // But the allocation decreased. assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(username_to_sign.clone()) - )) + AuthorityOf::::get(&Identity::suffix_of_username(&username).unwrap()) + .unwrap() + .allocation, + 9 ); + + // do the same for a username with a deposit + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + // set up username + let second_username = test_username_of(b"84".to_vec(), suffix.clone()); + + // set up user and sign message + let public = sr25519_generate(1.into(), None); + let second_who: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(1.into(), &public, &second_username[..]).unwrap()); + // don't use the allocation this time + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + second_who.clone(), + second_username.clone().into(), + Some(signature), + false, + )); + + // Even though user has no balance and no identity, the authority placed the deposit for + // them. + assert_eq!(UsernameOf::::get(&second_who), Some(second_username.clone())); // Lookup from username to account works. + let expected_user_info = UsernameInformation { + owner: second_who, + provider: Provider::AuthorityDeposit(username_deposit), + }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info) + ); + // The username deposit was reserved. + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + // But the allocation was preserved. assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account) + AuthorityOf::::get(&Identity::suffix_of_username(&second_username).unwrap()) + .unwrap() + .allocation, + 9 ); }); } @@ -1084,14 +1119,13 @@ fn set_username_with_signature_with_existing_identity_should_work() { )); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix); + let username = test_username_of(b"42".to_vec(), suffix); // set up user and sign message let public = sr25519_generate(0.into(), None); let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); - let signature = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_to_sign[..]).unwrap(), - ); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); // Set an identity for who. They need some balance though. Balances::make_free_balance_be(&who_account, 1000); @@ -1103,24 +1137,84 @@ fn set_username_with_signature_with_existing_identity_should_work() { assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - username.clone(), - Some(signature) + username.clone().into(), + Some(signature), + true, )); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + let expected_user_info = + UsernameInformation { owner: who_account, provider: Provider::Allocation }; assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit(&ten_info), - info: ten_info - }, - Some(username_to_sign.clone()) - )) + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) ); + }); +} + +#[test] +fn set_username_through_deposit_with_existing_identity_should_work() { + new_test_ext().execute_with(|| { + // set up authority + let initial_authority_balance = 1000; + let [authority, _] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + // set up username + let username = test_username_of(b"42".to_vec(), suffix); + + // set up user and sign message + let public = sr25519_generate(0.into(), None); + let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); + + // Set an identity for who. They need some balance though. + Balances::make_free_balance_be(&who_account, 1000); + let ten_info = infoof_ten(); + let expected_identity_deposit = Identity::calculate_identity_deposit(&ten_info); + assert_ok!(Identity::set_identity( + RuntimeOrigin::signed(who_account.clone()), + Box::new(ten_info.clone()) + )); assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account) + expected_identity_deposit, + IdentityOf::::get(&who_account).unwrap().deposit + ); + assert_eq!(Balances::reserved_balance(&who_account), expected_identity_deposit); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username.clone().into(), + Some(signature), + false, + )); + + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + // The authority placed the deposit for the username. + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + // No extra balance was reserved from the user for the username. + assert_eq!(Balances::free_balance(&who_account), 1000 - expected_identity_deposit); + assert_eq!(Balances::reserved_balance(&who_account), expected_identity_deposit); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + let expected_user_info = UsernameInformation { + owner: who_account, + provider: Provider::AuthorityDeposit(username_deposit), + }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) ); }); } @@ -1144,8 +1238,8 @@ fn set_username_with_bytes_signature_should_work() { let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix); - let unwrapped_username = username_to_sign.to_vec(); + let username = test_username_of(b"42".to_vec(), suffix); + let unwrapped_username = username.to_vec(); // Sign an unwrapped version, as in `username.suffix`. let signature_on_unwrapped = MultiSignature::Sr25519( @@ -1184,27 +1278,20 @@ fn set_username_with_bytes_signature_should_work() { assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - username, - Some(signature_on_wrapped) + username.clone().into(), + Some(signature_on_wrapped), + true, )); // The username in storage should not include ``. As in, it's the original // `username_to_sign`. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(username_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); // Likewise for the lookup. + let expected_user_info = + UsernameInformation { owner: who_account, provider: Provider::Allocation }; assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account) + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) ); }); } @@ -1213,7 +1300,9 @@ fn set_username_with_bytes_signature_should_work() { fn set_username_with_acceptance_should_work() { new_test_ext().execute_with(|| { // set up authority + let initial_authority_balance = 1000; let [authority, who] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1224,45 +1313,82 @@ fn set_username_with_acceptance_should_work() { )); // set up username - let (username, full_username) = test_username_of(b"101".to_vec(), suffix); + let username = test_username_of(b"101".to_vec(), suffix.clone()); let now = frame_system::Pallet::::block_number(); let expiration = now + <::PendingUsernameExpiration as Get>::get(); assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(authority.clone()), who.clone(), - username.clone(), - None + username.clone().into(), + None, + true, )); // Should be pending assert_eq!( - PendingUsernames::::get::<&Username>(&full_username), - Some((who.clone(), expiration)) + PendingUsernames::::get::<&Username>(&username), + Some((who.clone(), expiration, Provider::Allocation)) ); + // Now the user can accept + assert_ok!(Identity::accept_username(RuntimeOrigin::signed(who.clone()), username.clone())); + + // No more pending + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); + // Check Identity storage + assert_eq!(UsernameOf::::get(&who), Some(username.clone())); + // Check reverse lookup + let expected_user_info = UsernameInformation { owner: who, provider: Provider::Allocation }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) + ); + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + + let second_caller = account(99); + let second_username = test_username_of(b"102".to_vec(), suffix); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + second_caller.clone(), + second_username.clone().into(), + None, + false, + )); + + // Should be pending + let username_deposit = ::UsernameDeposit::get(); + assert_eq!( + PendingUsernames::::get::<&Username>(&second_username), + Some((second_caller.clone(), expiration, Provider::AuthorityDeposit(username_deposit))) + ); + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); // Now the user can accept assert_ok!(Identity::accept_username( - RuntimeOrigin::signed(who.clone()), - full_username.clone() + RuntimeOrigin::signed(second_caller.clone()), + second_username.clone() )); // No more pending - assert!(PendingUsernames::::get::<&Username>(&full_username).is_none()); + assert!(PendingUsernames::::get::<&Username>(&second_username).is_none()); // Check Identity storage + assert_eq!(UsernameOf::::get(&second_caller), Some(second_username.clone())); + // Check reverse lookup + let expected_user_info = UsernameInformation { + owner: second_caller, + provider: Provider::AuthorityDeposit(username_deposit), + }; assert_eq!( - IdentityOf::::get(&who), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(full_username.clone()) - )) + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info) + ); + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit ); - // Check reverse lookup - assert_eq!(AccountOfUsername::::get::<&Username>(&full_username), Some(who)); }); } @@ -1295,7 +1421,7 @@ fn invalid_usernames_should_be_rejected() { assert_ok!(Identity::add_username_authority( RuntimeOrigin::root(), authority.clone(), - valid_suffix, + valid_suffix.clone(), allocation )); @@ -1311,25 +1437,33 @@ fn invalid_usernames_should_be_rejected() { //0 1 2 v With `.test` this makes it too long. b"testusernametestusernametest".to_vec(), ]; - for username in invalid_usernames { + for username in invalid_usernames.into_iter().map(|mut username| { + username.push(b'.'); + username.extend(valid_suffix.clone()); + username + }) { assert_noop!( Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who.clone(), username.clone(), - None + None, + true, ), Error::::InvalidUsername ); } // valid one works - let valid_username = b"testusernametestusernametes".to_vec(); + let mut valid_username = b"testusernametestusernametes".to_vec(); + valid_username.push(b'.'); + valid_username.extend(valid_suffix); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who, valid_username, - None + None, + true, )); }); } @@ -1352,21 +1486,24 @@ fn authorities_should_run_out_of_allocation() { assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), pi, - b"username314159".to_vec(), - None + b"username314159.test".to_vec(), + None, + true, )); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), e, - b"username271828".to_vec(), - None + b"username271828.test".to_vec(), + None, + true )); assert_noop!( Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), c, - b"username299792458".to_vec(), - None + b"username299792458.test".to_vec(), + None, + true, ), Error::::NoAllocation ); @@ -1392,91 +1529,65 @@ fn setting_primary_should_work() { let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); // set up username - let (first_username, first_to_sign) = test_username_of(b"42".to_vec(), suffix.clone()); + let first_username = test_username_of(b"42".to_vec(), suffix.clone()); let first_signature = - MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &first_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &first_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who_account.clone(), - first_username.clone(), - Some(first_signature) + first_username.clone().into(), + Some(first_signature), + true )); // First username set as primary. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(first_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(first_username.clone())); // set up username - let (second_username, second_to_sign) = test_username_of(b"101".to_vec(), suffix); + let second_username = test_username_of(b"101".to_vec(), suffix); let second_signature = - MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &second_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &second_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority), who_account.clone(), - second_username.clone(), - Some(second_signature) + second_username.clone().into(), + Some(second_signature), + true, )); // The primary is still the first username. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(first_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(first_username.clone())); // Lookup from both works. + let expected_user_info = + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; assert_eq!( - AccountOfUsername::::get::<&Username>(&first_to_sign), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&first_username), + Some(expected_user_info.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&second_to_sign), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info.clone()) ); assert_ok!(Identity::set_primary_username( RuntimeOrigin::signed(who_account.clone()), - second_to_sign.clone() + second_username.clone() )); // The primary is now the second username. - assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: 0, - info: Default::default() - }, - Some(second_to_sign.clone()) - )) - ); + assert_eq!(UsernameOf::::get(&who_account), Some(second_username.clone())); // Lookup from both still works. assert_eq!( - AccountOfUsername::::get::<&Username>(&first_to_sign), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&first_username), + Some(expected_user_info.clone()) ); assert_eq!( - AccountOfUsername::::get::<&Username>(&second_to_sign), - Some(who_account) + UsernameInfoOf::::get::<&Username>(&second_username), + Some(expected_user_info) ); }); } @@ -1498,60 +1609,67 @@ fn must_own_primary() { // Set up first user ("pi") and a username. let pi_public = sr25519_generate(0.into(), None); let pi_account: AccountIdOf = MultiSigner::Sr25519(pi_public).into_account().into(); - let (pi_username, pi_to_sign) = - test_username_of(b"username314159".to_vec(), suffix.clone()); + let pi_username = test_username_of(b"username314159".to_vec(), suffix.clone()); let pi_signature = - MultiSignature::Sr25519(sr25519_sign(0.into(), &pi_public, &pi_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(0.into(), &pi_public, &pi_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), pi_account.clone(), - pi_username.clone(), - Some(pi_signature) + pi_username.clone().into(), + Some(pi_signature), + true, )); // Set up second user ("e") and a username. let e_public = sr25519_generate(1.into(), None); let e_account: AccountIdOf = MultiSigner::Sr25519(e_public).into_account().into(); - let (e_username, e_to_sign) = test_username_of(b"username271828".to_vec(), suffix.clone()); + let e_username = test_username_of(b"username271828".to_vec(), suffix.clone()); let e_signature = - MultiSignature::Sr25519(sr25519_sign(1.into(), &e_public, &e_to_sign[..]).unwrap()); + MultiSignature::Sr25519(sr25519_sign(1.into(), &e_public, &e_username[..]).unwrap()); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), e_account.clone(), - e_username.clone(), - Some(e_signature) + e_username.clone().into(), + Some(e_signature), + true )); // Ensure that both users have their usernames. + let expected_pi_info = + UsernameInformation { owner: pi_account.clone(), provider: Provider::Allocation }; assert_eq!( - AccountOfUsername::::get::<&Username>(&pi_to_sign), - Some(pi_account.clone()) + UsernameInfoOf::::get::<&Username>(&pi_username), + Some(expected_pi_info) ); + let expected_e_info = + UsernameInformation { owner: e_account.clone(), provider: Provider::Allocation }; assert_eq!( - AccountOfUsername::::get::<&Username>(&e_to_sign), - Some(e_account.clone()) + UsernameInfoOf::::get::<&Username>(&e_username), + Some(expected_e_info) ); // Cannot set primary to a username that does not exist. - let (_, c_username) = test_username_of(b"speedoflight".to_vec(), suffix.clone()); + let c_username = test_username_of(b"speedoflight".to_vec(), suffix.clone()); assert_err!( - Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), c_username,), + Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), c_username), Error::::NoUsername ); // Cannot take someone else's username as your primary. assert_err!( - Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), e_to_sign,), + Identity::set_primary_username(RuntimeOrigin::signed(pi_account.clone()), e_username), Error::::InvalidUsername ); }); } #[test] -fn unaccepted_usernames_should_expire() { +fn unaccepted_usernames_through_grant_should_expire() { new_test_ext().execute_with(|| { // set up authority + let initial_authority_balance = 1000; let [authority, who] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1562,31 +1680,34 @@ fn unaccepted_usernames_should_expire() { )); // set up username - let (username, full_username) = test_username_of(b"101".to_vec(), suffix); + let username = test_username_of(b"101".to_vec(), suffix.clone()); let now = frame_system::Pallet::::block_number(); let expiration = now + <::PendingUsernameExpiration as Get>::get(); + let suffix: Suffix = suffix.try_into().unwrap(); + + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(authority.clone()), who.clone(), - username.clone(), - None + username.clone().into(), + None, + true, )); + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); // Should be pending assert_eq!( - PendingUsernames::::get::<&Username>(&full_username), - Some((who.clone(), expiration)) + PendingUsernames::::get::<&Username>(&username), + Some((who.clone(), expiration, Provider::Allocation)) ); run_to_block(now + expiration - 1); // Cannot be removed assert_noop!( - Identity::remove_expired_approval( - RuntimeOrigin::signed(account(1)), - full_username.clone() - ), + Identity::remove_expired_approval(RuntimeOrigin::signed(account(1)), username.clone()), Error::::NotExpired ); @@ -1595,19 +1716,98 @@ fn unaccepted_usernames_should_expire() { // Anyone can remove assert_ok!(Identity::remove_expired_approval( RuntimeOrigin::signed(account(1)), - full_username.clone() + username.clone() )); + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + // Allocation wasn't refunded + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); // No more pending - assert!(PendingUsernames::::get::<&Username>(&full_username).is_none()); + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); }); } #[test] -fn removing_dangling_usernames_should_work() { +fn unaccepted_usernames_through_deposit_should_expire() { new_test_ext().execute_with(|| { // set up authority - let [authority, caller] = unfunded_accounts(); + let initial_authority_balance = 1000; + let [authority, who] = unfunded_accounts(); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + // set up username + let username = test_username_of(b"101".to_vec(), suffix.clone()); + let now = frame_system::Pallet::::block_number(); + let expiration = now + <::PendingUsernameExpiration as Get>::get(); + + let suffix: Suffix = suffix.try_into().unwrap(); + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who.clone(), + username.clone().into(), + None, + false, + )); + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); + + // Should be pending + assert_eq!( + PendingUsernames::::get::<&Username>(&username), + Some((who.clone(), expiration, Provider::AuthorityDeposit(username_deposit))) + ); + + run_to_block(now + expiration - 1); + + // Cannot be removed + assert_noop!( + Identity::remove_expired_approval(RuntimeOrigin::signed(account(1)), username.clone()), + Error::::NotExpired + ); + + run_to_block(now + expiration); + + // Anyone can remove + assert_eq!( + Balances::free_balance(&authority), + initial_authority_balance - username_deposit + ); + assert_eq!(Balances::reserved_balance(&authority), username_deposit); + assert_ok!(Identity::remove_expired_approval( + RuntimeOrigin::signed(account(1)), + username.clone() + )); + // Deposit was refunded + assert_eq!(Balances::free_balance(&authority), initial_authority_balance); + // Allocation wasn't refunded + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 10); + + // No more pending + assert!(PendingUsernames::::get::<&Username>(&username).is_none()); + }); +} + +#[test] +fn kill_username_should_work() { + new_test_ext().execute_with(|| { + let initial_authority_balance = 10000; + // set up first authority + let authority = account(100); + Balances::make_free_balance_be(&authority, initial_authority_balance); let suffix: Vec = b"test".to_vec(); let allocation: u32 = 10; assert_ok!(Identity::add_username_authority( @@ -1617,99 +1817,421 @@ fn removing_dangling_usernames_should_work() { allocation )); + let second_authority = account(200); + Balances::make_free_balance_be(&second_authority, initial_authority_balance); + let second_suffix: Vec = b"abc".to_vec(); + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + second_authority.clone(), + second_suffix.clone(), + allocation + )); + + let username_deposit = ::UsernameDeposit::get(); + // set up username - let (username, username_to_sign) = test_username_of(b"42".to_vec(), suffix.clone()); + let username = test_username_of(b"42".to_vec(), suffix.clone()); // set up user and sign message let public = sr25519_generate(0.into(), None); let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); - let signature = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_to_sign[..]).unwrap(), - ); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); // Set an identity for who. They need some balance though. Balances::make_free_balance_be(&who_account, 1000); - let ten_info = infoof_ten(); - assert_ok!(Identity::set_identity( - RuntimeOrigin::signed(who_account.clone()), - Box::new(ten_info.clone()) - )); assert_ok!(Identity::set_username_for( RuntimeOrigin::signed(authority.clone()), who_account.clone(), - username.clone(), - Some(signature) + username.clone().into(), + Some(signature), + false )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); // Now they set up a second username. - let (username_two, username_two_to_sign) = test_username_of(b"43".to_vec(), suffix); + let username_two = test_username_of(b"43".to_vec(), suffix.clone()); // set up user and sign message - let signature_two = MultiSignature::Sr25519( - sr25519_sign(0.into(), &public, &username_two_to_sign[..]).unwrap(), + let signature_two = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_two[..]).unwrap()); + + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username_two.clone().into(), + Some(signature_two), + false + )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - 2 * username_deposit ); + // Now they set up a third username with another authority. + let username_three = test_username_of(b"42".to_vec(), second_suffix.clone()); + + // set up user and sign message + let signature_three = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_three[..]).unwrap()); + assert_ok!(Identity::set_username_for( - RuntimeOrigin::signed(authority), + RuntimeOrigin::signed(second_authority.clone()), who_account.clone(), - username_two.clone(), - Some(signature_two) + username_three.clone().into(), + Some(signature_three), + true )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - 2 * username_deposit + ); + assert_eq!(Balances::free_balance(second_authority.clone()), initial_authority_balance); // The primary should still be the first one. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + + // But both usernames should look up the account. + let expected_user_info = UsernameInformation { + owner: who_account.clone(), + provider: Provider::AuthorityDeposit(username_deposit), + }; assert_eq!( - IdentityOf::::get(&who_account), - Some(( - Registration { - judgements: Default::default(), - deposit: id_deposit(&ten_info), - info: ten_info - }, - Some(username_to_sign.clone()) - )) + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info.clone()) + ); + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username_two), + Some(expected_user_info.clone()) ); + // Regular accounts can't kill a username, not even the authority that granted it. + assert_noop!( + Identity::kill_username(RuntimeOrigin::signed(authority.clone()), username.clone()), + BadOrigin + ); + + // Can't kill a username that doesn't exist. + assert_noop!( + Identity::kill_username( + RuntimeOrigin::root(), + test_username_of(b"999".to_vec(), suffix.clone()) + ), + Error::::NoUsername + ); + + // Unbind the second username. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username_two.clone() + )); + + // Kill the second username. + assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username_two.clone().into())); + + // The reverse lookup of the primary is gone. + assert!(UsernameInfoOf::::get::<&Username>(&username_two).is_none()); + // The unbinding map entry is gone. + assert!(UnbindingUsernames::::get::<&Username>(&username).is_none()); + // The authority's deposit was slashed. + assert_eq!(Balances::reserved_balance(authority.clone()), username_deposit); + + // But the reverse lookup of the primary is still there + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info) + ); + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + assert!(UsernameInfoOf::::contains_key(&username_three)); + + // Kill the first, primary username. + assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username.clone().into())); + + // The reverse lookup of the primary is gone. + assert!(UsernameInfoOf::::get::<&Username>(&username).is_none()); + assert!(!UsernameOf::::contains_key(&who_account)); + // The authority's deposit was slashed. + assert_eq!(Balances::reserved_balance(authority.clone()), 0); + + // But the reverse lookup of the third and final username is still there + let expected_user_info = + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; + assert_eq!( + UsernameInfoOf::::get::<&Username>(&username_three), + Some(expected_user_info) + ); + + // Kill the third and last username. + assert_ok!(Identity::kill_username(RuntimeOrigin::root(), username_three.clone().into())); + // Everything is gone. + assert!(!UsernameInfoOf::::contains_key(&username_three)); + }); +} + +#[test] +fn unbind_and_remove_username_should_work() { + new_test_ext().execute_with(|| { + let initial_authority_balance = 10000; + // Set up authority. + let authority = account(100); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); + + let username_deposit = ::UsernameDeposit::get(); + + // Set up username. + let username = test_username_of(b"42".to_vec(), suffix.clone()); + + // Set up user and sign message. + let public = sr25519_generate(0.into(), None); + let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); + + // Set an identity for who. They need some balance though. + Balances::make_free_balance_be(&who_account, 1000); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username.clone().into(), + Some(signature), + false + )); + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); + + // Now they set up a second username. + let username_two = test_username_of(b"43".to_vec(), suffix.clone()); + + // Set up user and sign message. + let signature_two = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username_two[..]).unwrap()); + + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username_two.clone().into(), + Some(signature_two), + true + )); + // Second one is free. + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); + + // The primary should still be the first one. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + // But both usernames should look up the account. + let expected_user_info = UsernameInformation { + owner: who_account.clone(), + provider: Provider::AuthorityDeposit(username_deposit), + }; assert_eq!( - AccountOfUsername::::get::<&Username>(&username_to_sign), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&username), + Some(expected_user_info.clone()) ); + let expected_user_info = + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }; assert_eq!( - AccountOfUsername::::get::<&Username>(&username_two_to_sign), - Some(who_account.clone()) + UsernameInfoOf::::get::<&Username>(&username_two), + Some(expected_user_info.clone()) ); - // Someone tries to remove it, but they can't + // Regular accounts can't kill a username, not even the authority that granted it. assert_noop!( - Identity::remove_dangling_username( - RuntimeOrigin::signed(caller.clone()), - username_to_sign.clone() + Identity::kill_username(RuntimeOrigin::signed(authority.clone()), username.clone()), + BadOrigin + ); + + // Can't unbind a username that doesn't exist. + let dummy_suffix = b"abc".to_vec(); + let dummy_username = test_username_of(b"999".to_vec(), dummy_suffix.clone()); + let dummy_authority = account(78); + assert_noop!( + Identity::unbind_username( + RuntimeOrigin::signed(dummy_authority.clone()), + dummy_username.clone() ), - Error::::InvalidUsername + Error::::NoUsername ); - // Now the user calls `clear_identity` - assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(who_account.clone()),)); + let dummy_suffix: Suffix = dummy_suffix.try_into().unwrap(); + // Only the authority that granted the username can unbind it. + UsernameInfoOf::::insert( + dummy_username.clone(), + UsernameInformation { owner: who_account.clone(), provider: Provider::Allocation }, + ); + assert_noop!( + Identity::unbind_username( + RuntimeOrigin::signed(dummy_authority.clone()), + dummy_username.clone() + ), + Error::::NotUsernameAuthority + ); + // Simulate a dummy authority. + AuthorityOf::::insert( + dummy_suffix.clone(), + AuthorityProperties { account_id: dummy_authority.clone(), allocation: 10 }, + ); + // But try to remove the dummy username as a different authority, not the one that + // originally granted the username. + assert_noop!( + Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + dummy_username.clone() + ), + Error::::NotUsernameAuthority + ); + // Clean up storage. + let _ = UsernameInfoOf::::take(dummy_username.clone()); + let _ = AuthorityOf::::take(dummy_suffix); - // Identity is gone - assert!(IdentityOf::::get(who_account.clone()).is_none()); + // We can successfully unbind the username as the authority that granted it. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username_two.clone() + )); + let grace_period: BlockNumberFor = ::UsernameGracePeriod::get(); + let now = 1; + assert_eq!(System::block_number(), now); + let expected_grace_period_expiry: BlockNumberFor = now + grace_period; + assert_eq!( + UnbindingUsernames::::get(&username_two), + Some(expected_grace_period_expiry) + ); - // The reverse lookup of the primary is gone. - assert!(AccountOfUsername::::get::<&Username>(&username_to_sign).is_none()); + // Still in the grace period. + assert_noop!( + Identity::remove_username(RuntimeOrigin::signed(account(0)), username_two.clone()), + Error::::TooEarly + ); + + // Advance the block number to simulate the grace period passing. + System::set_block_number(expected_grace_period_expiry); + + let suffix: Suffix = suffix.try_into().unwrap(); + // We can now remove the username from any account. + assert_ok!(Identity::remove_username( + RuntimeOrigin::signed(account(0)), + username_two.clone() + )); + // The username is gone. + assert!(!UnbindingUsernames::::contains_key(&username_two)); + assert!(!UsernameInfoOf::::contains_key(&username_two)); + // Primary username was preserved. + assert_eq!(UsernameOf::::get(&who_account), Some(username.clone())); + // The username was granted through a governance allocation, so no deposit was released. + assert_eq!( + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit + ); + // Allocation wasn't refunded. + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); + + // Unbind the first username as well. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username.clone() + )); + let now: BlockNumberFor = expected_grace_period_expiry; + assert_eq!(System::block_number(), now); + let expected_grace_period_expiry: BlockNumberFor = now + grace_period; + assert_eq!(UnbindingUsernames::::get(&username), Some(expected_grace_period_expiry)); + // Advance the block number to simulate the grace period passing. + System::set_block_number(expected_grace_period_expiry); + // We can now remove the username from any account. + assert_ok!(Identity::remove_username(RuntimeOrigin::signed(account(0)), username.clone())); + // The username is gone. + assert!(!UnbindingUsernames::::contains_key(&username)); + assert!(!UsernameInfoOf::::contains_key(&username)); + // Primary username was also removed. + assert!(!UsernameOf::::contains_key(&who_account)); + // The username deposit was released. + assert_eq!(Balances::free_balance(authority.clone()), initial_authority_balance); + // Allocation didn't change. + assert_eq!(AuthorityOf::::get(&suffix).unwrap().allocation, 9); + }); +} + +#[test] +#[should_panic] +fn unbind_dangling_username_defensive_should_panic() { + new_test_ext().execute_with(|| { + let initial_authority_balance = 10000; + // Set up authority. + let authority = account(100); + Balances::make_free_balance_be(&authority, initial_authority_balance); + let suffix: Vec = b"test".to_vec(); + let allocation: u32 = 10; + assert_ok!(Identity::add_username_authority( + RuntimeOrigin::root(), + authority.clone(), + suffix.clone(), + allocation + )); - // But the reverse lookup of the non-primary is still there + let username_deposit: BalanceOf = ::UsernameDeposit::get(); + + // Set up username. + let username = test_username_of(b"42".to_vec(), suffix.clone()); + + // Set up user and sign message. + let public = sr25519_generate(0.into(), None); + let who_account: AccountIdOf = MultiSigner::Sr25519(public).into_account().into(); + let signature = + MultiSignature::Sr25519(sr25519_sign(0.into(), &public, &username[..]).unwrap()); + + // Set an identity for who. They need some balance though. + Balances::make_free_balance_be(&who_account, 1000); + assert_ok!(Identity::set_username_for( + RuntimeOrigin::signed(authority.clone()), + who_account.clone(), + username.clone().into(), + Some(signature), + false + )); assert_eq!( - AccountOfUsername::::get::<&Username>(&username_two_to_sign), - Some(who_account) + Balances::free_balance(authority.clone()), + initial_authority_balance - username_deposit ); - // Now it can be removed - assert_ok!(Identity::remove_dangling_username( - RuntimeOrigin::signed(caller), - username_two_to_sign.clone() + // We can successfully unbind the username as the authority that granted it. + assert_ok!(Identity::unbind_username( + RuntimeOrigin::signed(authority.clone()), + username.clone() )); + assert_eq!(System::block_number(), 1); + assert_eq!(UnbindingUsernames::::get(&username), Some(1)); + + // Still in the grace period. + assert_noop!( + Identity::remove_username(RuntimeOrigin::signed(account(0)), username.clone()), + Error::::TooEarly + ); - // And the reverse lookup is gone - assert!(AccountOfUsername::::get::<&Username>(&username_two_to_sign).is_none()); + // Advance the block number to simulate the grace period passing. + System::set_block_number(3); + + // Simulate a dangling entry in the unbinding map without an actual username registered. + UsernameInfoOf::::remove(&username); + UsernameOf::::remove(&who_account); + assert_noop!( + Identity::remove_username(RuntimeOrigin::signed(account(0)), username.clone()), + Error::::NoUsername + ); }); } diff --git a/substrate/frame/identity/src/types.rs b/substrate/frame/identity/src/types.rs index 45401d53e9e9..ece3c34f82ef 100644 --- a/substrate/frame/identity/src/types.rs +++ b/substrate/frame/identity/src/types.rs @@ -320,9 +320,6 @@ pub struct RegistrarInfo< pub fields: IdField, } -/// Authority properties for a given pallet configuration. -pub type AuthorityPropertiesOf = AuthorityProperties>; - /// The number of usernames that an authority may allocate. type Allocation = u32; /// A byte vec used to represent a username. @@ -330,11 +327,9 @@ pub(crate) type Suffix = BoundedVec::MaxSuffixLength>; /// Properties of a username authority. #[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)] -pub struct AuthorityProperties { - /// The suffix added to usernames granted by this authority. Will be appended to usernames; for - /// example, a suffix of `wallet` will result in `.wallet` being appended to a user's selected - /// name. - pub suffix: Suffix, +pub struct AuthorityProperties { + /// The account of the authority. + pub account_id: Account, /// The number of usernames remaining that this authority can grant. pub allocation: Allocation, } @@ -342,6 +337,34 @@ pub struct AuthorityProperties { /// A byte vec used to represent a username. pub(crate) type Username = BoundedVec::MaxUsernameLength>; +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)] +pub enum Provider { + Allocation, + AuthorityDeposit(Balance), + System, +} + +impl Provider { + pub fn new_with_allocation() -> Self { + Self::Allocation + } + + pub fn new_with_deposit(deposit: Balance) -> Self { + Self::AuthorityDeposit(deposit) + } + + #[allow(unused)] + pub fn new_permanent() -> Self { + Self::System + } +} + +#[derive(Clone, Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Debug)] +pub struct UsernameInformation { + pub owner: Account, + pub provider: Provider, +} + #[cfg(test)] mod tests { use super::*; diff --git a/substrate/frame/identity/src/weights.rs b/substrate/frame/identity/src/weights.rs index 008d5465bb4f..a74cca9dc8ec 100644 --- a/substrate/frame/identity/src/weights.rs +++ b/substrate/frame/identity/src/weights.rs @@ -69,11 +69,19 @@ pub trait WeightInfo { fn quit_sub(s: u32, ) -> Weight; fn add_username_authority() -> Weight; fn remove_username_authority() -> Weight; - fn set_username_for() -> Weight; + fn set_username_for(p: u32) -> Weight; fn accept_username() -> Weight; - fn remove_expired_approval() -> Weight; + fn remove_expired_approval(p: u32) -> Weight; fn set_primary_username() -> Weight; - fn remove_dangling_username() -> Weight; + fn unbind_username() -> Weight; + fn remove_username() -> Weight; + fn kill_username(p: u32) -> Weight; + fn migration_v2_authority_step() -> Weight; + fn migration_v2_username_step() -> Weight; + fn migration_v2_identity_step() -> Weight; + fn migration_v2_pending_username_step() -> Weight; + fn migration_v2_cleanup_authority_step() -> Weight; + fn migration_v2_cleanup_username_step() -> Weight; } /// Weights for `pallet_identity` using the Substrate node and recommended hardware. @@ -380,7 +388,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -406,7 +414,7 @@ impl WeightInfo for SubstrateWeight { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32) -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `3550` @@ -428,18 +436,32 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `11037` - // Minimum execution time: 12_017_000 picoseconds. - Weight::from_parts(12_389_000, 11037) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32) -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() } } @@ -746,7 +768,7 @@ impl WeightInfo for () { /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn set_username_for() -> Weight { + fn set_username_for(_p: u32) -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` @@ -772,7 +794,7 @@ impl WeightInfo for () { } /// Storage: `Identity::PendingUsernames` (r:1 w:1) /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) - fn remove_expired_approval() -> Weight { + fn remove_expired_approval(_p: u32) -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `3550` @@ -794,17 +816,31 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) - /// Storage: `Identity::IdentityOf` (r:1 w:0) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) - fn remove_dangling_username() -> Weight { - // Proof Size summary in bytes: - // Measured: `98` - // Estimated: `11037` - // Minimum execution time: 12_017_000 picoseconds. - Weight::from_parts(12_389_000, 11037) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + fn unbind_username() -> Weight { + Weight::zero() + } + fn remove_username() -> Weight { + Weight::zero() + } + fn kill_username(_p: u32) -> Weight { + Weight::zero() + } + fn migration_v2_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_identity_step() -> Weight { + Weight::zero() + } + fn migration_v2_pending_username_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_authority_step() -> Weight { + Weight::zero() + } + fn migration_v2_cleanup_username_step() -> Weight { + Weight::zero() } }