Skip to content

Commit

Permalink
Update the approach to obtain (weight_limit, proof_size_base_cost) (p…
Browse files Browse the repository at this point in the history
…olkadot-evm#1121)

* Move `proof_size_base_cost` out to reuse it

* Add field

* Reuse `transaction_weight`

* Code clean

* Fix clippy
  • Loading branch information
boundless-forest authored and frank0528 committed Sep 24, 2024
1 parent b63bfe1 commit 15be204
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 138 deletions.
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::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 @@ -687,43 +689,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 @@ -735,11 +714,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 @@ -762,46 +741,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 @@ -812,11 +764,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

0 comments on commit 15be204

Please sign in to comment.