Skip to content

Commit

Permalink
Add weight annotation to pallet Ethereum's transact extrinsic (#202)
Browse files Browse the repository at this point in the history
* Initial simple weight annotation for transact.

* Configureable gas to weight mapping

* refund unused weight

* Thought: gas weight conversion belongs in pallet evm

* Move GasToWeight to pallet_Evm

* Weight refund in pallet_evm

* indentation

* fix mocks
  • Loading branch information
JoshOrndorff committed Nov 24, 2020
1 parent 4497bd3 commit 8b73597
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 24 deletions.
12 changes: 7 additions & 5 deletions frame/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@

use frame_support::{
decl_module, decl_storage, decl_error, decl_event,
traits::Get, traits::FindAuthor,
traits::Get, traits::FindAuthor, weights::Weight,
dispatch::DispatchResultWithPostInfo,
};
use sp_std::prelude::*;
use frame_system::ensure_none;
Expand All @@ -38,7 +39,7 @@ use sp_runtime::{
};
use evm::ExitReason;
use fp_evm::CallOrCreateInfo;
use pallet_evm::Runner;
use pallet_evm::{Runner, GasToWeight};
use sha3::{Digest, Keccak256};
use codec::Encode;
use fp_consensus::{FRONTIER_ENGINE_ID, ConsensusLog};
Expand Down Expand Up @@ -112,8 +113,8 @@ decl_module! {
fn deposit_event() = default;

/// Transact an Ethereum transaction.
#[weight = 0]
fn transact(origin, transaction: ethereum::Transaction) {
#[weight = <T as pallet_evm::Trait>::GasToWeight::gas_to_weight(transaction.gas_limit.low_u32())]
fn transact(origin, transaction: ethereum::Transaction) -> DispatchResultWithPostInfo {
ensure_none(origin)?;

let source = Self::recover_signer(&transaction)
Expand Down Expand Up @@ -183,13 +184,14 @@ decl_module! {
Pending::append((transaction, status, receipt));

Self::deposit_event(Event::Executed(source, transaction_hash, reason));
Ok(Some(T::GasToWeight::gas_to_weight(used_gas.low_u32())).into())
}

fn on_finalize(n: T::BlockNumber) {
<Module<T>>::store_block();
}

fn on_initialize(n: T::BlockNumber) -> frame_support::weights::Weight {
fn on_initialize(n: T::BlockNumber) -> Weight {
Pending::kill();
0
}
Expand Down
1 change: 1 addition & 0 deletions frame/ethereum/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ impl AddressMapping<AccountId32> for HashedAddressMapping {

impl pallet_evm::Trait for Test {
type FeeCalculator = FixedGasPrice;
type GasToWeight = ();
type CallOrigin = EnsureAddressTruncated;
type WithdrawOrigin = EnsureAddressTruncated;
type AddressMapping = HashedAddressMapping;
Expand Down
64 changes: 45 additions & 19 deletions frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ use codec::{Encode, Decode};
#[cfg(feature = "std")]
use serde::{Serialize, Deserialize};
use frame_support::{decl_module, decl_storage, decl_event, decl_error};
use frame_support::weights::{Weight, Pays};
use frame_support::weights::{Weight, Pays, PostDispatchInfo};
use frame_support::traits::{Currency, ExistenceRequirement, Get};
use frame_support::dispatch::DispatchResultWithPostInfo;
use frame_system::RawOrigin;
use sp_core::{U256, H256, H160, Hasher};
use sp_runtime::{AccountId32, traits::{UniqueSaturatedInto, SaturatedConversion, BadOrigin}};
use sp_runtime::{AccountId32, traits::{UniqueSaturatedInto, BadOrigin}};
use evm::Config;

/// Type alias for currency balance.
Expand Down Expand Up @@ -207,6 +207,17 @@ impl<H: Hasher<Out=H256>> AddressMapping<AccountId32> for HashedAddressMapping<H
}
}

/// A mapping function that converts Ethereum gas to Substrate weight
pub trait GasToWeight {
fn gas_to_weight(gas: u32) -> Weight;
}

impl GasToWeight for () {
fn gas_to_weight(gas: u32) -> Weight {
gas as Weight
}
}

/// Substrate system chain ID.
pub struct SystemChainId;

Expand All @@ -223,6 +234,9 @@ pub trait Trait: frame_system::Trait + pallet_timestamp::Trait {
/// Calculator for current gas price.
type FeeCalculator: FeeCalculator;

/// Maps Ethereum gas to Substrate weight.
type GasToWeight: GasToWeight;

/// Allow the origin to call on behalf of given address.
type CallOrigin: EnsureAddressOrigin<Self::Origin>;
/// Allow the origin to withdraw on behalf of given address.
Expand Down Expand Up @@ -356,7 +370,7 @@ decl_module! {
}

/// Issue an EVM call operation. This is similar to a message call transaction in Ethereum.
#[weight = (*gas_price).saturated_into::<Weight>().saturating_mul(*gas_limit as Weight)]
#[weight = T::GasToWeight::gas_to_weight(*gas_limit)]
fn call(
origin,
source: H160,
Expand All @@ -369,32 +383,34 @@ decl_module! {
) -> DispatchResultWithPostInfo {
T::CallOrigin::ensure_address_origin(&source, origin)?;

match T::Runner::call(
let info = T::Runner::call(
source,
target,
input,
value,
gas_limit,
Some(gas_price),
nonce,
)? {
CallInfo {
exit_reason: ExitReason::Succeed(_),
..
} => {
)?;

match info.exit_reason {
ExitReason::Succeed(_) => {
Module::<T>::deposit_event(Event::<T>::Executed(target));
},
_ => {
Module::<T>::deposit_event(Event::<T>::ExecutedFailed(target));
},
}
};

Ok(Pays::No.into())
Ok(PostDispatchInfo {
actual_weight: Some(T::GasToWeight::gas_to_weight(info.used_gas.low_u32())),
pays_fee: Pays::No,
})
}

/// Issue an EVM create operation. This is similar to a contract creation transaction in
/// Ethereum.
#[weight = (*gas_price).saturated_into::<Weight>().saturating_mul(*gas_limit as Weight)]
#[weight = T::GasToWeight::gas_to_weight(*gas_limit)]
fn create(
origin,
source: H160,
Expand All @@ -406,14 +422,16 @@ decl_module! {
) -> DispatchResultWithPostInfo {
T::CallOrigin::ensure_address_origin(&source, origin)?;

match T::Runner::create(
let info = T::Runner::create(
source,
init,
value,
gas_limit,
Some(gas_price),
nonce,
)? {
)?;

match info {
CreateInfo {
exit_reason: ExitReason::Succeed(_),
value: create_address,
Expand All @@ -430,11 +448,14 @@ decl_module! {
},
}

Ok(Pays::No.into())
Ok(PostDispatchInfo {
actual_weight: Some(T::GasToWeight::gas_to_weight(info.used_gas.low_u32())),
pays_fee: Pays::No,
})
}

/// Issue an EVM create2 operation.
#[weight = (*gas_price).saturated_into::<Weight>().saturating_mul(*gas_limit as Weight)]
#[weight = T::GasToWeight::gas_to_weight(*gas_limit)]
fn create2(
origin,
source: H160,
Expand All @@ -447,15 +468,17 @@ decl_module! {
) -> DispatchResultWithPostInfo {
T::CallOrigin::ensure_address_origin(&source, origin)?;

match T::Runner::create2(
let info = T::Runner::create2(
source,
init,
salt,
value,
gas_limit,
Some(gas_price),
nonce,
)? {
)?;

match info {
CreateInfo {
exit_reason: ExitReason::Succeed(_),
value: create_address,
Expand All @@ -472,7 +495,10 @@ decl_module! {
},
}

Ok(Pays::No.into())
Ok(PostDispatchInfo {
actual_weight: Some(T::GasToWeight::gas_to_weight(info.used_gas.low_u32())),
pays_fee: Pays::No,
})
}
}
}
Expand Down
1 change: 1 addition & 0 deletions frame/evm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ impl FeeCalculator for FixedGasPrice {

impl Trait for Test {
type FeeCalculator = FixedGasPrice;
type GasToWeight = ();

type CallOrigin = EnsureAddressRoot<Self::AccountId>;
type WithdrawOrigin = EnsureAddressNever<Self::AccountId>;
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 @@ -284,6 +284,7 @@ parameter_types! {

impl pallet_evm::Trait for Runtime {
type FeeCalculator = FixedGasPrice;
type GasToWeight = ();
type CallOrigin = EnsureAddressTruncated;
type WithdrawOrigin = EnsureAddressTruncated;
type AddressMapping = HashedAddressMapping<BlakeTwo256>;
Expand Down

0 comments on commit 8b73597

Please sign in to comment.