Skip to content

Commit

Permalink
Support external account provider (#83) (#92) (#97) (#104)
Browse files Browse the repository at this point in the history
* 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

* 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
  • Loading branch information
dmitrylavrenov committed Oct 21, 2024
1 parent 4b8e961 commit 501c85a
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 27 deletions.
1 change: 1 addition & 0 deletions frame/ethereum/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ impl AddressMapping<AccountId32> for HashedAddressMapping {
}

impl pallet_evm::Config for Test {
type AccountProvider = pallet_evm::NativeSystemAccountProvider<Self>;
type FeeCalculator = FixedGasPrice;
type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;
Expand Down
4 changes: 2 additions & 2 deletions frame/evm/precompile/dispatch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ impl<T, DispatchValidator, DecodeLimit> Precompile for Dispatch<T, DispatchValid
where
T: pallet_evm::Config,
T::RuntimeCall: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo + Decode,
<T::RuntimeCall as Dispatchable>::RuntimeOrigin: From<Option<T::AccountId>>,
DispatchValidator: DispatchValidateT<T::AccountId, T::RuntimeCall>,
<T::RuntimeCall as Dispatchable>::RuntimeOrigin: From<Option<<<T as pallet_evm::Config>::AccountProvider as pallet_evm::AccountProvider>::AccountId>>,
DispatchValidator: DispatchValidateT<<<T as pallet_evm::Config>::AccountProvider as pallet_evm::AccountProvider>::AccountId, T::RuntimeCall>,
DecodeLimit: Get<u32>,
{
fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
Expand Down
5 changes: 3 additions & 2 deletions frame/evm/precompile/dispatch/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,15 @@ parameter_types! {
pub WeightPerGas: Weight = Weight::from_parts(20_000, 0);
}
impl pallet_evm::Config for Test {
type AccountProvider = pallet_evm::NativeSystemAccountProvider<Self>;
type FeeCalculator = FixedGasPrice;
type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;

type BlockHashMapping = pallet_evm::SubstrateBlockHashMapping<Self>;
type CallOrigin = EnsureAddressRoot<Self::AccountId>;
type CallOrigin = EnsureAddressRoot<<Self::AccountProvider as pallet_evm::AccountProvider>::AccountId>;

type WithdrawOrigin = EnsureAddressNever<Self::AccountId>;
type WithdrawOrigin = EnsureAddressNever<<Self::AccountProvider as pallet_evm::AccountProvider>::AccountId>;
type AddressMapping = IdentityAddressMapping;
type Currency = Balances;

Expand Down
63 changes: 45 additions & 18 deletions frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,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,
InvalidEvmTransactionError, IsPrecompileResult, LinearCostPrecompile, Log, Precompile,
PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet,
Vicinity,
Expand All @@ -119,6 +119,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;

Expand All @@ -134,12 +137,12 @@ pub mod pallet {
/// Allow the origin to call on behalf of given address.
type CallOrigin: EnsureAddressOrigin<Self::RuntimeOrigin>;
/// Allow the origin to withdraw on behalf of given address.
type WithdrawOrigin: EnsureAddressOrigin<Self::RuntimeOrigin, Success = Self::AccountId>;
type WithdrawOrigin: EnsureAddressOrigin<Self::RuntimeOrigin, Success = <Self::AccountProvider as AccountProvider>::AccountId>;

/// Mapping from address to account id.
type AddressMapping: AddressMapping<Self::AccountId>;
type AddressMapping: AddressMapping<<Self::AccountProvider as AccountProvider>::AccountId>;
/// Currency type for withdraw and balance storage.
type Currency: Currency<Self::AccountId> + Inspect<Self::AccountId>;
type Currency: Currency<<Self::AccountProvider as AccountProvider>::AccountId> + Inspect<<Self::AccountProvider as AccountProvider>::AccountId>;

/// The overarching event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
Expand Down Expand Up @@ -534,7 +537,7 @@ pub mod pallet {
MAX_ACCOUNT_NONCE,
UniqueSaturatedInto::<usize>::unique_saturated_into(account.nonce),
) {
frame_system::Pallet::<T>::inc_account_nonce(&account_id);
T::AccountProvider::inc_account_nonce(&account_id);
}

T::Currency::deposit_creating(&account_id, account.balance.unique_saturated_into());
Expand Down Expand Up @@ -562,11 +565,11 @@ pub mod pallet {

/// Type alias for currency balance.
pub type BalanceOf<T> =
<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
<<T as Config>::Currency as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::Balance;

/// Type alias for negative imbalance during fees
type NegativeImbalanceOf<C, T> =
<C as Currency<<T as frame_system::Config>::AccountId>>::NegativeImbalance;
<C as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::NegativeImbalance;

#[derive(
Debug,
Expand Down Expand Up @@ -791,7 +794,7 @@ impl<T: Config> Pallet<T> {
pub fn remove_account(address: &H160) {
if <AccountCodes<T>>::contains_key(address) {
let account_id = T::AddressMapping::into_account_id(*address);
let _ = frame_system::Pallet::<T>::dec_sufficients(&account_id);
T::AccountProvider::remove_account(&account_id);
}

<AccountCodes<T>>::remove(address);
Expand All @@ -808,7 +811,7 @@ impl<T: Config> Pallet<T> {

if !<AccountCodes<T>>::contains_key(address) {
let account_id = T::AddressMapping::into_account_id(address);
let _ = frame_system::Pallet::<T>::inc_sufficients(&account_id);
T::AccountProvider::create_account(&account_id);
}

// Update metadata.
Expand Down Expand Up @@ -849,7 +852,7 @@ impl<T: Config> Pallet<T> {
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::<T>::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);
Expand Down Expand Up @@ -906,17 +909,17 @@ pub struct EVMCurrencyAdapter<C, OU>(sp_std::marker::PhantomData<(C, OU)>);
impl<T, C, OU> OnChargeEVMTransaction<T> for EVMCurrencyAdapter<C, OU>
where
T: Config,
C: Currency<<T as frame_system::Config>::AccountId>,
C: Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>,
C::PositiveImbalance: Imbalance<
<C as Currency<<T as frame_system::Config>::AccountId>>::Balance,
<C as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::Balance,
Opposite = C::NegativeImbalance,
>,
C::NegativeImbalance: Imbalance<
<C as Currency<<T as frame_system::Config>::AccountId>>::Balance,
<C as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::Balance,
Opposite = C::PositiveImbalance,
>,
OU: OnUnbalanced<NegativeImbalanceOf<C, T>>,
U256: UniqueSaturatedInto<<C as Currency<<T as frame_system::Config>::AccountId>>::Balance>,
U256: UniqueSaturatedInto<<C as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::Balance>,
{
// Kept type as Option to satisfy bound of Default
type LiquidityInfo = Option<NegativeImbalanceOf<C, T>>;
Expand Down Expand Up @@ -1000,10 +1003,10 @@ where
impl<T> OnChargeEVMTransaction<T> for ()
where
T: Config,
<T::Currency as Currency<<T as frame_system::Config>::AccountId>>::PositiveImbalance:
Imbalance<<T::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance, Opposite = <T::Currency as Currency<<T as frame_system::Config>::AccountId>>::NegativeImbalance>,
<T::Currency as Currency<<T as frame_system::Config>::AccountId>>::NegativeImbalance:
Imbalance<<T::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance, Opposite = <T::Currency as Currency<<T as frame_system::Config>::AccountId>>::PositiveImbalance>,
<T::Currency as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::PositiveImbalance:
Imbalance<<T::Currency as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::Balance, Opposite = <T::Currency as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::NegativeImbalance>,
<T::Currency as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::NegativeImbalance:
Imbalance<<T::Currency as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::Balance, Opposite = <T::Currency as Currency<<<T as Config>::AccountProvider as AccountProvider>::AccountId>>::PositiveImbalance>,
U256: UniqueSaturatedInto<BalanceOf<T>>,

{
Expand Down Expand Up @@ -1047,3 +1050,27 @@ impl<T> OnCreate<T> for Tuple {
)*)
}
}

/// Native system account provider that `frame_system` provides.
pub struct NativeSystemAccountProvider<T>(sp_std::marker::PhantomData<T>);

impl<T: frame_system::Config> AccountProvider for NativeSystemAccountProvider<T> {
type AccountId = T::AccountId;
type Index = T::Index;

fn account_nonce(who: &Self::AccountId) -> Self::Index {
frame_system::Pallet::<T>::account_nonce(&who)
}

fn inc_account_nonce(who: &Self::AccountId) {
frame_system::Pallet::<T>::inc_account_nonce(&who)
}

fn create_account(who: &Self::AccountId) {
let _ = frame_system::Pallet::<T>::inc_sufficients(&who);
}
fn remove_account(who: &Self::AccountId) {
let _ = frame_system::Pallet::<T>::dec_sufficients(&who);
}
}

5 changes: 3 additions & 2 deletions frame/evm/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,15 @@ parameter_types! {
pub MockPrecompiles: MockPrecompileSet = MockPrecompileSet;
}
impl crate::Config for Test {
type AccountProvider = crate::NativeSystemAccountProvider<Self>;
type FeeCalculator = FixedGasPrice;
type GasWeightMapping = crate::FixedGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;

type BlockHashMapping = crate::SubstrateBlockHashMapping<Self>;
type CallOrigin = EnsureAddressRoot<Self::AccountId>;
type CallOrigin = EnsureAddressRoot<<Self::AccountProvider as crate::AccountProvider>::AccountId>;

type WithdrawOrigin = EnsureAddressNever<Self::AccountId>;
type WithdrawOrigin = EnsureAddressNever<<Self::AccountProvider as crate::AccountProvider>::AccountId>;
type AddressMapping = IdentityAddressMapping;
type Currency = Balances;

Expand Down
6 changes: 3 additions & 3 deletions frame/evm/src/runner/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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::<T>::inc_account_nonce(&account_id);
T::AccountProvider::inc_account_nonce(&account_id);
Ok(())
}

Expand Down
41 changes: 41 additions & 0 deletions primitives/evm/src/account_provider.rs
Original file line number Diff line number Diff line change
@@ -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);
}
2 changes: 2 additions & 0 deletions primitives/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(unused_crate_dependencies)]

mod account_provider;
mod precompile;
mod validation;

Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ parameter_types! {
}

impl pallet_evm::Config for Runtime {
type AccountProvider = pallet_evm::NativeSystemAccountProvider<Self>;
type FeeCalculator = BaseFee;
type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;
Expand Down

0 comments on commit 501c85a

Please sign in to comment.