diff --git a/frame/ethereum/src/mock.rs b/frame/ethereum/src/mock.rs index 5e41224e9d..9614fb8a0c 100644 --- a/frame/ethereum/src/mock.rs +++ b/frame/ethereum/src/mock.rs @@ -152,6 +152,7 @@ impl AddressMapping for HashedAddressMapping { } 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 958a4a86cc..d6f9cd2b42 100644 --- a/frame/evm/precompile/dispatch/src/lib.rs +++ b/frame/evm/precompile/dispatch/src/lib.rs @@ -49,7 +49,7 @@ impl Precompile for Dispatch where T: pallet_evm::Config, T::RuntimeCall: Dispatchable + GetDispatchInfo + Decode, - ::RuntimeOrigin: From>, + ::RuntimeOrigin: From::AccountProvider as pallet_evm::AccountProvider>::AccountId>>, 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 173091f4f6..7163d8ea2d 100644 --- a/frame/evm/precompile/dispatch/src/mock.rs +++ b/frame/evm/precompile/dispatch/src/mock.rs @@ -139,14 +139,15 @@ parameter_types! { pub WeightPerGas: Weight = Weight::from_ref_time(20_000); } 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<::AccountId>; - type WithdrawOrigin = EnsureAddressNever; + type WithdrawOrigin = EnsureAddressNever<::AccountId>; type AddressMapping = IdentityAddressMapping; type Currency = Balances; diff --git a/frame/evm/src/account_provider.rs b/frame/evm/src/account_provider.rs new file mode 100644 index 0000000000..69484222cf --- /dev/null +++ b/frame/evm/src/account_provider.rs @@ -0,0 +1,64 @@ +//! Custom account provider logic. + +use super::*; + +/// 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); +} + +/// Native system account provider that `frame_system` provides. +pub struct NativeSystemAccountProvider(sp_std::marker::PhantomData); + +impl AccountProvider for NativeSystemAccountProvider { + type AccountId = ::AccountId; + type Index = ::Index; + + fn account_nonce(who: &Self::AccountId) -> Self::Index { + 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/lib.rs b/frame/evm/src/lib.rs index a6b1406e2d..76bfb498a2 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -64,6 +64,9 @@ pub mod runner; #[cfg(test)] mod tests; +mod account_provider; +pub use account_provider::{AccountProvider, NativeSystemAccountProvider}; + use frame_support::{ dispatch::{DispatchResultWithPostInfo, Pays, PostDispatchInfo}, traits::{ @@ -76,7 +79,7 @@ use frame_system::RawOrigin; use impl_trait_for_tuples::impl_for_tuples; use sp_core::{Hasher, H160, H256, U256}; use sp_runtime::{ - traits::{BadOrigin, Saturating, UniqueSaturatedInto, Zero}, + traits::{BadOrigin, Saturating, UniqueSaturatedInto, AtLeast32Bit, Zero}, AccountId32, DispatchErrorWithPostInfo, }; use sp_std::{cmp::min, vec::Vec}; @@ -110,6 +113,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + pallet_timestamp::Config { + /// Account info provider. + type AccountProvider: AccountProvider; + /// Calculator for current gas price. type FeeCalculator: FeeCalculator; @@ -125,12 +131,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::AccountId>; /// Mapping from address to account id. - type AddressMapping: AddressMapping; + type AddressMapping: AddressMapping<::AccountId>; /// Currency type for withdraw and balance storage. - type Currency: Currency + Inspect; + type Currency: Currency<::AccountId> + Inspect<::AccountId>; /// The overarching event type. type RuntimeEvent: From> + IsType<::RuntimeEvent>; @@ -486,7 +492,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()); @@ -512,11 +518,11 @@ pub mod pallet { /// Type alias for currency balance. pub type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; + <::Currency as Currency<<::AccountProvider as AccountProvider>::AccountId>>::Balance; /// Type alias for negative imbalance during fees type NegativeImbalanceOf = - ::AccountId>>::NegativeImbalance; + ::AccountProvider as AccountProvider>::AccountId>>::NegativeImbalance; pub trait EnsureAddressOrigin { /// Success return type. @@ -690,7 +696,7 @@ impl Pallet { pub fn remove_account(address: &H160) { if >::contains_key(address) { let account_id = T::AddressMapping::into_account_id(*address); - let _ = frame_system::Pallet::::dec_sufficients(&account_id); + T::AccountProvider::remove_account(&account_id); } >::remove(address); @@ -706,7 +712,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); } >::insert(address, code); @@ -716,7 +722,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, true); @@ -772,17 +778,17 @@ pub struct EVMCurrencyAdapter(sp_std::marker::PhantomData<(C, OU)>); impl OnChargeEVMTransaction for EVMCurrencyAdapter where T: Config, - C: Currency<::AccountId>, + C: Currency<<::AccountProvider as AccountProvider>::AccountId>, C::PositiveImbalance: Imbalance< - ::AccountId>>::Balance, + ::AccountProvider as AccountProvider>::AccountId>>::Balance, Opposite = C::NegativeImbalance, >, C::NegativeImbalance: Imbalance< - ::AccountId>>::Balance, + ::AccountProvider as AccountProvider>::AccountId>>::Balance, Opposite = C::PositiveImbalance, >, OU: OnUnbalanced>, - U256: UniqueSaturatedInto<::AccountId>>::Balance>, + U256: UniqueSaturatedInto<::AccountProvider as AccountProvider>::AccountId>>::Balance>, { // Kept type as Option to satisfy bound of Default type LiquidityInfo = Option>; @@ -866,10 +872,10 @@ where impl OnChargeEVMTransaction for () where T: Config, - ::AccountId>>::PositiveImbalance: - Imbalance<::AccountId>>::Balance, Opposite = ::AccountId>>::NegativeImbalance>, - ::AccountId>>::NegativeImbalance: -Imbalance<::AccountId>>::Balance, Opposite = ::AccountId>>::PositiveImbalance>, + ::AccountProvider as AccountProvider>::AccountId>>::PositiveImbalance: + Imbalance<::AccountProvider as AccountProvider>::AccountId>>::Balance, Opposite = ::AccountProvider as AccountProvider>::AccountId>>::NegativeImbalance>, + ::AccountProvider as AccountProvider>::AccountId>>::NegativeImbalance: +Imbalance<::AccountProvider as AccountProvider>::AccountId>>::Balance, Opposite = ::AccountProvider as AccountProvider>::AccountId>>::PositiveImbalance>, U256: UniqueSaturatedInto>, { diff --git a/frame/evm/src/mock.rs b/frame/evm/src/mock.rs index a82721fe5e..ad886616db 100644 --- a/frame/evm/src/mock.rs +++ b/frame/evm/src/mock.rs @@ -132,14 +132,15 @@ parameter_types! { pub MockPrecompiles: MockPrecompileSet = MockPrecompileSet; } 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<::AccountId>; - type WithdrawOrigin = EnsureAddressNever; + type WithdrawOrigin = EnsureAddressNever<::AccountId>; type AddressMapping = IdentityAddressMapping; type Currency = Balances; diff --git a/frame/evm/src/runner/stack.rs b/frame/evm/src/runner/stack.rs index be39912a48..02d4848956 100644 --- a/frame/evm/src/runner/stack.rs +++ b/frame/evm/src/runner/stack.rs @@ -20,7 +20,7 @@ use crate::{ runner::Runner as RunnerT, AccountCodes, AccountStorages, AddressMapping, BalanceOf, BlockHashMapping, Config, Error, Event, FeeCalculator, OnChargeEVMTransaction, OnCreate, - Pallet, RunnerError, + Pallet, RunnerError, AccountProvider }; use evm::{ backend::Backend as BackendT, @@ -721,7 +721,7 @@ where fn inc_nonce(&mut self, address: H160) { let account_id = T::AddressMapping::into_account_id(address); - frame_system::Pallet::::inc_account_nonce(&account_id); + T::AccountProvider::inc_account_nonce(&account_id); } fn set_storage(&mut self, address: H160, index: H256, value: H256) { diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 4b0aec6759..2316298271 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -326,6 +326,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;