From 4dff4e43c4deecd782b1c8464daa9290cf674b28 Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov <39522748+dmitrylavrenov@users.noreply.github.com> Date: Wed, 10 May 2023 13:01:48 +0300 Subject: [PATCH 1/2] Introduce external account provider into `pallet_evm` (#61) * Introduce AccountProvider interface * Apply account provider logic for tests and template * Fix docs for remove_account method * Fix missing docs * Improve docs for account provider trait * Fix docs for native system account provider * Move account provider logic to separate mod * Add details docs for methods --- 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/account_provider.rs | 64 +++++++++++++++++++++++ frame/evm/src/lib.rs | 42 ++++++++------- frame/evm/src/mock.rs | 5 +- frame/evm/src/runner/stack.rs | 4 +- precompiles/src/precompile_set.rs | 2 +- template/runtime/src/lib.rs | 1 + 9 files changed, 101 insertions(+), 27 deletions(-) create mode 100644 frame/evm/src/account_provider.rs diff --git a/frame/ethereum/src/mock.rs b/frame/ethereum/src/mock.rs index c4d01b2f55..b29b3bb022 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 4de25ae878..e74079f239 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::AccountProvider as pallet_evm::AccountProvider>::AccountId>>, + DispatchValidator: DispatchValidateT<<::AccountProvider as pallet_evm::AccountProvider>::AccountId, 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 cb55296bda..18049b791b 100644 --- a/frame/evm/precompile/dispatch/src/mock.rs +++ b/frame/evm/precompile/dispatch/src/mock.rs @@ -132,14 +132,15 @@ parameter_types! { pub WeightPerGas: Weight = Weight::from_parts(20_000, 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<::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..76b5d6eba2 --- /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; + /// 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); +} + +/// Native system account provider that `frame_system` provides. +pub struct NativeSystemAccountProvider(sp_std::marker::PhantomData); + +impl AccountProvider for NativeSystemAccountProvider { + type AccountId = ::AccountId; + type Nonce = ::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/lib.rs b/frame/evm/src/lib.rs index 012d5e796d..3ef7c9ad2c 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -65,6 +65,9 @@ pub mod runner; mod tests; pub mod weights; +mod account_provider; +pub use account_provider::{AccountProvider, NativeSystemAccountProvider}; + pub use evm::{ Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, }; @@ -89,7 +92,7 @@ use frame_support::{ use frame_system::RawOrigin; use sp_core::{H160, H256, U256}; use sp_runtime::{ - traits::{BadOrigin, NumberFor, Saturating, UniqueSaturatedInto, Zero}, + traits::{BadOrigin, NumberFor, Saturating, UniqueSaturatedInto, AtLeast32Bit, Zero}, AccountId32, DispatchErrorWithPostInfo, }; use sp_std::{cmp::min, collections::btree_map::BTreeMap, vec::Vec}; @@ -120,6 +123,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; @@ -135,12 +141,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>; @@ -537,7 +543,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()); @@ -568,11 +574,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; #[derive( Debug, @@ -802,7 +808,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); @@ -825,7 +831,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. @@ -866,7 +872,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); @@ -923,17 +929,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>; @@ -1017,10 +1023,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 2ba1495eb4..7a9d3f9184 100644 --- a/frame/evm/src/mock.rs +++ b/frame/evm/src/mock.rs @@ -130,14 +130,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 274990137f..7e3d7fa5f9 100644 --- a/frame/evm/src/runner/stack.rs +++ b/frame/evm/src/runner/stack.rs @@ -50,7 +50,7 @@ use fp_evm::{ use crate::{ runner::Runner as RunnerT, AccountCodes, AccountCodesMetadata, AccountStorages, AddressMapping, BalanceOf, BlockHashMapping, Config, Error, Event, FeeCalculator, OnChargeEVMTransaction, - OnCreate, Pallet, RunnerError, + OnCreate, Pallet, RunnerError, AccountProvider, }; #[cfg(feature = "forbid-evm-reentrancy")] @@ -843,7 +843,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 2f9bb0816a..d8b90fce37 100644 --- a/precompiles/src/precompile_set.rs +++ b/precompiles/src/precompile_set.rs @@ -1086,7 +1086,7 @@ impl PrecompileSetBuilder } /// Return the list of addresses contained in this PrecompileSet. - pub fn used_addresses() -> impl Iterator { + pub fn used_addresses() -> impl Iterator::AccountId> { Self::new() .inner .used_addresses() diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index d905e3d144..e9f5643d97 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -327,6 +327,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 507a9e1459b06dc76fd30346d77d2687d5dee82b Mon Sep 17 00:00:00 2001 From: Dmitry Lavrenov <39522748+dmitrylavrenov@users.noreply.github.com> Date: Sun, 18 Jun 2023 11:34:00 +0300 Subject: [PATCH 2/2] Move `AccountProvider` interface into `fp-em` (#71) * Move account provider interface into fp-em * Implement AccountProvider interface for EvmSystem * Revert formatter * Move NativeSystemAccountProvider to pallet-evm --- frame/evm/src/lib.rs | 31 ++++++++++++++++--- .../evm/src/account_provider.rs | 25 +-------------- primitives/evm/src/lib.rs | 2 ++ 3 files changed, 29 insertions(+), 29 deletions(-) rename {frame => primitives}/evm/src/account_provider.rs (66%) diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index 3ef7c9ad2c..f9c3a9d276 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -65,9 +65,6 @@ pub mod runner; mod tests; pub mod weights; -mod account_provider; -pub use account_provider::{AccountProvider, NativeSystemAccountProvider}; - pub use evm::{ Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, }; @@ -92,7 +89,7 @@ use frame_support::{ use frame_system::RawOrigin; use sp_core::{H160, H256, U256}; use sp_runtime::{ - traits::{BadOrigin, NumberFor, Saturating, UniqueSaturatedInto, AtLeast32Bit, Zero}, + traits::{BadOrigin, NumberFor, Saturating, UniqueSaturatedInto, Zero}, AccountId32, DispatchErrorWithPostInfo, }; use sp_std::{cmp::min, collections::btree_map::BTreeMap, vec::Vec}; @@ -100,7 +97,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, }; @@ -1070,3 +1067,27 @@ 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/account_provider.rs b/primitives/evm/src/account_provider.rs similarity index 66% rename from frame/evm/src/account_provider.rs rename to primitives/evm/src/account_provider.rs index 76b5d6eba2..51ef6d2113 100644 --- a/frame/evm/src/account_provider.rs +++ b/primitives/evm/src/account_provider.rs @@ -1,6 +1,6 @@ //! Custom account provider logic. -use super::*; +use sp_runtime::traits::AtLeast32Bit; /// The account provider interface abstraction layer. /// @@ -39,26 +39,3 @@ pub trait AccountProvider { /// 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 Nonce = ::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/primitives/evm/src/lib.rs b/primitives/evm/src/lib.rs index bdbb2792f0..af6a442f1c 100644 --- a/primitives/evm/src/lib.rs +++ b/primitives/evm/src/lib.rs @@ -18,6 +18,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![deny(unused_crate_dependencies)] +mod account_provider; mod precompile; mod validation; @@ -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,