Skip to content

Commit

Permalink
Support external account provider (#83) (#92) (#97) (#104) (#121)
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 authored Jun 10, 2024
1 parent 393f597 commit ee14c57
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 32 deletions.
1 change: 1 addition & 0 deletions frame/ethereum/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,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 @@ -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<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
79 changes: 57 additions & 22 deletions frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,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, 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::{
Expand All @@ -118,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 @@ -133,12 +137,16 @@ 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 @@ -535,7 +543,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 All @@ -562,12 +570,14 @@ 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;
pub type BalanceOf<T> = <<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;
type NegativeImbalanceOf<C, T> = <C as Currency<
<<T as Config>::AccountProvider as AccountProvider>::AccountId,
>>::NegativeImbalance;

#[derive(
Debug,
Expand Down Expand Up @@ -792,7 +802,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 @@ -809,7 +819,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 @@ -850,7 +860,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 @@ -907,17 +917,19 @@ 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 @@ -1001,10 +1013,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 @@ -1048,3 +1060,26 @@ 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 Nonce = T::Nonce;

fn account_nonce(who: &Self::AccountId) -> Self::Nonce {
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 @@ -130,14 +130,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
3 changes: 2 additions & 1 deletion precompiles/src/precompile_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,8 @@ impl<R: pallet_evm::Config, P: PrecompileSetFragment> PrecompileSetBuilder<R, P>
}

/// Return the list of addresses contained in this PrecompileSet.
pub fn used_addresses() -> impl Iterator<Item = R::AccountId> {
pub fn used_addresses(
) -> impl Iterator<Item = <R::AccountProvider as pallet_evm::AccountProvider>::AccountId> {
Self::new()
.inner
.used_addresses()
Expand Down
1 change: 1 addition & 0 deletions precompiles/tests-external/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ parameter_types! {
}

impl pallet_evm::Config for Runtime {
type AccountProvider = pallet_evm::NativeSystemAccountProvider<Self>;
type FeeCalculator = ();
type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;
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;
/// 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);
}
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 @@ -328,6 +328,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 ee14c57

Please sign in to comment.