diff --git a/frame/ethereum/src/mock.rs b/frame/ethereum/src/mock.rs index 332549ddd0..6da28a4b77 100644 --- a/frame/ethereum/src/mock.rs +++ b/frame/ethereum/src/mock.rs @@ -159,6 +159,7 @@ parameter_types! { } impl pallet_evm::Config for Test { + type AccountProvider = pallet_evm::FrameSystemAccountProvider; 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 b7be946b93..78279a82bc 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 d2fce9dc8d..7a921371a8 100644 --- a/frame/evm/precompile/dispatch/src/mock.rs +++ b/frame/evm/precompile/dispatch/src/mock.rs @@ -136,6 +136,7 @@ parameter_types! { pub SuicideQuickClearLimit: u32 = 0; } impl pallet_evm::Config for Test { + type AccountProvider = pallet_evm::FrameSystemAccountProvider; type FeeCalculator = FixedGasPrice; type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type WeightPerGas = WeightPerGas; diff --git a/frame/evm/precompile/storage-cleaner/src/lib.rs b/frame/evm/precompile/storage-cleaner/src/lib.rs index e294b765e7..1660785aa0 100644 --- a/frame/evm/precompile/storage-cleaner/src/lib.rs +++ b/frame/evm/precompile/storage-cleaner/src/lib.rs @@ -23,7 +23,9 @@ extern crate alloc; use alloc::vec::Vec; use core::marker::PhantomData; -use fp_evm::{PrecompileFailure, ACCOUNT_BASIC_PROOF_SIZE, ACCOUNT_STORAGE_PROOF_SIZE}; +use fp_evm::{ + AccountProvider, PrecompileFailure, ACCOUNT_BASIC_PROOF_SIZE, ACCOUNT_STORAGE_PROOF_SIZE, +}; use pallet_evm::AddressMapping; use precompile_utils::{prelude::*, EvmResult}; use sp_core::H160; @@ -200,7 +202,7 @@ where pallet_evm::Suicided::::remove(address); let account_id = Runtime::AddressMapping::into_account_id(address); - let _ = frame_system::Pallet::::dec_sufficients(&account_id); + Runtime::AccountProvider::remove_account(&account_id); } } diff --git a/frame/evm/precompile/storage-cleaner/src/mock.rs b/frame/evm/precompile/storage-cleaner/src/mock.rs index 06c58e5f96..2fe0c16a6a 100644 --- a/frame/evm/precompile/storage-cleaner/src/mock.rs +++ b/frame/evm/precompile/storage-cleaner/src/mock.rs @@ -124,6 +124,7 @@ parameter_types! { } impl pallet_evm::Config for Runtime { + type AccountProvider = pallet_evm::FrameSystemAccountProvider; type FeeCalculator = (); type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type WeightPerGas = WeightPerGas; diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index 81de8a366a..a3332d7061 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -102,9 +102,10 @@ use sp_runtime::{ use fp_account::AccountId20; use fp_evm::GenesisAccount; pub use fp_evm::{ - Account, 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::{ @@ -125,6 +126,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; @@ -140,12 +144,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>; @@ -551,7 +555,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); } let _ = T::Currency::deposit_creating( @@ -583,13 +587,14 @@ 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; +pub type BalanceOf = <::Currency as Currency>>::Balance; /// Type alias for negative imbalance during fees -type NegativeImbalanceOf = - ::AccountId>>::NegativeImbalance; +type NegativeImbalanceOf = >>::NegativeImbalance; #[derive( Debug, @@ -827,7 +832,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); @@ -842,7 +847,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(_) => (), } @@ -865,7 +870,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. @@ -905,7 +910,7 @@ impl Pallet { /// Get the account basic in EVM format. 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); let balance = T::Currency::reducible_balance(&account_id, Preservation::Preserve, Fortitude::Polite); @@ -961,17 +966,13 @@ pub struct EVMCurrencyAdapter(core::marker::PhantomData<(C, OU)>); impl OnChargeEVMTransaction for EVMCurrencyAdapter where T: Config, - C: Currency<::AccountId>, - C::PositiveImbalance: Imbalance< - ::AccountId>>::Balance, - Opposite = C::NegativeImbalance, - >, - C::NegativeImbalance: Imbalance< - ::AccountId>>::Balance, - Opposite = C::PositiveImbalance, - >, + C: Currency>, + C::PositiveImbalance: + Imbalance<>>::Balance, Opposite = C::NegativeImbalance>, + C::NegativeImbalance: + Imbalance<>>::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>; @@ -1061,12 +1062,12 @@ pub struct EVMFungibleAdapter(core::marker::PhantomData<(F, OU)>); impl OnChargeEVMTransaction for EVMFungibleAdapter where T: Config, - F: Balanced, - OU: OnUnbalanced>, - U256: UniqueSaturatedInto<::AccountId>>::Balance>, + F: Balanced>, + OU: OnUnbalanced, F>>, + U256: UniqueSaturatedInto<>>::Balance>, { // Kept type as Option to satisfy bound of Default - type LiquidityInfo = Option>; + type LiquidityInfo = Option, F>>; fn withdraw_fee(who: &H160, fee: U256) -> Result> { if fee.is_zero() { @@ -1099,13 +1100,13 @@ where .saturating_sub(corrected_fee.unique_saturated_into()); // refund to the account that paid the fees. let refund_imbalance = F::deposit(&account_id, refund_amount, Precision::BestEffort) - .unwrap_or_else(|_| Debt::::zero()); + .unwrap_or_else(|_| Debt::, F>::zero()); // merge the imbalance caused by paying the fees and refunding parts of it again. let adjusted_paid = paid .offset(refund_imbalance) .same() - .unwrap_or_else(|_| Credit::::zero()); + .unwrap_or_else(|_| Credit::, F>::zero()); let (base_fee, tip) = adjusted_paid.split(base_fee.unique_saturated_into()); // Handle base fee. Can be either burned, rationed, etc ... @@ -1128,13 +1129,11 @@ where impl OnChargeEVMTransaction for () where T: Config, - T::Currency: Balanced, - U256: UniqueSaturatedInto< - <::Currency as Inspect<::AccountId>>::Balance, - >, + T::Currency: Balanced>, + U256: UniqueSaturatedInto<<::Currency as Inspect>>::Balance>, { // Kept type as Option to satisfy bound of Default - type LiquidityInfo = Option>; + type LiquidityInfo = Option, T::Currency>>; fn withdraw_fee(who: &H160, fee: U256) -> Result> { EVMFungibleAdapter::::withdraw_fee(who, fee) @@ -1175,3 +1174,29 @@ impl OnCreate for Tuple { )*) } } + +/// EVM account provider based on the [`frame_system`] accounts. +/// +/// Uses standard Substrate accounts system to hold EVM accounts. +pub struct FrameSystemAccountProvider(core::marker::PhantomData); + +impl AccountProvider for FrameSystemAccountProvider { + 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 ab98820f11..8cb158d4d0 100644 --- a/frame/evm/src/mock.rs +++ b/frame/evm/src/mock.rs @@ -134,6 +134,7 @@ parameter_types! { pub SuicideQuickClearLimit: u32 = 0; } impl crate::Config for Test { + type AccountProvider = crate::FrameSystemAccountProvider; type FeeCalculator = FixedGasPrice; type GasWeightMapping = crate::FixedGasWeightMapping; type WeightPerGas = WeightPerGas; diff --git a/frame/evm/src/runner/stack.rs b/frame/evm/src/runner/stack.rs index 0707159cd2..3546b45d31 100644 --- a/frame/evm/src/runner/stack.rs +++ b/frame/evm/src/runner/stack.rs @@ -47,9 +47,9 @@ use fp_evm::{ }; use crate::{ - runner::Runner as RunnerT, AccountCodes, AccountCodesMetadata, 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")] @@ -840,7 +840,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 345da89f8f..2873f28682 100644 --- a/precompiles/src/precompile_set.rs +++ b/precompiles/src/precompile_set.rs @@ -1085,7 +1085,7 @@ impl PrecompileSetBuilder } /// Return the list of mapped addresses contained in this PrecompileSet. - pub fn used_addresses() -> impl Iterator { + pub fn used_addresses() -> impl Iterator> { Self::used_addresses_h160().map(R::AddressMapping::into_account_id) } diff --git a/precompiles/tests-external/lib.rs b/precompiles/tests-external/lib.rs index de0c5de26e..b79fed5cb4 100644 --- a/precompiles/tests-external/lib.rs +++ b/precompiles/tests-external/lib.rs @@ -230,6 +230,7 @@ parameter_types! { } impl pallet_evm::Config for Runtime { + type AccountProvider = pallet_evm::FrameSystemAccountProvider; 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 new file mode 100644 index 0000000000..a9ee7c92a1 --- /dev/null +++ b/primitives/evm/src/account_provider.rs @@ -0,0 +1,62 @@ +// This file is part of Frontier. + +// Copyright (c) Humanode Core. +// 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. + +//! 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 nonce type. + /// + /// The number that helps to ensure that each transaction in the network is unique + /// for particular account. + type Nonce: 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::Nonce; + + /// 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 efc94593a4..2ae0b344bf 100644 --- a/primitives/evm/src/lib.rs +++ b/primitives/evm/src/lib.rs @@ -20,6 +20,7 @@ extern crate alloc; +mod account_provider; mod precompile; mod validation; @@ -38,6 +39,7 @@ pub use evm::{ }; pub use self::{ + account_provider::AccountProvider, precompile::{ Context, ExitError, ExitRevert, ExitSucceed, IsPrecompileResult, LinearCostPrecompile, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 27e0611c8f..6954605854 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -348,6 +348,7 @@ parameter_types! { } impl pallet_evm::Config for Runtime { + type AccountProvider = pallet_evm::FrameSystemAccountProvider; type FeeCalculator = BaseFee; type GasWeightMapping = pallet_evm::FixedGasWeightMapping; type WeightPerGas = WeightPerGas;