Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 20 additions & 52 deletions frame/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ mod tests;
use ethereum_types::{Bloom, BloomInput, H160, H256, H64, U256};
use evm::ExitReason;
use fp_consensus::{PostLog, PreLog, FRONTIER_ENGINE_ID};
use fp_ethereum::{
TransactionData, TransactionValidationError, ValidatedTransaction as ValidatedTransactionT,
};
use fp_ethereum::{TransactionValidationError, ValidatedTransaction as ValidatedTransactionT};
use fp_evm::{
CallOrCreateInfo, CheckEvmTransaction, CheckEvmTransactionConfig, InvalidEvmTransactionError,
};
Expand Down Expand Up @@ -63,6 +61,7 @@ pub use ethereum::{
AccessListItem, BlockV2 as Block, LegacyTransactionMessage, Log, ReceiptV3 as Receipt,
TransactionAction, TransactionV2 as Transaction,
};
pub use fp_ethereum::TransactionData;
pub use fp_rpc::TransactionStatus;

#[derive(Clone, Eq, PartialEq, RuntimeDebug)]
Expand Down Expand Up @@ -353,15 +352,17 @@ pub mod pallet {
}

impl<T: Config> Pallet<T> {
/// The call wrapped in the extrinsic is part of the PoV, record this as a base cost for the size of the proof.
fn proof_size_base_cost(transaction: &Transaction) -> u64 {
transaction
.encode()
.len()
// pallet index
.saturating_add(1)
// call index
.saturating_add(1) as u64
pub fn transaction_weight(transaction_data: &TransactionData) -> (Option<Weight>, Option<u64>) {
match <T as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
transaction_data.gas_limit.unique_saturated_into(),
true,
) {
weight_limit if weight_limit.proof_size() > 0 => (
Some(weight_limit),
Some(transaction_data.proof_size_base_cost.unwrap_or_default()),
),
_ => (None, None),
}
}

fn recover_signer(transaction: &Transaction) -> Option<H160> {
Expand Down Expand Up @@ -483,19 +484,7 @@ impl<T: Config> Pallet<T> {
) -> TransactionValidity {
let transaction_data: TransactionData = transaction.into();
let transaction_nonce = transaction_data.nonce;

let (weight_limit, proof_size_base_cost) =
match <T as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
transaction_data.gas_limit.unique_saturated_into(),
true,
) {
weight_limit if weight_limit.proof_size() > 0 => (
Some(weight_limit),
Some(Self::proof_size_base_cost(transaction)),
),
_ => (None, None),
};

let (weight_limit, proof_size_base_cost) = Self::transaction_weight(&transaction_data);
let (base_fee, _) = T::FeeCalculator::min_gas_price();
let (who, _) = pallet_evm::Pallet::<T>::account_basic(&origin);

Expand Down Expand Up @@ -714,6 +703,11 @@ impl<T: Config> Pallet<T> {
(Option<H160>, Option<H160>, CallOrCreateInfo),
DispatchErrorWithPostInfo<PostDispatchInfo>,
> {
let transaction_data: TransactionData = transaction.into();
let (weight_limit, proof_size_base_cost) = Self::transaction_weight(&transaction_data);
let is_transactional = true;
let validate = false;

let (
input,
value,
Expand Down Expand Up @@ -774,20 +768,6 @@ impl<T: Config> Pallet<T> {
}
};

let is_transactional = true;
let validate = false;

let (proof_size_base_cost, weight_limit) =
match <T as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
gas_limit.unique_saturated_into(),
true,
) {
weight_limit if weight_limit.proof_size() > 0 => (
Some(Self::proof_size_base_cost(transaction)),
Some(weight_limit),
),
_ => (None, None),
};
match action {
ethereum::TransactionAction::Call(target) => {
let res = match T::Runner::call(
Expand Down Expand Up @@ -862,22 +842,10 @@ impl<T: Config> Pallet<T> {
transaction: &Transaction,
) -> Result<(), TransactionValidityError> {
let transaction_data: TransactionData = transaction.into();

let (weight_limit, proof_size_base_cost) = Self::transaction_weight(&transaction_data);
let (base_fee, _) = T::FeeCalculator::min_gas_price();
let (who, _) = pallet_evm::Pallet::<T>::account_basic(&origin);

let (weight_limit, proof_size_base_cost) =
match <T as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
transaction_data.gas_limit.unique_saturated_into(),
true,
) {
weight_limit if weight_limit.proof_size() > 0 => (
Some(weight_limit),
Some(Self::proof_size_base_cost(transaction)),
),
_ => (None, None),
};

let _ = CheckEvmTransaction::<InvalidTransactionWrapper>::new(
CheckEvmTransactionConfig {
evm_config: T::config(),
Expand Down
55 changes: 55 additions & 0 deletions primitives/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,49 @@ pub struct TransactionData {
pub value: U256,
pub chain_id: Option<u64>,
pub access_list: Vec<(H160, Vec<H256>)>,
pub proof_size_base_cost: Option<u64>,
}

impl TransactionData {
#[allow(clippy::too_many_arguments)]
pub fn new(
action: TransactionAction,
input: Vec<u8>,
nonce: U256,
gas_limit: U256,
gas_price: Option<U256>,
max_fee_per_gas: Option<U256>,
max_priority_fee_per_gas: Option<U256>,
value: U256,
chain_id: Option<u64>,
access_list: Vec<(H160, Vec<H256>)>,
) -> Self {
let mut transaction_data = Self {
action,
input,
nonce,
gas_limit,
gas_price,
max_fee_per_gas,
max_priority_fee_per_gas,
value,
chain_id,
access_list,
proof_size_base_cost: None,
};
let proof_size_base_cost = transaction_data
.encode()
.len()
// signature
.saturating_add(65)
// pallet index
.saturating_add(1)
// call index
.saturating_add(1) as u64;
transaction_data.proof_size_base_cost = Some(proof_size_base_cost);

transaction_data
}
}

impl From<TransactionData> for CheckEvmTransactionInput {
Expand All @@ -84,6 +127,15 @@ impl From<TransactionData> for CheckEvmTransactionInput {

impl From<&Transaction> for TransactionData {
fn from(t: &Transaction) -> Self {
// The call wrapped in the extrinsic is part of the PoV, record this as a base cost for the size of the proof.
let proof_size_base_cost = t
.encode()
.len()
// pallet index
.saturating_add(1)
// call index
.saturating_add(1) as u64;

match t {
Transaction::Legacy(t) => TransactionData {
action: t.action,
Expand All @@ -96,6 +148,7 @@ impl From<&Transaction> for TransactionData {
value: t.value,
chain_id: t.signature.chain_id(),
access_list: Vec::new(),
proof_size_base_cost: Some(proof_size_base_cost),
},
Transaction::EIP2930(t) => TransactionData {
action: t.action,
Expand All @@ -112,6 +165,7 @@ impl From<&Transaction> for TransactionData {
.iter()
.map(|d| (d.address, d.storage_keys.clone()))
.collect(),
proof_size_base_cost: Some(proof_size_base_cost),
},
Transaction::EIP1559(t) => TransactionData {
action: t.action,
Expand All @@ -128,6 +182,7 @@ impl From<&Transaction> for TransactionData {
.iter()
.map(|d| (d.address, d.storage_keys.clone()))
.collect(),
proof_size_base_cost: Some(proof_size_base_cost),
},
}
}
Expand Down
124 changes: 38 additions & 86 deletions template/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ use pallet_transaction_payment::{ConstFeeMultiplier, CurrencyAdapter};
use fp_account::EthereumSignature;
use fp_evm::weight_per_gas;
use fp_rpc::TransactionStatus;
use pallet_ethereum::{Call::transact, PostLogContent, Transaction as EthereumTransaction};
use pallet_ethereum::{
Call::transact, PostLogContent, Transaction as EthereumTransaction, TransactionAction,
TransactionData,
};
use pallet_evm::{
Account as EVMAccount, EnsureAccountId20, FeeCalculator, GasWeightMapping,
IdentityAddressMapping, Runner,
Account as EVMAccount, EnsureAccountId20, FeeCalculator, IdentityAddressMapping, Runner,
};

// A few exports that help ease life for downstream crates.
Expand Down Expand Up @@ -688,43 +690,20 @@ impl_runtime_apis! {
None
};

let is_transactional = false;
let validate = true;
let evm_config = config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config());

let mut estimated_transaction_len = data.len() +
20 + // to
20 + // from
32 + // value
32 + // gas_limit
32 + // nonce
1 + // TransactionAction
8 + // chain id
65; // signature

if max_fee_per_gas.is_some() {
estimated_transaction_len += 32;
}
if max_priority_fee_per_gas.is_some() {
estimated_transaction_len += 32;
}
if access_list.is_some() {
estimated_transaction_len += access_list.encoded_size();
}

let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
let without_base_extrinsic_weight = true;

let (weight_limit, proof_size_base_cost) =
match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
gas_limit,
without_base_extrinsic_weight
) {
weight_limit if weight_limit.proof_size() > 0 => {
(Some(weight_limit), Some(estimated_transaction_len as u64))
}
_ => (None, None),
};
let gas_limit = gas_limit.min(u64::MAX.into());
let transaction_data = TransactionData::new(
TransactionAction::Call(to),
data.clone(),
nonce.unwrap_or_default(),
gas_limit,
None,
max_fee_per_gas,
max_priority_fee_per_gas,
value,
Some(<Runtime as pallet_evm::Config>::ChainId::get()),
access_list.clone().unwrap_or_default(),
);
let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);

<Runtime as pallet_evm::Config>::Runner::call(
from,
Expand All @@ -736,11 +715,11 @@ impl_runtime_apis! {
max_priority_fee_per_gas,
nonce,
access_list.unwrap_or_default(),
is_transactional,
validate,
false,
true,
weight_limit,
proof_size_base_cost,
evm_config,
config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
).map_err(|err| err.error.into())
}

Expand All @@ -763,46 +742,19 @@ impl_runtime_apis! {
None
};

let is_transactional = false;
let validate = true;
let evm_config = config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config());

let mut estimated_transaction_len = data.len() +
20 + // from
32 + // value
32 + // gas_limit
32 + // nonce
1 + // TransactionAction
8 + // chain id
65; // signature

if max_fee_per_gas.is_some() {
estimated_transaction_len += 32;
}
if max_priority_fee_per_gas.is_some() {
estimated_transaction_len += 32;
}
if access_list.is_some() {
estimated_transaction_len += access_list.encoded_size();
}

let gas_limit = if gas_limit > U256::from(u64::MAX) {
u64::MAX
} else {
gas_limit.low_u64()
};
let without_base_extrinsic_weight = true;

let (weight_limit, proof_size_base_cost) =
match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
gas_limit,
without_base_extrinsic_weight
) {
weight_limit if weight_limit.proof_size() > 0 => {
(Some(weight_limit), Some(estimated_transaction_len as u64))
}
_ => (None, None),
};
let transaction_data = TransactionData::new(
TransactionAction::Create,
data.clone(),
nonce.unwrap_or_default(),
gas_limit,
None,
max_fee_per_gas,
max_priority_fee_per_gas,
value,
Some(<Runtime as pallet_evm::Config>::ChainId::get()),
access_list.clone().unwrap_or_default(),
);
let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);

<Runtime as pallet_evm::Config>::Runner::create(
from,
Expand All @@ -813,11 +765,11 @@ impl_runtime_apis! {
max_priority_fee_per_gas,
nonce,
access_list.unwrap_or_default(),
is_transactional,
validate,
false,
true,
weight_limit,
proof_size_base_cost,
evm_config,
config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
).map_err(|err| err.error.into())
}

Expand Down