From 2ceaa688928bf8d394fbcb156cbfd722e50b5959 Mon Sep 17 00:00:00 2001 From: Nisheeth Barthwal Date: Thu, 2 Jun 2022 07:37:10 +0200 Subject: [PATCH] add pallet::call to hotfix sufficients for non-zero nonce accounts (#619) * add pallet::call to hotfix sufficients for non-zero nonce accounts * make hotfix to fix sufficients payable * cargo fmt * use distinct pallet for hotfix * cleanup traces from pallet evm * add pallet-hotfix-sufficients * fix description * fix benchmarking * update test condition, add docs * use safe add Co-authored-by: tgmichel --- Cargo.lock | 17 +++ Cargo.toml | 1 + benchmarking/frame-weight-template.hbs | 109 +++++++++++++++ frame/evm/src/lib.rs | 1 + frame/hotfix-sufficients/Cargo.toml | 40 ++++++ frame/hotfix-sufficients/README.md | 16 +++ frame/hotfix-sufficients/src/benchmarking.rs | 62 +++++++++ frame/hotfix-sufficients/src/lib.rs | 102 ++++++++++++++ frame/hotfix-sufficients/src/mock.rs | 84 +++++++++++ frame/hotfix-sufficients/src/tests.rs | 139 +++++++++++++++++++ frame/hotfix-sufficients/src/weights.rs | 95 +++++++++++++ scripts/benchmark.sh | 49 +++++++ template/runtime/Cargo.toml | 2 + template/runtime/src/lib.rs | 10 ++ 14 files changed, 727 insertions(+) create mode 100644 benchmarking/frame-weight-template.hbs create mode 100644 frame/hotfix-sufficients/Cargo.toml create mode 100644 frame/hotfix-sufficients/README.md create mode 100644 frame/hotfix-sufficients/src/benchmarking.rs create mode 100644 frame/hotfix-sufficients/src/lib.rs create mode 100644 frame/hotfix-sufficients/src/mock.rs create mode 100644 frame/hotfix-sufficients/src/tests.rs create mode 100644 frame/hotfix-sufficients/src/weights.rs create mode 100755 scripts/benchmark.sh diff --git a/Cargo.lock b/Cargo.lock index 7909cd5edf..bae8f4dcd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2122,6 +2122,7 @@ dependencies = [ "pallet-evm-precompile-sha3fips", "pallet-evm-precompile-simple", "pallet-grandpa", + "pallet-hotfix-sufficients", "pallet-randomness-collective-flip", "pallet-sudo", "pallet-timestamp", @@ -4562,6 +4563,22 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-hotfix-sufficients" +version = "1.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-evm", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-randomness-collective-flip" version = "4.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 3827572e1a..e656a72290 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "frame/dynamic-fee", "frame/ethereum", "frame/evm", + "frame/hotfix-sufficients", "frame/evm/precompile/sha3fips", "frame/evm/precompile/simple", "frame/evm/precompile/modexp", diff --git a/benchmarking/frame-weight-template.hbs b/benchmarking/frame-weight-template.hbs new file mode 100644 index 0000000000..f4dd4da68e --- /dev/null +++ b/benchmarking/frame-weight-template.hbs @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: Apache-2.0 +// This file is part of Frontier. +// +// Copyright (c) 2020 Parity Technologies (UK) Ltd. +// +// 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. + +//! 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}}` +//! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} + +// Executed Command: +{{#each args as |arg|~}} +// {{arg}} +{{/each}} + +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// 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); +impl WeightInfo for SubstrateWeight { + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} + // {{comment}} + {{/each}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + ({{underscore benchmark.base_weight}} as Weight) + {{#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) + {{/each}} + {{#if (ne benchmark.base_reads "0")}} + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight)) + {{/if}} + {{#each benchmark.component_reads as |cr|}} + .saturating_add(T::DbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) + {{/each}} + {{#if (ne benchmark.base_writes "0")}} + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight)) + {{/if}} + {{#each benchmark.component_writes as |cw|}} + .saturating_add(T::DbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) + {{/each}} + } + {{/each}} +} + +// For backwards compatibility and tests +impl WeightInfo for () { + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} + // {{comment}} + {{/each}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + ({{underscore benchmark.base_weight}} as Weight) + {{#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(({{underscore cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight)) + {{/each}} + {{#if (ne benchmark.base_reads "0")}} + .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}} as Weight)) + {{/if}} + {{#each benchmark.component_reads as |cr|}} + .saturating_add(RocksDbWeight::get().reads(({{cr.slope}} as Weight).saturating_mul({{cr.name}} as Weight))) + {{/each}} + {{#if (ne benchmark.base_writes "0")}} + .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}} as Weight)) + {{/if}} + {{#each benchmark.component_writes as |cw|}} + .saturating_add(RocksDbWeight::get().writes(({{cw.slope}} as Weight).saturating_mul({{cw.name}} as Weight))) + {{/each}} + } + {{/each}} +} diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index 19be4ced78..b8e8795894 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -54,6 +54,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::too_many_arguments)] +#[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; #[cfg(test)] diff --git a/frame/hotfix-sufficients/Cargo.toml b/frame/hotfix-sufficients/Cargo.toml new file mode 100644 index 0000000000..e1df27153b --- /dev/null +++ b/frame/hotfix-sufficients/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "pallet-hotfix-sufficients" +version = "1.0.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/frontier/" +description = "Hotfix zero-value account sufficients with non-zero-value nonces" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } +sp-core = { version = "6.0.0", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { version = "6.0.0", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { version = "6.0.0", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { version = "4.0.0", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +frame-benchmarking = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +frame-support = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-evm = { path = "../evm", default-features = false } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", +] +runtime-benchmarks = [ + "frame-benchmarking", +] diff --git a/frame/hotfix-sufficients/README.md b/frame/hotfix-sufficients/README.md new file mode 100644 index 0000000000..e6339b0f74 --- /dev/null +++ b/frame/hotfix-sufficients/README.md @@ -0,0 +1,16 @@ +# Hotfix Sufficients Module + +The Hotfix Sufficients module allows hotfixing account inconsistency to patch existing accounts that have a non-zero `nonce` but a zero `sufficients` value. +The accounts' `sufficients` values also need to be non-zero to be consistent. + +## Description + +This pallet can be used to hotfix the account state where a previous bug in EVM create account, lead to accounts being created with `0` references (consumers + providers + sufficients) +but a non-zero nonce. + +The dispatchable `hotfix_inc_account_sufficients` fixes this by taking a list of account addresses that have zero reference counts (consumers, providers, sufficients are all `0`), +and incrementing their `sufficients` reference counter. + +Any addresses that do not have a zero reference count, will be unaffected. + +License: Apache-2.0 \ No newline at end of file diff --git a/frame/hotfix-sufficients/src/benchmarking.rs b/frame/hotfix-sufficients/src/benchmarking.rs new file mode 100644 index 0000000000..ef20513d93 --- /dev/null +++ b/frame/hotfix-sufficients/src/benchmarking.rs @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: Apache-2.0 +// This file is part of Frontier. +// +// Copyright (c) 2020-2022 Parity Technologies (UK) Ltd. +// +// 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. + +#![cfg(feature = "runtime-benchmarks")] + +use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; + +use super::*; + +benchmarks! { + hotfix_inc_account_sufficients { + // This benchmark tests the resource utilization by hotfixing N number of accounts + // by incrementing their `sufficients` if `nonce` is > 0. + + let n in 0 .. 1000; + + use frame_benchmarking::{whitelisted_caller}; + use sp_core::H160; + use frame_system::RawOrigin; + + // The caller account is whitelisted for DB reads/write by the benchmarking macro. + let caller: T::AccountId = whitelisted_caller(); + let addresses = (0..n as u64) + .map(H160::from_low_u64_le) + .collect::>(); + let accounts = addresses + .iter() + .cloned() + .map(|addr| { + let account_id = T::AddressMapping::into_account_id(addr); + frame_system::Pallet::::inc_account_nonce(&account_id); + assert_eq!(frame_system::Pallet::::sufficients(&account_id), 0); + + account_id + }) + .collect::>(); + + }: _(RawOrigin::Signed(caller), addresses) + verify { + accounts + .iter() + .for_each(|id| { + assert_eq!(frame_system::Pallet::::sufficients(&id), 1); + }); + } +} + +impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::tests::Test); diff --git a/frame/hotfix-sufficients/src/lib.rs b/frame/hotfix-sufficients/src/lib.rs new file mode 100644 index 0000000000..3a4d49f9e3 --- /dev/null +++ b/frame/hotfix-sufficients/src/lib.rs @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: Apache-2.0 +// This file is part of Frontier. +// +// Copyright (c) 2021-2022 Parity Technologies (UK) Ltd. +// +// 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. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(test)] +mod tests; + +#[cfg(test)] +mod mock; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; +pub mod weights; +pub use weights::WeightInfo; + +pub use pallet_evm::AddressMapping; +use sp_runtime::traits::Zero; +use sp_std::vec::Vec; + +pub use self::pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + use sp_core::H160; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// Mapping from address to account id. + type AddressMapping: AddressMapping; + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + } + + #[pallet::error] + pub enum Error { + /// Maximum address count exceeded + MaxAddressCountExceeded, + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + /// Increment `sufficients` for existing accounts having a nonzero `nonce` but zero `sufficients`, `consumers` and `providers` value. + /// This state was caused by a previous bug in EVM create account dispatchable. + /// + /// Any accounts in the input list not satisfying the above condition will remain unaffected. + #[pallet::weight( + ::WeightInfo::hotfix_inc_account_sufficients(addresses.len().try_into().unwrap_or(u32::MAX)) + )] + pub fn hotfix_inc_account_sufficients( + origin: OriginFor, + addresses: Vec, + ) -> DispatchResultWithPostInfo { + const MAX_ADDRESS_COUNT: usize = 1000; + + frame_system::ensure_signed(origin)?; + ensure!( + addresses.len() <= MAX_ADDRESS_COUNT, + Error::::MaxAddressCountExceeded + ); + + for address in addresses { + let account_id = T::AddressMapping::into_account_id(address); + let nonce = frame_system::Pallet::::account_nonce(&account_id); + let refs = frame_system::Pallet::::consumers(&account_id) + .saturating_add(frame_system::Pallet::::providers(&account_id)) + .saturating_add(frame_system::Pallet::::sufficients(&account_id)); + + if !nonce.is_zero() && refs.is_zero() { + frame_system::Pallet::::inc_sufficients(&account_id); + } + } + + Ok(PostDispatchInfo { + actual_weight: None, + pays_fee: Pays::Yes, + }) + } + } +} diff --git a/frame/hotfix-sufficients/src/mock.rs b/frame/hotfix-sufficients/src/mock.rs new file mode 100644 index 0000000000..c6112b69e5 --- /dev/null +++ b/frame/hotfix-sufficients/src/mock.rs @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: Apache-2.0 +// This file is part of Frontier. +// +// Copyright (c) 2021-2022 Parity Technologies (UK) Ltd. +// +// 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. + +use frame_support::{parameter_types, traits::ConstU32}; +use sp_core::{H160, H256}; +use sp_runtime::{ + testing::Header, + traits::{BlakeTwo256, IdentityLookup}, +}; + +use super::*; +use crate as pallet_hotfix_sufficients; + +pub fn new_test_ext() -> sp_io::TestExternalities { + frame_system::GenesisConfig::default() + .build_storage::() + .unwrap() + .into() +} + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + HotfixSufficients: pallet_hotfix_sufficients::{Pallet, Call}, + } +); + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(1024); +} +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = Call; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = H160; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl Config for Test { + type AddressMapping = pallet_evm::IdentityAddressMapping; + type WeightInfo = (); +} diff --git a/frame/hotfix-sufficients/src/tests.rs b/frame/hotfix-sufficients/src/tests.rs new file mode 100644 index 0000000000..a6fd5c9fa8 --- /dev/null +++ b/frame/hotfix-sufficients/src/tests.rs @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: Apache-2.0 +// This file is part of Frontier. +// +// Copyright (c) 2021-2022 Parity Technologies (UK) Ltd. +// +// 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. + +use core::str::FromStr; + +use sp_core::H160; +// use std::str::FromStr; + +use super::*; +use crate::{ + mock::{new_test_ext, Origin, Test}, + pallet::Pallet, +}; + +#[test] +fn test_hotfix_inc_account_sufficients_returns_error_if_max_addresses_exceeded() { + new_test_ext().execute_with(|| { + let max_address_count = 1000; + let addresses = (0..max_address_count + 1 as u64) + .map(H160::from_low_u64_le) + .collect::>(); + + let result = >::hotfix_inc_account_sufficients( + Origin::signed(H160::default()), + addresses, + ); + + assert!(result.is_err(), "expected error"); + }); +} + +#[test] +fn test_hotfix_inc_account_sufficients_requires_signed_origin() { + new_test_ext().execute_with(|| { + let addr = H160::from_str("1230000000000000000000000000000000000001").unwrap(); + let unsigned_origin = Origin::root(); + let result = >::hotfix_inc_account_sufficients(unsigned_origin, vec![addr]); + + assert!(result.is_err(), "expected error"); + }); +} + +#[test] +fn test_hotfix_inc_account_sufficients_increments_if_nonce_nonzero() { + new_test_ext().execute_with(|| { + let addr_1 = H160::from_str("1230000000000000000000000000000000000001").unwrap(); + let addr_2 = H160::from_str("1234000000000000000000000000000000000001").unwrap(); + let substrate_addr_1 = ::AddressMapping::into_account_id(addr_1); + let substrate_addr_2 = ::AddressMapping::into_account_id(addr_2); + + frame_system::Pallet::::inc_account_nonce(&substrate_addr_1); + + let account_1 = frame_system::Account::::get(substrate_addr_1); + let account_2 = frame_system::Account::::get(substrate_addr_2); + assert_eq!(account_1.nonce, 1); + assert_eq!(account_1.sufficients, 0); + assert_eq!(account_2.nonce, 0); + assert_eq!(account_2.sufficients, 0); + + >::hotfix_inc_account_sufficients( + Origin::signed(H160::default()), + vec![addr_1, addr_2], + ) + .unwrap(); + + let account_1 = frame_system::Account::::get(substrate_addr_1); + let account_2 = frame_system::Account::::get(substrate_addr_2); + assert_eq!(account_1.nonce, 1); + assert_eq!(account_1.sufficients, 1); + assert_eq!(account_2.nonce, 0); + assert_eq!(account_2.sufficients, 0); + }); +} + +#[test] +fn test_hotfix_inc_account_sufficients_increments_with_saturation_if_nonce_nonzero() { + new_test_ext().execute_with(|| { + let addr = H160::from_str("1230000000000000000000000000000000000001").unwrap(); + let substrate_addr = ::AddressMapping::into_account_id(addr); + + frame_system::Account::::mutate(substrate_addr, |x| { + x.nonce = 1; + x.sufficients = u32::MAX; + }); + + let account = frame_system::Account::::get(substrate_addr); + + assert_eq!(account.sufficients, u32::MAX); + assert_eq!(account.nonce, 1); + + >::hotfix_inc_account_sufficients(Origin::signed(H160::default()), vec![addr]) + .unwrap(); + + let account = frame_system::Account::::get(substrate_addr); + assert_eq!(account.sufficients, u32::MAX); + assert_eq!(account.nonce, 1); + }); +} + +#[test] +fn test_hotfix_inc_account_sufficients_does_not_increment_if_both_nonce_and_refs_nonzero() { + new_test_ext().execute_with(|| { + let addr = H160::from_str("1230000000000000000000000000000000000001").unwrap(); + let substrate_addr = ::AddressMapping::into_account_id(addr); + + frame_system::Account::::mutate(substrate_addr, |x| { + x.nonce = 1; + x.consumers = 1; + }); + + let account = frame_system::Account::::get(substrate_addr); + + assert_eq!(account.sufficients, 0); + assert_eq!(account.nonce, 1); + assert_eq!(account.consumers, 1); + + >::hotfix_inc_account_sufficients(Origin::signed(H160::default()), vec![addr]) + .unwrap(); + + let account = frame_system::Account::::get(substrate_addr); + assert_eq!(account.sufficients, 0); + assert_eq!(account.nonce, 1); + assert_eq!(account.consumers, 1); + }); +} diff --git a/frame/hotfix-sufficients/src/weights.rs b/frame/hotfix-sufficients/src/weights.rs new file mode 100644 index 0000000000..ad50cb28f2 --- /dev/null +++ b/frame/hotfix-sufficients/src/weights.rs @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: Apache-2.0 +// This file is part of Frontier. +// +// Copyright (c) 2020 Parity Technologies (UK) Ltd. +// +// 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. + +//! Autogenerated weights for pallet_evm +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-03-03, STEPS: `32`, REPEAT: 64, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// ./target/release/frontier-template-node +// benchmark +// --chain +// dev +// --execution=wasm +// --wasm-execution=compiled +// --pallet +// pallet_hotfix_sufficients +// --extrinsic +// hotfix_inc_account_sufficients +// --steps +// 32 +// --repeat +// 64 +// --template=./benchmarking/frame-weight-template.hbs +// --record-proof +// --json-file +// raw.json +// --output +// weights.rs + +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_evm. +pub trait WeightInfo { + fn hotfix_inc_account_sufficients(n: u32) -> Weight; +} + +/// Weights for pallet_evm using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: System Account (r:31 w:31) + // Storage: System Number (r:1 w:0) + // Storage: System ExecutionPhase (r:1 w:0) + // Storage: System EventCount (r:1 w:1) + // Storage: System Events (r:1 w:1) + fn hotfix_inc_account_sufficients(n: u32) -> Weight { + (0 as Weight) + // Standard Error: 2_000 + .saturating_add((11_298_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(T::DbWeight::get().reads(4 as Weight)) + .saturating_add(T::DbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(n as Weight))) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: System Account (r:31 w:31) + // Storage: System Number (r:1 w:0) + // Storage: System ExecutionPhase (r:1 w:0) + // Storage: System EventCount (r:1 w:1) + // Storage: System Events (r:1 w:1) + fn hotfix_inc_account_sufficients(n: u32) -> Weight { + (0 as Weight) + // Standard Error: 2_000 + .saturating_add((11_298_000 as Weight).saturating_mul(n as Weight)) + .saturating_add(RocksDbWeight::get().reads(4 as Weight)) + .saturating_add(RocksDbWeight::get().reads((1 as Weight).saturating_mul(n as Weight))) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(n as Weight))) + } +} diff --git a/scripts/benchmark.sh b/scripts/benchmark.sh new file mode 100755 index 0000000000..aa75d4f934 --- /dev/null +++ b/scripts/benchmark.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +# This script can be used for running frontier's benchmarks. +# +# The frontier binary is required to be compiled with --features=runtime-benchmarks +# in release mode. + +set -e + +BINARY="./target/release/frontier-template-node" + +function choose_and_bench { + readarray -t options < <(${BINARY} benchmark pallet --list | sed 1d) + options+=('EXIT') + + select opt in "${options[@]}"; do + IFS=', ' read -ra parts <<< "${opt}" + echo "${parts[0]} -- ${parts[1]}" + [[ "${opt}" == 'EXIT' ]] && exit 0 + + bench "${parts[0]}" "${parts[1]}" + break + done +} + +function bench { + echo "benchmarking ${1}::${2}" + WASMTIME_BACKTRACE_DETAILS=1 ${BINARY} benchmark pallet \ + --chain dev \ + --execution=wasm \ + --wasm-execution=compiled \ + --pallet "${1}" \ + --extrinsic "${2}" \ + --steps 32 \ + --repeat 64 \ + --template=./benchmarking/frame-weight-template.hbs \ + --record-proof \ + --json-file raw.json \ + --output weights.rs +} + +if [[ $# -eq 1 && "${1}" == "--help" ]]; then + echo "USAGE:" + echo " ${0} [ ]" +elif [[ $# -ne 2 ]]; then + choose_and_bench +else + bench "${1}" "${2}" +fi diff --git a/template/runtime/Cargo.toml b/template/runtime/Cargo.toml index 9116e274b6..655e02f44e 100644 --- a/template/runtime/Cargo.toml +++ b/template/runtime/Cargo.toml @@ -52,6 +52,7 @@ pallet-base-fee = { path = "../../frame/base-fee", default-features = false } pallet-dynamic-fee = { path = "../../frame/dynamic-fee", default-features = false } pallet-ethereum = { path = "../../frame/ethereum", default-features = false } pallet-evm = { path = "../../frame/evm", default-features = false } +pallet-hotfix-sufficients = { path = "../../frame/hotfix-sufficients", default-features = false } pallet-evm-precompile-modexp = { path = "../../frame/evm/precompile/modexp", default-features = false } pallet-evm-precompile-sha3fips = { path = "../../frame/evm/precompile/sha3fips", default-features = false } pallet-evm-precompile-simple = { path = "../../frame/evm/precompile/simple", default-features = false } @@ -112,4 +113,5 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-ethereum/runtime-benchmarks", "pallet-evm/runtime-benchmarks", + "pallet-hotfix-sufficients/runtime-benchmarks", ] diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 8b19feba9f..ed9b991e80 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -384,6 +384,11 @@ impl pallet_base_fee::Config for Runtime { impl pallet_randomness_collective_flip::Config for Runtime {} +impl pallet_hotfix_sufficients::Config for Runtime { + type AddressMapping = HashedAddressMapping; + type WeightInfo = pallet_hotfix_sufficients::weights::SubstrateWeight; +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime where @@ -403,6 +408,7 @@ construct_runtime!( EVM: pallet_evm::{Pallet, Config, Call, Storage, Event}, DynamicFee: pallet_dynamic_fee::{Pallet, Call, Storage, Config, Inherent}, BaseFee: pallet_base_fee::{Pallet, Call, Storage, Config, Event}, + HotfixSufficients: pallet_hotfix_sufficients::{Pallet, Call}, } ); @@ -816,9 +822,11 @@ impl_runtime_apis! { ) { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; + use pallet_hotfix_sufficients::Pallet as PalletHotfixSufficients; let mut list = Vec::::new(); list_benchmarks!(list, extra); + list_benchmark!(list, extra, pallet_hotfix_sufficients, PalletHotfixSufficients::); let storage_info = AllPalletsWithSystem::storage_info(); return (list, storage_info) @@ -829,6 +837,7 @@ impl_runtime_apis! { ) -> Result, sp_runtime::RuntimeString> { use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; use pallet_evm::Pallet as PalletEvmBench; + use pallet_hotfix_sufficients::Pallet as PalletHotfixSufficients; impl frame_system_benchmarking::Config for Runtime {} let whitelist: Vec = vec![]; @@ -837,6 +846,7 @@ impl_runtime_apis! { let params = (&config, &whitelist); add_benchmark!(params, batches, pallet_evm, PalletEvmBench::); + add_benchmark!(params, batches, pallet_hotfix_sufficients, PalletHotfixSufficients::); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches)