Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support external account provider #1329

1 change: 1 addition & 0 deletions frame/ethereum/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ parameter_types! {
}

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 @@ -54,8 +54,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<pallet_evm::AccountIdOf<T>>>,
DispatchValidator: DispatchValidateT<pallet_evm::AccountIdOf<T>, T::RuntimeCall>,
DecodeLimit: Get<u32>,
{
fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
Expand Down
1 change: 1 addition & 0 deletions frame/evm/precompile/dispatch/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ parameter_types! {
pub SuicideQuickClearLimit: u32 = 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;
Expand Down
6 changes: 4 additions & 2 deletions frame/evm/precompile/storage-cleaner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -200,7 +202,7 @@ where
pallet_evm::Suicided::<Runtime>::remove(address);

let account_id = Runtime::AddressMapping::into_account_id(address);
let _ = frame_system::Pallet::<Runtime>::dec_sufficients(&account_id);
Runtime::AccountProvider::remove_account(&account_id);
}
}

Expand Down
1 change: 1 addition & 0 deletions frame/evm/precompile/storage-cleaner/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,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
94 changes: 58 additions & 36 deletions frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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;

Expand All @@ -140,12 +144,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 = AccountIdOf<Self>>;

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

/// The overarching event type.
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
Expand Down Expand Up @@ -551,7 +555,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);
}

let _ = T::Currency::deposit_creating(
Expand Down Expand Up @@ -583,13 +587,14 @@ pub mod pallet {
pub type Suicided<T: Config> = StorageMap<_, Blake2_128Concat, H160, (), OptionQuery>;
}

/// Utility alias for easy access to the [`AccountProvider::AccountId`] type from a given config.
pub type AccountIdOf<T> = <<T as Config>::AccountProvider as AccountProvider>::AccountId;

/// 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<AccountIdOf<T>>>::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<AccountIdOf<T>>>::NegativeImbalance;

#[derive(
Debug,
Expand Down Expand Up @@ -827,7 +832,7 @@ impl<T: Config> Pallet<T> {
// 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::<T>::inc_account_nonce(&account_id);
T::AccountProvider::inc_account_nonce(&account_id);
}

<AccountCodes<T>>::remove(address);
Expand All @@ -842,7 +847,7 @@ impl<T: Config> Pallet<T> {
<Suicided<T>>::remove(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);
}
KillStorageResult::SomeRemaining(_) => (),
}
Expand All @@ -865,7 +870,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 @@ -905,7 +910,7 @@ impl<T: Config> Pallet<T> {
/// 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::<T>::account_nonce(&account_id);
let nonce = T::AccountProvider::account_nonce(&account_id);
let balance =
T::Currency::reducible_balance(&account_id, Preservation::Preserve, Fortitude::Polite);

Expand Down Expand Up @@ -961,17 +966,13 @@ pub struct EVMCurrencyAdapter<C, OU>(core::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::PositiveImbalance: Imbalance<
<C as Currency<<T as frame_system::Config>::AccountId>>::Balance,
Opposite = C::NegativeImbalance,
>,
C::NegativeImbalance: Imbalance<
<C as Currency<<T as frame_system::Config>::AccountId>>::Balance,
Opposite = C::PositiveImbalance,
>,
C: Currency<AccountIdOf<T>>,
C::PositiveImbalance:
Imbalance<<C as Currency<AccountIdOf<T>>>::Balance, Opposite = C::NegativeImbalance>,
C::NegativeImbalance:
Imbalance<<C as Currency<AccountIdOf<T>>>::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<AccountIdOf<T>>>::Balance>,
{
// Kept type as Option to satisfy bound of Default
type LiquidityInfo = Option<NegativeImbalanceOf<C, T>>;
Expand Down Expand Up @@ -1061,12 +1062,12 @@ pub struct EVMFungibleAdapter<F, OU>(core::marker::PhantomData<(F, OU)>);
impl<T, F, OU> OnChargeEVMTransaction<T> for EVMFungibleAdapter<F, OU>
where
T: Config,
F: Balanced<T::AccountId>,
OU: OnUnbalanced<Credit<T::AccountId, F>>,
U256: UniqueSaturatedInto<<F as Inspect<<T as frame_system::Config>::AccountId>>::Balance>,
F: Balanced<AccountIdOf<T>>,
OU: OnUnbalanced<Credit<AccountIdOf<T>, F>>,
U256: UniqueSaturatedInto<<F as Inspect<AccountIdOf<T>>>::Balance>,
{
// Kept type as Option to satisfy bound of Default
type LiquidityInfo = Option<Credit<T::AccountId, F>>;
type LiquidityInfo = Option<Credit<AccountIdOf<T>, F>>;

fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>> {
if fee.is_zero() {
Expand Down Expand Up @@ -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::<T::AccountId, F>::zero());
.unwrap_or_else(|_| Debt::<AccountIdOf<T>, 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::<T::AccountId, F>::zero());
.unwrap_or_else(|_| Credit::<AccountIdOf<T>, F>::zero());

let (base_fee, tip) = adjusted_paid.split(base_fee.unique_saturated_into());
// Handle base fee. Can be either burned, rationed, etc ...
Expand All @@ -1128,13 +1129,11 @@ where
impl<T> OnChargeEVMTransaction<T> for ()
where
T: Config,
T::Currency: Balanced<T::AccountId>,
U256: UniqueSaturatedInto<
<<T as Config>::Currency as Inspect<<T as frame_system::Config>::AccountId>>::Balance,
>,
T::Currency: Balanced<AccountIdOf<T>>,
U256: UniqueSaturatedInto<<<T as Config>::Currency as Inspect<AccountIdOf<T>>>::Balance>,
{
// Kept type as Option to satisfy bound of Default
type LiquidityInfo = Option<Credit<T::AccountId, T::Currency>>;
type LiquidityInfo = Option<Credit<AccountIdOf<T>, T::Currency>>;

fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>> {
EVMFungibleAdapter::<T::Currency, ()>::withdraw_fee(who, fee)
Expand Down Expand Up @@ -1175,3 +1174,26 @@ impl<T> OnCreate<T> for Tuple {
)*)
}
}

/// Native system account provider that `frame_system` provides.
pub struct NativeSystemAccountProvider<T>(core::marker::PhantomData<T>);
boundless-forest marked this conversation as resolved.
Show resolved Hide resolved

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);
}
}
1 change: 1 addition & 0 deletions frame/evm/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ parameter_types! {
pub SuicideQuickClearLimit: u32 = 0;
}
impl crate::Config for Test {
type AccountProvider = crate::NativeSystemAccountProvider<Self>;
type FeeCalculator = FixedGasPrice;
type GasWeightMapping = crate::FixedGasWeightMapping<Self>;
type WeightPerGas = WeightPerGas;
Expand Down
8 changes: 4 additions & 4 deletions frame/evm/src/runner/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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::<T>::inc_account_nonce(&account_id);
T::AccountProvider::inc_account_nonce(&account_id);
Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion precompiles/src/precompile_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@ impl<R: pallet_evm::Config, P: PrecompileSetFragment> PrecompileSetBuilder<R, P>
}

/// Return the list of mapped addresses contained in this PrecompileSet.
pub fn used_addresses() -> impl Iterator<Item = R::AccountId> {
pub fn used_addresses() -> impl Iterator<Item = pallet_evm::AccountIdOf<R>> {
Self::used_addresses_h160().map(R::AddressMapping::into_account_id)
}

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 @@ -230,6 +230,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.
boundless-forest marked this conversation as resolved.
Show resolved Hide resolved
MOZGIII marked this conversation as resolved.
Show resolved Hide resolved

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);
}
2 changes: 2 additions & 0 deletions primitives/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

extern crate alloc;

mod account_provider;
mod precompile;
mod validation;

Expand All @@ -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,
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 @@ -348,6 +348,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
Loading