From e14fcca936dfb18cd9d6ceb8a61522c7996cb07a Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov Date: Tue, 5 Mar 2024 18:18:29 +0300 Subject: [PATCH 1/8] Introduce account provider interface --- primitives/evm/src/account_provider.rs | 41 ++++++++++++++++++++++++++ primitives/evm/src/lib.rs | 2 ++ 2 files changed, 43 insertions(+) create mode 100644 primitives/evm/src/account_provider.rs diff --git a/primitives/evm/src/account_provider.rs b/primitives/evm/src/account_provider.rs new file mode 100644 index 0000000000..4fbd07530b --- /dev/null +++ b/primitives/evm/src/account_provider.rs @@ -0,0 +1,41 @@ +//! Custom account provider logic. + +use sp_runtime::traits::AtLeast32Bit; + +/// The account provider interface abstraction layer. +/// +/// Expose account related logic that `pallet_evm` required to control accounts existence +/// in the network and their transactions uniqueness. By default, the pallet operates native +/// system accounts records that `frame_system` provides. +/// +/// The interface allow any custom account provider logic to be used instead of +/// just using `frame_system` account provider. The accounts records should store nonce value +/// for each account at least. +pub trait AccountProvider { + /// The account identifier type. + /// + /// Represent the account itself in accounts records. + type AccountId; + /// Account index (aka nonce) type. + /// + /// The number that helps to ensure that each transaction in the network is unique + /// for particular account. + type Index: AtLeast32Bit; + + /// Creates a new account in accounts records. + /// + /// The account associated with new created address EVM. + fn create_account(who: &Self::AccountId); + /// Removes an account from accounts records. + /// + /// The account associated with removed address from EVM. + fn remove_account(who: &Self::AccountId); + /// Return current account nonce value. + /// + /// Used to represent account basic information in EVM format. + fn account_nonce(who: &Self::AccountId) -> Self::Index; + /// Increment a particular account's nonce value. + /// + /// Incremented with each new transaction submitted by the account. + fn inc_account_nonce(who: &Self::AccountId); +} diff --git a/primitives/evm/src/lib.rs b/primitives/evm/src/lib.rs index 1b436f1d05..1f5f6066aa 100644 --- a/primitives/evm/src/lib.rs +++ b/primitives/evm/src/lib.rs @@ -20,6 +20,7 @@ mod precompile; mod validation; +mod account_provider; use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}; use scale_codec::{Decode, Encode}; @@ -36,6 +37,7 @@ pub use evm::{ }; pub use self::{ + account_provider::AccountProvider, precompile::{ Context, ExitError, ExitRevert, ExitSucceed, IsPrecompileResult, LinearCostPrecompile, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, From c5fb4ca7fe884bd257c3cfba39f117fe8c559713 Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov Date: Tue, 5 Mar 2024 18:49:12 +0300 Subject: [PATCH 2/8] Use AccountProvider logic at pallet-evm --- frame/ethereum/src/mock.rs | 1 + frame/evm/precompile/dispatch/src/lib.rs | 4 +- frame/evm/precompile/dispatch/src/mock.rs | 5 +- frame/evm/src/lib.rs | 67 ++++++++++++++++------- frame/evm/src/mock.rs | 5 +- frame/evm/src/runner/stack.rs | 6 +- precompiles/src/precompile_set.rs | 2 +- precompiles/tests-external/lib.rs | 1 + primitives/evm/src/account_provider.rs | 6 +- template/runtime/src/lib.rs | 1 + 10 files changed, 66 insertions(+), 32 deletions(-) diff --git a/frame/ethereum/src/mock.rs b/frame/ethereum/src/mock.rs index 814d5e9551..70f4a20fe7 100644 --- a/frame/ethereum/src/mock.rs +++ b/frame/ethereum/src/mock.rs @@ -158,6 +158,7 @@ parameter_types! { } impl pallet_evm::Config for Test { + type AccountProvider = pallet_evm::NativeSystemAccountProvider; type FeeCalculator = FixedGasPrice; type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type WeightPerGas = WeightPerGas; diff --git a/frame/evm/precompile/dispatch/src/lib.rs b/frame/evm/precompile/dispatch/src/lib.rs index 16fadf7e91..3393064e65 100644 --- a/frame/evm/precompile/dispatch/src/lib.rs +++ b/frame/evm/precompile/dispatch/src/lib.rs @@ -54,8 +54,8 @@ impl Precompile for Dispatch + GetDispatchInfo + Decode, - ::RuntimeOrigin: From>, - DispatchValidator: DispatchValidateT, + ::RuntimeOrigin: From>>, + DispatchValidator: DispatchValidateT, T::RuntimeCall>, DecodeLimit: Get, { fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { diff --git a/frame/evm/precompile/dispatch/src/mock.rs b/frame/evm/precompile/dispatch/src/mock.rs index 01a66d779d..26917201e9 100644 --- a/frame/evm/precompile/dispatch/src/mock.rs +++ b/frame/evm/precompile/dispatch/src/mock.rs @@ -134,14 +134,15 @@ parameter_types! { pub SuicideQuickClearLimit: u32 = 0; } impl pallet_evm::Config for Test { + type AccountProvider = pallet_evm::NativeSystemAccountProvider; type FeeCalculator = FixedGasPrice; type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type WeightPerGas = WeightPerGas; type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; - type CallOrigin = EnsureAddressRoot; + type CallOrigin = EnsureAddressRoot>; - type WithdrawOrigin = EnsureAddressNever; + type WithdrawOrigin = EnsureAddressNever>; type AddressMapping = IdentityAddressMapping; type Currency = Balances; diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index 59945a4fd1..bada09f768 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -98,7 +98,7 @@ use sp_std::{cmp::min, collections::btree_map::BTreeMap, vec::Vec}; use fp_account::AccountId20; use fp_evm::GenesisAccount; pub use fp_evm::{ - Account, CallInfo, CreateInfo, ExecutionInfoV2 as ExecutionInfo, FeeCalculator, + Account, AccountProvider, CallInfo, CreateInfo, ExecutionInfoV2 as ExecutionInfo, FeeCalculator, IsPrecompileResult, LinearCostPrecompile, Log, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet, TransactionValidationError, Vicinity, }; @@ -121,6 +121,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { + /// Account info provider. + type AccountProvider: AccountProvider; + /// Calculator for current gas price. type FeeCalculator: FeeCalculator; @@ -136,12 +139,12 @@ pub mod pallet { /// Allow the origin to call on behalf of given address. type CallOrigin: EnsureAddressOrigin; /// Allow the origin to withdraw on behalf of given address. - type WithdrawOrigin: EnsureAddressOrigin; + type WithdrawOrigin: EnsureAddressOrigin>; /// Mapping from address to account id. - type AddressMapping: AddressMapping; + type AddressMapping: AddressMapping>; /// Currency type for withdraw and balance storage. - type Currency: Currency + Inspect; + type Currency: Currency> + Inspect>; /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -547,7 +550,7 @@ pub mod pallet { MAX_ACCOUNT_NONCE, UniqueSaturatedInto::::unique_saturated_into(account.nonce), ) { - frame_system::Pallet::::inc_account_nonce(&account_id); + T::AccountProvider::inc_account_nonce(&account_id); } T::Currency::deposit_creating(&account_id, account.balance.unique_saturated_into()); @@ -576,13 +579,16 @@ pub mod pallet { pub type Suicided = StorageMap<_, Blake2_128Concat, H160, (), OptionQuery>; } +/// Utility alias for easy access to the [`AccountProvider::AccountId`] type from a given config. +pub type AccountIdOf = <::AccountProvider as AccountProvider>::AccountId; + /// Type alias for currency balance. pub type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; + <::Currency as Currency>>::Balance; /// Type alias for negative imbalance during fees type NegativeImbalanceOf = - ::AccountId>>::NegativeImbalance; + >>::NegativeImbalance; #[derive( Debug, @@ -812,7 +818,7 @@ impl Pallet { // In theory, we can always have pre-EIP161 contracts, so we // make sure the account nonce is at least one. let account_id = T::AddressMapping::into_account_id(*address); - frame_system::Pallet::::inc_account_nonce(&account_id); + T::AccountProvider::inc_account_nonce(&account_id); } >::remove(address); @@ -827,7 +833,7 @@ impl Pallet { >::remove(address); let account_id = T::AddressMapping::into_account_id(*address); - let _ = frame_system::Pallet::::dec_sufficients(&account_id); + T::AccountProvider::remove_account(&account_id); } KillStorageResult::SomeRemaining(_) => (), } @@ -850,7 +856,7 @@ impl Pallet { if !>::contains_key(address) { let account_id = T::AddressMapping::into_account_id(address); - let _ = frame_system::Pallet::::inc_sufficients(&account_id); + T::AccountProvider::create_account(&account_id); } // Update metadata. @@ -891,7 +897,7 @@ impl Pallet { pub fn account_basic(address: &H160) -> (Account, frame_support::weights::Weight) { let account_id = T::AddressMapping::into_account_id(*address); - let nonce = frame_system::Pallet::::account_nonce(&account_id); + let nonce = T::AccountProvider::account_nonce(&account_id); // keepalive `true` takes into account ExistentialDeposit as part of what's considered liquid balance. let balance = T::Currency::reducible_balance(&account_id, Preservation::Preserve, Fortitude::Polite); @@ -948,17 +954,17 @@ pub struct EVMCurrencyAdapter(sp_std::marker::PhantomData<(C, OU)>); impl OnChargeEVMTransaction for EVMCurrencyAdapter where T: Config, - C: Currency<::AccountId>, + C: Currency>, C::PositiveImbalance: Imbalance< - ::AccountId>>::Balance, + >>::Balance, Opposite = C::NegativeImbalance, >, C::NegativeImbalance: Imbalance< - ::AccountId>>::Balance, + >>::Balance, Opposite = C::PositiveImbalance, >, OU: OnUnbalanced>, - U256: UniqueSaturatedInto<::AccountId>>::Balance>, + U256: UniqueSaturatedInto<>>::Balance>, { // Kept type as Option to satisfy bound of Default type LiquidityInfo = Option>; @@ -1042,10 +1048,10 @@ where impl OnChargeEVMTransaction for () where T: Config, - ::AccountId>>::PositiveImbalance: - Imbalance<::AccountId>>::Balance, Opposite = ::AccountId>>::NegativeImbalance>, - ::AccountId>>::NegativeImbalance: -Imbalance<::AccountId>>::Balance, Opposite = ::AccountId>>::PositiveImbalance>, + >>::PositiveImbalance: + Imbalance<>>::Balance, Opposite = >>::NegativeImbalance>, + >>::NegativeImbalance: +Imbalance<>>::Balance, Opposite = >>::PositiveImbalance>, U256: UniqueSaturatedInto>, { @@ -1089,3 +1095,26 @@ impl OnCreate for Tuple { )*) } } + +/// Native system account provider that `frame_system` provides. +pub struct NativeSystemAccountProvider(sp_std::marker::PhantomData); + +impl AccountProvider for NativeSystemAccountProvider { + type AccountId = T::AccountId; + type Nonce = T::Nonce; + + fn account_nonce(who: &Self::AccountId) -> Self::Nonce { + frame_system::Pallet::::account_nonce(&who) + } + + fn inc_account_nonce(who: &Self::AccountId) { + frame_system::Pallet::::inc_account_nonce(&who) + } + + fn create_account(who: &Self::AccountId) { + let _ = frame_system::Pallet::::inc_sufficients(&who); + } + fn remove_account(who: &Self::AccountId) { + let _ = frame_system::Pallet::::dec_sufficients(&who); + } +} diff --git a/frame/evm/src/mock.rs b/frame/evm/src/mock.rs index 1249f62620..56e0b4e69f 100644 --- a/frame/evm/src/mock.rs +++ b/frame/evm/src/mock.rs @@ -132,14 +132,15 @@ parameter_types! { pub SuicideQuickClearLimit: u32 = 0; } impl crate::Config for Test { + type AccountProvider = crate::NativeSystemAccountProvider; type FeeCalculator = FixedGasPrice; type GasWeightMapping = crate::FixedGasWeightMapping; type WeightPerGas = WeightPerGas; type BlockHashMapping = crate::SubstrateBlockHashMapping; - type CallOrigin = EnsureAddressRoot; + type CallOrigin = EnsureAddressRoot>; - type WithdrawOrigin = EnsureAddressNever; + type WithdrawOrigin = EnsureAddressNever>; type AddressMapping = IdentityAddressMapping; type Currency = Balances; diff --git a/frame/evm/src/runner/stack.rs b/frame/evm/src/runner/stack.rs index ab4be0b068..5b135ddc01 100644 --- a/frame/evm/src/runner/stack.rs +++ b/frame/evm/src/runner/stack.rs @@ -48,8 +48,8 @@ use fp_evm::{ }; use crate::{ - runner::Runner as RunnerT, AccountCodes, AccountCodesMetadata, AccountStorages, AddressMapping, - BalanceOf, BlockHashMapping, Config, Error, Event, FeeCalculator, OnChargeEVMTransaction, + runner::Runner as RunnerT, AccountCodes, AccountCodesMetadata, AccountProvider, AccountStorages, + AddressMapping, BalanceOf, BlockHashMapping, Config, Error, Event, FeeCalculator, OnChargeEVMTransaction, OnCreate, Pallet, RunnerError, }; @@ -841,7 +841,7 @@ where fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError> { let account_id = T::AddressMapping::into_account_id(address); - frame_system::Pallet::::inc_account_nonce(&account_id); + T::AccountProvider::inc_account_nonce(&account_id); Ok(()) } diff --git a/precompiles/src/precompile_set.rs b/precompiles/src/precompile_set.rs index ebe2d11cfd..d3a7087423 100644 --- a/precompiles/src/precompile_set.rs +++ b/precompiles/src/precompile_set.rs @@ -1088,7 +1088,7 @@ impl PrecompileSetBuilder } /// Return the list of addresses contained in this PrecompileSet. - pub fn used_addresses() -> impl Iterator { + pub fn used_addresses() -> impl Iterator> { Self::new() .inner .used_addresses() diff --git a/precompiles/tests-external/lib.rs b/precompiles/tests-external/lib.rs index 42a7682f91..e6e7e03b2e 100644 --- a/precompiles/tests-external/lib.rs +++ b/precompiles/tests-external/lib.rs @@ -225,6 +225,7 @@ parameter_types! { } impl pallet_evm::Config for Runtime { + type AccountProvider = pallet_evm::NativeSystemAccountProvider; type FeeCalculator = (); type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type WeightPerGas = WeightPerGas; diff --git a/primitives/evm/src/account_provider.rs b/primitives/evm/src/account_provider.rs index 4fbd07530b..545e763429 100644 --- a/primitives/evm/src/account_provider.rs +++ b/primitives/evm/src/account_provider.rs @@ -16,11 +16,11 @@ pub trait AccountProvider { /// /// Represent the account itself in accounts records. type AccountId; - /// Account index (aka nonce) type. + /// Account nonce type. /// /// The number that helps to ensure that each transaction in the network is unique /// for particular account. - type Index: AtLeast32Bit; + type Nonce: AtLeast32Bit; /// Creates a new account in accounts records. /// @@ -33,7 +33,7 @@ pub trait AccountProvider { /// Return current account nonce value. /// /// Used to represent account basic information in EVM format. - fn account_nonce(who: &Self::AccountId) -> Self::Index; + fn account_nonce(who: &Self::AccountId) -> Self::Nonce; /// Increment a particular account's nonce value. /// /// Incremented with each new transaction submitted by the account. diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 9684ebf008..56b45817d1 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -330,6 +330,7 @@ parameter_types! { } impl pallet_evm::Config for Runtime { + type AccountProvider = pallet_evm::NativeSystemAccountProvider; type FeeCalculator = BaseFee; type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type WeightPerGas = WeightPerGas; From 3278d0b0aa5c4c547d7025be2b680f7ca59d4d2a Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov Date: Tue, 5 Mar 2024 18:54:35 +0300 Subject: [PATCH 3/8] Remove redundant ower type usage --- frame/evm/precompile/dispatch/src/mock.rs | 4 ++-- frame/evm/src/mock.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/evm/precompile/dispatch/src/mock.rs b/frame/evm/precompile/dispatch/src/mock.rs index 26917201e9..6f0cea64cc 100644 --- a/frame/evm/precompile/dispatch/src/mock.rs +++ b/frame/evm/precompile/dispatch/src/mock.rs @@ -140,9 +140,9 @@ impl pallet_evm::Config for Test { type WeightPerGas = WeightPerGas; type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping; - type CallOrigin = EnsureAddressRoot>; + type CallOrigin = EnsureAddressRoot; - type WithdrawOrigin = EnsureAddressNever>; + type WithdrawOrigin = EnsureAddressNever; type AddressMapping = IdentityAddressMapping; type Currency = Balances; diff --git a/frame/evm/src/mock.rs b/frame/evm/src/mock.rs index 56e0b4e69f..e61f9b4d47 100644 --- a/frame/evm/src/mock.rs +++ b/frame/evm/src/mock.rs @@ -138,9 +138,9 @@ impl crate::Config for Test { type WeightPerGas = WeightPerGas; type BlockHashMapping = crate::SubstrateBlockHashMapping; - type CallOrigin = EnsureAddressRoot>; + type CallOrigin = EnsureAddressRoot; - type WithdrawOrigin = EnsureAddressNever>; + type WithdrawOrigin = EnsureAddressNever; type AddressMapping = IdentityAddressMapping; type Currency = Balances; From 68b23ec614fecb10cbea67601b32cd9d59622cb0 Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov Date: Tue, 5 Mar 2024 19:42:32 +0300 Subject: [PATCH 4/8] Fix fmt --- frame/evm/src/lib.rs | 47 ++++++++++++++++------------------- frame/evm/src/runner/stack.rs | 6 ++--- primitives/evm/src/lib.rs | 2 +- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index bada09f768..d0cd2478dc 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -98,9 +98,10 @@ use sp_std::{cmp::min, collections::btree_map::BTreeMap, vec::Vec}; use fp_account::AccountId20; use fp_evm::GenesisAccount; pub use fp_evm::{ - Account, AccountProvider, CallInfo, CreateInfo, ExecutionInfoV2 as ExecutionInfo, FeeCalculator, - IsPrecompileResult, LinearCostPrecompile, Log, Precompile, PrecompileFailure, PrecompileHandle, - PrecompileOutput, PrecompileResult, PrecompileSet, TransactionValidationError, Vicinity, + Account, AccountProvider, CallInfo, CreateInfo, ExecutionInfoV2 as ExecutionInfo, + FeeCalculator, IsPrecompileResult, LinearCostPrecompile, Log, Precompile, PrecompileFailure, + PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet, + TransactionValidationError, Vicinity, }; pub use self::{ @@ -583,12 +584,10 @@ pub mod pallet { pub type AccountIdOf = <::AccountProvider as AccountProvider>::AccountId; /// Type alias for currency balance. -pub type BalanceOf = - <::Currency as Currency>>::Balance; +pub type BalanceOf = <::Currency as Currency>>::Balance; /// Type alias for negative imbalance during fees -type NegativeImbalanceOf = - >>::NegativeImbalance; +type NegativeImbalanceOf = >>::NegativeImbalance; #[derive( Debug, @@ -955,14 +954,10 @@ impl OnChargeEVMTransaction for EVMCurrencyAdapter where T: Config, C: Currency>, - C::PositiveImbalance: Imbalance< - >>::Balance, - Opposite = C::NegativeImbalance, - >, - C::NegativeImbalance: Imbalance< - >>::Balance, - Opposite = C::PositiveImbalance, - >, + C::PositiveImbalance: + Imbalance<>>::Balance, Opposite = C::NegativeImbalance>, + C::NegativeImbalance: + Imbalance<>>::Balance, Opposite = C::PositiveImbalance>, OU: OnUnbalanced>, U256: UniqueSaturatedInto<>>::Balance>, { @@ -1046,22 +1041,22 @@ where /// Implementation for () does not specify what to do with imbalance impl OnChargeEVMTransaction for () - where +where T: Config, - >>::PositiveImbalance: - Imbalance<>>::Balance, Opposite = >>::NegativeImbalance>, - >>::NegativeImbalance: -Imbalance<>>::Balance, Opposite = >>::PositiveImbalance>, -U256: UniqueSaturatedInto>, - + >>::PositiveImbalance: Imbalance< + >>::Balance, + Opposite = >>::NegativeImbalance, + >, + >>::NegativeImbalance: Imbalance< + >>::Balance, + Opposite = >>::PositiveImbalance, + >, + U256: UniqueSaturatedInto>, { // Kept type as Option to satisfy bound of Default type LiquidityInfo = Option>; - fn withdraw_fee( - who: &H160, - fee: U256, - ) -> Result> { + fn withdraw_fee(who: &H160, fee: U256) -> Result> { EVMCurrencyAdapter::<::Currency, ()>::withdraw_fee(who, fee) } diff --git a/frame/evm/src/runner/stack.rs b/frame/evm/src/runner/stack.rs index 5b135ddc01..8b0a80f4ce 100644 --- a/frame/evm/src/runner/stack.rs +++ b/frame/evm/src/runner/stack.rs @@ -48,9 +48,9 @@ use fp_evm::{ }; use crate::{ - runner::Runner as RunnerT, AccountCodes, AccountCodesMetadata, AccountProvider, AccountStorages, - AddressMapping, BalanceOf, BlockHashMapping, Config, Error, Event, FeeCalculator, OnChargeEVMTransaction, - OnCreate, Pallet, RunnerError, + runner::Runner as RunnerT, AccountCodes, AccountCodesMetadata, AccountProvider, + AccountStorages, AddressMapping, BalanceOf, BlockHashMapping, Config, Error, Event, + FeeCalculator, OnChargeEVMTransaction, OnCreate, Pallet, RunnerError, }; #[cfg(feature = "forbid-evm-reentrancy")] diff --git a/primitives/evm/src/lib.rs b/primitives/evm/src/lib.rs index 1f5f6066aa..411489c076 100644 --- a/primitives/evm/src/lib.rs +++ b/primitives/evm/src/lib.rs @@ -18,9 +18,9 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(unused_crate_dependencies)] +mod account_provider; mod precompile; mod validation; -mod account_provider; use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}; use scale_codec::{Decode, Encode}; From 198623bb80d48c46126d1ada5a2bc1e2efb3d8d2 Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov Date: Tue, 5 Mar 2024 20:16:51 +0300 Subject: [PATCH 5/8] Fix clippy --- frame/evm/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index d0cd2478dc..adef13dffa 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -1099,17 +1099,17 @@ impl AccountProvider for NativeSystemAccountProvider type Nonce = T::Nonce; fn account_nonce(who: &Self::AccountId) -> Self::Nonce { - frame_system::Pallet::::account_nonce(&who) + frame_system::Pallet::::account_nonce(who) } fn inc_account_nonce(who: &Self::AccountId) { - frame_system::Pallet::::inc_account_nonce(&who) + frame_system::Pallet::::inc_account_nonce(who) } fn create_account(who: &Self::AccountId) { - let _ = frame_system::Pallet::::inc_sufficients(&who); + let _ = frame_system::Pallet::::inc_sufficients(who); } fn remove_account(who: &Self::AccountId) { - let _ = frame_system::Pallet::::dec_sufficients(&who); + let _ = frame_system::Pallet::::dec_sufficients(who); } } From 20d85a5dd17012e6b607974508c73ff7e1ab9f48 Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov Date: Wed, 6 Mar 2024 22:08:43 +0300 Subject: [PATCH 6/8] Implement sovereign accounts and EVM system layer --- Cargo.lock | 16 ++ Cargo.toml | 2 + frame/evm-system/Cargo.toml | 45 ++++++ frame/evm-system/src/lib.rs | 262 ++++++++++++++++++++++++++++++ frame/evm-system/src/mock.rs | 132 +++++++++++++++ frame/evm-system/src/tests.rs | 297 ++++++++++++++++++++++++++++++++++ 6 files changed, 754 insertions(+) create mode 100644 frame/evm-system/Cargo.toml create mode 100644 frame/evm-system/src/lib.rs create mode 100644 frame/evm-system/src/mock.rs create mode 100644 frame/evm-system/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 680d145410..3502596c51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5800,6 +5800,22 @@ dependencies = [ "sp-io", ] +[[package]] +name = "pallet-evm-system" +version = "1.0.0-dev" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "mockall", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 14.0.0 (git+https://github.com/paritytech/polkadot-sdk?branch=release-polkadot-v1.7.0)", +] + [[package]] name = "pallet-evm-test-vector-support" version = "1.0.0-dev" diff --git a/Cargo.toml b/Cargo.toml index 10dfb195ef..1973cb9d99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "frame/ethereum", "frame/evm", "frame/evm-chain-id", + "frame/evm-system", "frame/hotfix-sufficients", "frame/evm/precompile/sha3fips", "frame/evm/precompile/simple", @@ -62,6 +63,7 @@ jsonrpsee = "0.20.3" kvdb-rocksdb = "0.19.0" libsecp256k1 = { version = "0.7.1", default-features = false } log = { version = "0.4.21", default-features = false } +mockall = "0.11" num_enum = { version = "0.7.2", default-features = false } parity-db = "0.4.13" parking_lot = "0.12.1" diff --git a/frame/evm-system/Cargo.toml b/frame/evm-system/Cargo.toml new file mode 100644 index 0000000000..d387383bcc --- /dev/null +++ b/frame/evm-system/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "pallet-evm-system" +version = "1.0.0-dev" +license = "Apache-2.0" +description = "FRAME EVM SYSTEM pallet." +authors = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +scale-codec = { package = "parity-scale-codec", workspace = true } +scale-info = { workspace = true } +# Substrate +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +# Frontier +fp-evm = { workspace = true } + +[dev-dependencies] +mockall = { workspace = true } +sp-core = { workspace = true } +sp-io = { workspace = true } + +[features] +default = ["std"] +std = [ + "scale-codec/std", + "scale-info/std", + # Substrate + "frame-support/std", + "frame-system/std", + "sp-runtime/std", + "sp-std/std", + # Frontier + "fp-evm/std", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/frame/evm-system/src/lib.rs b/frame/evm-system/src/lib.rs new file mode 100644 index 0000000000..b957e49673 --- /dev/null +++ b/frame/evm-system/src/lib.rs @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: Apache-2.0 +// This file is part of Frontier. +// +// Copyright (c) 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. +// SPDX-License-Identifier: Apache-2.0 + +//! # EVM System Pallet. + +// Ensure we're `no_std` when compiling for Wasm. +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::traits::StoredMap; +use scale_codec::{Decode, Encode, FullCodec, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_runtime::{traits::One, DispatchError, DispatchResult, RuntimeDebug}; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +pub use pallet::*; + +/// Account information. +#[derive( + Clone, + Eq, + PartialEq, + Default, + RuntimeDebug, + Encode, + Decode, + TypeInfo, + MaxEncodedLen +)] +pub struct AccountInfo { + /// The number of transactions this account has sent. + pub nonce: Nonce, + /// The additional data that belongs to this account. Used to store the balance(s) in a lot of + /// chains. + pub data: AccountData, +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use sp_runtime::traits::{AtLeast32Bit, MaybeDisplay}; + use sp_std::fmt::Debug; + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData); + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The user account identifier type. + type AccountId: Parameter + + Member + + MaybeSerializeDeserialize + + Debug + + MaybeDisplay + + Ord + + MaxEncodedLen; + + /// This stores the number of previous transactions associated with a sender account. + type Nonce: Parameter + + Member + + MaybeSerializeDeserialize + + Debug + + Default + + MaybeDisplay + + AtLeast32Bit + + Copy + + MaxEncodedLen; + + /// Data to be associated with an account (other than nonce/transaction counter, which this + /// pallet does regardless). + type AccountData: Member + FullCodec + Clone + Default + TypeInfo + MaxEncodedLen; + + /// Handler for when a new account has just been created. + type OnNewAccount: OnNewAccount<::AccountId>; + + /// A function that is invoked when an account has been determined to be dead. + /// + /// All resources should be cleaned up associated with the given account. + type OnKilledAccount: OnKilledAccount<::AccountId>; + } + + /// The full account information for a particular account ID. + #[pallet::storage] + pub type Account = StorageMap< + _, + Blake2_128Concat, + ::AccountId, + AccountInfo<::Nonce, ::AccountData>, + ValueQuery, + >; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A new account was created. + NewAccount { account: ::AccountId }, + /// An account was reaped. + KilledAccount { account: ::AccountId }, + } + + #[pallet::error] + pub enum Error { + /// The account already exists in case creating it. + AccountAlreadyExist, + /// The account doesn't exist in case removing it. + AccountNotExist, + } +} + +impl Pallet { + /// Check the account existence. + pub fn account_exists(who: &::AccountId) -> bool { + Account::::contains_key(who) + } + + /// An account is being created. + fn on_created_account(who: ::AccountId) { + ::OnNewAccount::on_new_account(&who); + Self::deposit_event(Event::NewAccount { account: who }); + } + + /// Do anything that needs to be done after an account has been killed. + fn on_killed_account(who: ::AccountId) { + ::OnKilledAccount::on_killed_account(&who); + Self::deposit_event(Event::KilledAccount { account: who }); + } + + /// Retrieve the account transaction counter from storage. + pub fn account_nonce(who: &::AccountId) -> ::Nonce { + Account::::get(who).nonce + } + + /// Increment a particular account's nonce by 1. + pub fn inc_account_nonce(who: &::AccountId) { + Account::::mutate(who, |a| a.nonce += ::Nonce::one()); + } + + /// Create an account. + pub fn create_account(who: &::AccountId) -> DispatchResult { + if Self::account_exists(who) { + return Err(Error::::AccountAlreadyExist.into()); + } + + Account::::insert(who.clone(), AccountInfo::<_, _>::default()); + Self::on_created_account(who.clone()); + Ok(()) + } + + /// Remove an account. + pub fn remove_account(who: &::AccountId) -> DispatchResult { + if !Self::account_exists(who) { + return Err(Error::::AccountNotExist.into()); + } + + Account::::remove(who); + Self::on_killed_account(who.clone()); + Ok(()) + } +} + +impl StoredMap<::AccountId, ::AccountData> for Pallet { + fn get(k: &::AccountId) -> ::AccountData { + Account::::get(k).data + } + + fn try_mutate_exists>( + k: &::AccountId, + f: impl FnOnce(&mut Option<::AccountData>) -> Result, + ) -> Result { + let (mut maybe_account_data, was_providing) = if Self::account_exists(k) { + (Some(Account::::get(k).data), true) + } else { + (None, false) + }; + + let result = f(&mut maybe_account_data)?; + + match (maybe_account_data, was_providing) { + (Some(data), false) => { + Account::::mutate(k, |a| a.data = data); + Self::on_created_account(k.clone()); + } + (Some(data), true) => { + Account::::mutate(k, |a| a.data = data); + } + (None, true) => { + Account::::remove(k); + Self::on_killed_account(k.clone()); + } + (None, false) => { + // Do nothing. + } + } + + Ok(result) + } +} + +impl fp_evm::AccountProvider for Pallet { + type AccountId = ::AccountId; + type Nonce = ::Nonce; + + fn create_account(who: &Self::AccountId) { + let _ = Self::create_account(who); + } + + fn remove_account(who: &Self::AccountId) { + let _ = Self::remove_account(who); + } + + fn account_nonce(who: &Self::AccountId) -> Self::Nonce { + Self::account_nonce(who) + } + + fn inc_account_nonce(who: &Self::AccountId) { + Self::inc_account_nonce(who); + } +} + +/// Interface to handle account creation. +pub trait OnNewAccount { + /// A new account `who` has been registered. + fn on_new_account(who: &AccountId); +} + +impl OnNewAccount for () { + fn on_new_account(_who: &AccountId) {} +} + +/// Interface to handle account killing. +pub trait OnKilledAccount { + /// The account with the given id was reaped. + fn on_killed_account(who: &AccountId); +} + +impl OnKilledAccount for () { + fn on_killed_account(_who: &AccountId) {} +} diff --git a/frame/evm-system/src/mock.rs b/frame/evm-system/src/mock.rs new file mode 100644 index 0000000000..a0ba0cef3c --- /dev/null +++ b/frame/evm-system/src/mock.rs @@ -0,0 +1,132 @@ +// 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. + +//! Test mock for unit tests. + +use frame_support::traits::{ConstU32, ConstU64}; +use mockall::{mock, predicate::*}; +use sp_core::{H160, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, IdentityLookup}, + BuildStorage, +}; +use sp_std::{boxed::Box, prelude::*}; + +use crate::{self as pallet_evm_system, *}; + +mock! { + #[derive(Debug)] + pub DummyOnNewAccount {} + + impl OnNewAccount for DummyOnNewAccount { + pub fn on_new_account(who: &H160); + } +} + +mock! { + #[derive(Debug)] + pub DummyOnKilledAccount {} + + impl OnKilledAccount for DummyOnKilledAccount { + pub fn on_killed_account(who: &H160); + } +} + +frame_support::construct_runtime! { + pub enum Test { + System: frame_system, + EvmSystem: pallet_evm_system, + } +} + +impl frame_system::Config for Test { + type RuntimeEvent = RuntimeEvent; + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type RuntimeTask = RuntimeTask; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = H160; + type Lookup = IdentityLookup; + type Block = frame_system::mocking::MockBlock; + type BlockHashCount = ConstU64<250>; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = (); + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_evm_system::Config for Test { + type RuntimeEvent = RuntimeEvent; + type AccountId = H160; + type Nonce = u64; + type AccountData = u64; + type OnNewAccount = MockDummyOnNewAccount; + type OnKilledAccount = MockDummyOnKilledAccount; +} + +/// Build test externalities from the custom genesis. +/// Using this call requires manual assertions on the genesis init logic. +pub fn new_test_ext() -> sp_io::TestExternalities { + // Build genesis. + let config = RuntimeGenesisConfig { + ..Default::default() + }; + let storage = config.build_storage().unwrap(); + + // Make test externalities from the storage. + storage.into() +} + +pub fn runtime_lock() -> std::sync::MutexGuard<'static, ()> { + static MOCK_RUNTIME_MUTEX: std::sync::Mutex<()> = std::sync::Mutex::new(()); + + // Ignore the poisoning for the tests that panic. + // We only care about concurrency here, not about the poisoning. + match MOCK_RUNTIME_MUTEX.lock() { + Ok(guard) => guard, + Err(poisoned) => poisoned.into_inner(), + } +} + +pub trait TestExternalitiesExt { + fn execute_with_ext(&mut self, execute: E) -> R + where + E: for<'e> FnOnce(&'e ()) -> R; +} + +impl TestExternalitiesExt for sp_io::TestExternalities { + fn execute_with_ext(&mut self, execute: E) -> R + where + E: for<'e> FnOnce(&'e ()) -> R, + { + let guard = runtime_lock(); + let result = self.execute_with(|| execute(&guard)); + drop(guard); + result + } +} diff --git a/frame/evm-system/src/tests.rs b/frame/evm-system/src/tests.rs new file mode 100644 index 0000000000..b175d5e6c0 --- /dev/null +++ b/frame/evm-system/src/tests.rs @@ -0,0 +1,297 @@ +//! Unit tests. + +use sp_std::str::FromStr; + +use frame_support::{assert_noop, assert_ok}; +use mockall::predicate; +use sp_core::H160; + +use crate::{mock::*, *}; + +/// This test verifies that creating account works in the happy path. +#[test] +fn create_account_works() { + new_test_ext().execute_with_ext(|_| { + // Prepare test data. + let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); + + // Check test preconditions. + assert!(!EvmSystem::account_exists(&account_id)); + + // Set block number to enable events. + System::set_block_number(1); + + // Set mock expectations. + let on_new_account_ctx = MockDummyOnNewAccount::on_new_account_context(); + on_new_account_ctx + .expect() + .once() + .with(predicate::eq(account_id)) + .return_const(()); + + // Invoke the function under test. + assert_ok!(EvmSystem::create_account(&account_id)); + + // Assert state changes. + assert!(EvmSystem::account_exists(&account_id)); + System::assert_has_event(RuntimeEvent::EvmSystem(Event::NewAccount { + account: account_id, + })); + + // Assert mock invocations. + on_new_account_ctx.checkpoint(); + }); +} + +/// This test verifies that creating account fails when the account already exists. +#[test] +fn create_account_fails() { + new_test_ext().execute_with_ext(|_| { + // Prepare test data. + let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); + >::insert(account_id.clone(), AccountInfo::<_, _>::default()); + + // Invoke the function under test. + assert_noop!( + EvmSystem::create_account(&account_id), + Error::::AccountAlreadyExist + ); + }); +} + +/// This test verifies that removing account works in the happy path. +#[test] +fn remove_account_works() { + new_test_ext().execute_with_ext(|_| { + // Prepare test data. + let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); + >::insert(account_id.clone(), AccountInfo::<_, _>::default()); + + // Set block number to enable events. + System::set_block_number(1); + + // Set mock expectations. + let on_killed_account_ctx = MockDummyOnKilledAccount::on_killed_account_context(); + on_killed_account_ctx + .expect() + .once() + .with(predicate::eq(account_id)) + .return_const(()); + + // Invoke the function under test. + assert_ok!(EvmSystem::remove_account(&account_id)); + + // Assert state changes. + assert!(!EvmSystem::account_exists(&account_id)); + System::assert_has_event(RuntimeEvent::EvmSystem(Event::KilledAccount { + account: account_id, + })); + + // Assert mock invocations. + on_killed_account_ctx.checkpoint(); + }); +} + +/// This test verifies that removing account fails when the account doesn't exist. +#[test] +fn remove_account_fails() { + new_test_ext().execute_with_ext(|_| { + // Prepare test data. + let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); + + // Invoke the function under test. + assert_noop!( + EvmSystem::remove_account(&account_id), + Error::::AccountNotExist + ); + }); +} + +/// This test verifies that incrementing account nonce works in the happy path. +#[test] +fn inc_account_nonce_works() { + new_test_ext().execute_with_ext(|_| { + // Prepare test data. + let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); + + // Check test preconditions. + let nonce_before = EvmSystem::account_nonce(&account_id); + + // Invoke the function under test. + EvmSystem::inc_account_nonce(&account_id); + + // Assert state changes. + assert_eq!(EvmSystem::account_nonce(&account_id), nonce_before + 1); + }); +} + +/// This test verifies that try_mutate_exists works as expected in case data wasn't providing +/// and returned data is `Some`. As a result, a new account has been created. +#[test] +fn try_mutate_exists_account_created() { + new_test_ext().execute_with_ext(|_| { + // Prepare test data. + let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); + + // Check test preconditions. + assert!(!EvmSystem::account_exists(&account_id)); + + // Set mock expectations. + let on_new_account_ctx = MockDummyOnNewAccount::on_new_account_context(); + on_new_account_ctx + .expect() + .once() + .with(predicate::eq(account_id)) + .return_const(()); + + // Set block number to enable events. + System::set_block_number(1); + + // Invoke the function under test. + EvmSystem::try_mutate_exists(&account_id, |maybe_data| -> Result<(), DispatchError> { + *maybe_data = Some(1); + Ok(()) + }) + .unwrap(); + + // Assert state changes. + assert!(EvmSystem::account_exists(&account_id)); + assert_eq!(EvmSystem::get(&account_id), 1); + System::assert_has_event(RuntimeEvent::EvmSystem(Event::NewAccount { + account: account_id, + })); + + // Assert mock invocations. + on_new_account_ctx.checkpoint(); + }); +} + +/// This test verifies that try_mutate_exists works as expected in case data was providing +/// and returned data is `Some`. As a result, the account has been updated. +#[test] +fn try_mutate_exists_account_updated() { + new_test_ext().execute_with_ext(|_| { + // Prepare test data. + let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); + let nonce = 1; + let data = 1; + >::insert(account_id.clone(), AccountInfo { nonce, data }); + + // Check test preconditions. + assert!(EvmSystem::account_exists(&account_id)); + + // Set block number to enable events. + System::set_block_number(1); + + // Invoke the function under test. + EvmSystem::try_mutate_exists(&account_id, |maybe_data| -> Result<(), DispatchError> { + if let Some(ref mut data) = maybe_data { + *data += 1; + } + Ok(()) + }) + .unwrap(); + + // Assert state changes. + assert!(EvmSystem::account_exists(&account_id)); + assert_eq!(EvmSystem::get(&account_id), data + 1); + }); +} + +/// This test verifies that try_mutate_exists works as expected in case data was providing +/// and returned data is `None`. As a result, the account has been removed. +#[test] +fn try_mutate_exists_account_removed() { + new_test_ext().execute_with_ext(|_| { + // Prepare test data. + let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); + let nonce = 1; + let data = 1; + >::insert(account_id.clone(), AccountInfo { nonce, data }); + + // Check test preconditions. + assert!(EvmSystem::account_exists(&account_id)); + + // Set mock expectations. + let on_killed_account_ctx = MockDummyOnKilledAccount::on_killed_account_context(); + on_killed_account_ctx + .expect() + .once() + .with(predicate::eq(account_id)) + .return_const(()); + + // Set block number to enable events. + System::set_block_number(1); + + // Invoke the function under test. + EvmSystem::try_mutate_exists(&account_id, |maybe_data| -> Result<(), DispatchError> { + *maybe_data = None; + Ok(()) + }) + .unwrap(); + + // Assert state changes. + assert!(!EvmSystem::account_exists(&account_id)); + System::assert_has_event(RuntimeEvent::EvmSystem(Event::KilledAccount { + account: account_id, + })); + + // Assert mock invocations. + on_killed_account_ctx.checkpoint(); + }); +} + +/// This test verifies that try_mutate_exists works as expected in case data wasn't providing +/// and returned data is `None`. As a result, the account hasn't been created. +#[test] +fn try_mutate_exists_account_not_created() { + new_test_ext().execute_with_ext(|_| { + // Prepare test data. + let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); + + // Check test preconditions. + assert!(!EvmSystem::account_exists(&account_id)); + + // Set block number to enable events. + System::set_block_number(1); + + // Invoke the function under test. + >::try_mutate_exists(account_id, |maybe_data| -> Result<(), ()> { + *maybe_data = None; + Ok(()) + }) + .unwrap(); + + // Assert state changes. + assert!(!EvmSystem::account_exists(&account_id)); + }); +} + +/// This test verifies that try_mutate_exists works as expected in case getting error +/// during data mutation. +#[test] +fn try_mutate_exists_fails_without_changes() { + new_test_ext().execute_with_ext(|_| { + // Prepare test data. + let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); + let nonce = 1; + let data = 1; + >::insert(account_id.clone(), AccountInfo { nonce, data }); + + // Check test preconditions. + assert!(EvmSystem::account_exists(&account_id)); + + // Invoke the function under test. + assert_noop!( + >::try_mutate_exists(account_id, |maybe_data| -> Result<(), ()> { + *maybe_data = None; + Err(()) + }), + () + ); + + // Assert state changes. + assert!(EvmSystem::account_exists(&account_id)); + assert_eq!(EvmSystem::get(&account_id), data); + }); +} From 30a727522e54a2ee8c20d33fda5ebdd30e129760 Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov Date: Wed, 6 Mar 2024 22:51:24 +0300 Subject: [PATCH 7/8] Fix fmt --- frame/evm-system/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frame/evm-system/Cargo.toml b/frame/evm-system/Cargo.toml index d387383bcc..9e4b5a39e0 100644 --- a/frame/evm-system/Cargo.toml +++ b/frame/evm-system/Cargo.toml @@ -37,7 +37,7 @@ std = [ "sp-runtime/std", "sp-std/std", # Frontier - "fp-evm/std", + "fp-evm/std", ] try-runtime = [ "frame-support/try-runtime", From 959632f9c6abebe118b272222397bf6c18a89c23 Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov Date: Wed, 6 Mar 2024 23:30:21 +0300 Subject: [PATCH 8/8] Fix clippy --- frame/evm-system/src/tests.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frame/evm-system/src/tests.rs b/frame/evm-system/src/tests.rs index b175d5e6c0..a322f4e27d 100644 --- a/frame/evm-system/src/tests.rs +++ b/frame/evm-system/src/tests.rs @@ -49,7 +49,7 @@ fn create_account_fails() { new_test_ext().execute_with_ext(|_| { // Prepare test data. let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); - >::insert(account_id.clone(), AccountInfo::<_, _>::default()); + >::insert(account_id, AccountInfo::<_, _>::default()); // Invoke the function under test. assert_noop!( @@ -65,7 +65,7 @@ fn remove_account_works() { new_test_ext().execute_with_ext(|_| { // Prepare test data. let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); - >::insert(account_id.clone(), AccountInfo::<_, _>::default()); + >::insert(account_id, AccountInfo::<_, _>::default()); // Set block number to enable events. System::set_block_number(1); @@ -175,7 +175,7 @@ fn try_mutate_exists_account_updated() { let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); let nonce = 1; let data = 1; - >::insert(account_id.clone(), AccountInfo { nonce, data }); + >::insert(account_id, AccountInfo { nonce, data }); // Check test preconditions. assert!(EvmSystem::account_exists(&account_id)); @@ -207,7 +207,7 @@ fn try_mutate_exists_account_removed() { let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); let nonce = 1; let data = 1; - >::insert(account_id.clone(), AccountInfo { nonce, data }); + >::insert(account_id, AccountInfo { nonce, data }); // Check test preconditions. assert!(EvmSystem::account_exists(&account_id)); @@ -276,7 +276,7 @@ fn try_mutate_exists_fails_without_changes() { let account_id = H160::from_str("1000000000000000000000000000000000000001").unwrap(); let nonce = 1; let data = 1; - >::insert(account_id.clone(), AccountInfo { nonce, data }); + >::insert(account_id, AccountInfo { nonce, data }); // Check test preconditions. assert!(EvmSystem::account_exists(&account_id));