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
26 changes: 26 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ members = [
"frame/evm/precompile/bls12377",
"frame/evm/precompile/dispatch",
"frame/evm/precompile/curve25519",
"frame/evm-rent",
"client/api",
"client/consensus",
"client/rpc-core",
Expand All @@ -41,6 +42,7 @@ members = [
"primitives/bifrost/rpc/evm-tracing-events",
"primitives/bifrost/rpc/debug",
"primitives/bifrost/rpc/txpool",
"primitives/rent",
"runtime/evm-tracer",
"template/node",
"template/runtime",
Expand Down Expand Up @@ -192,6 +194,7 @@ fp-evm = { version = "3.0.0-dev", path = "primitives/evm", default-features = fa
fp-rpc = { version = "3.0.0-dev", path = "primitives/rpc", default-features = false }
fp-self-contained = { version = "1.0.0-dev", path = "primitives/self-contained", default-features = false }
fp-storage = { version = "2.0.0", path = "primitives/storage", default-features = false }
fp-rent = { version = "2.0.0-dev", path = "primitives/rent", default-features = false }
# Frontier BIFROST Primitive
fp-ext = { version = "0.1.0", path = "primitives/bifrost/ext", default-features = false }
fp-rpc-debug = { version = "0.1.0", path = "primitives/bifrost/rpc/debug", default-features = false }
Expand All @@ -211,6 +214,7 @@ pallet-evm-precompile-sha3fips = { version = "2.0.0-dev", path = "frame/evm/prec
pallet-evm-precompile-simple = { version = "2.0.0-dev", path = "frame/evm/precompile/simple", default-features = false }
pallet-evm-test-vector-support = { version = "1.0.0-dev", path = "frame/evm/test-vector-support" }
pallet-hotfix-sufficients = { version = "1.0.0", path = "frame/hotfix-sufficients", default-features = false }
pallet-evm-rent = { version = "1.0.0", path = "frame/evm-rent", default-features = false}
# Frontier Template
frontier-template-runtime = { path = "template/runtime", default-features = false }
# Frontier Utility
Expand Down
1 change: 1 addition & 0 deletions client/rpc/src/eth/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ impl Geth {
"max priority fee per gas higher than max fee per gas".into()
}
VError::InvalidFeeInput => "invalid fee input".into(),
VError::InsufficientRent => "insufficient balance for rent + gas * price + value".into(),
_ => "transaction validation error".into(),
},
_ => "unknown error".into(),
Expand Down
2 changes: 2 additions & 0 deletions frame/ethereum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ fp-evm = { workspace = true }
fp-rpc = { workspace = true }
fp-storage = { workspace = true }
pallet-evm = { workspace = true }
fp-rent = { workspace = true }

[dev-dependencies]
hex = { workspace = true }
Expand Down Expand Up @@ -64,6 +65,7 @@ std = [
"fp-self-contained/std",
"fp-storage/std",
"pallet-evm/std",
"fp-rent/std",
]
runtime-benchmarks = [
"frame-support/runtime-benchmarks",
Expand Down
75 changes: 74 additions & 1 deletion frame/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ use fp_evm::{
CallOrCreateInfo, CheckEvmTransaction, CheckEvmTransactionConfig, TransactionValidationError,
};
pub use fp_rpc::TransactionStatus;
pub use fp_rent::EvmRentCalculator;
use fp_storage::{EthereumStorageSchema, PALLET_ETHEREUM_SCHEMA};
use pallet_evm::{BlockHashMapping, FeeCalculator, GasWeightMapping, Runner};

Expand Down Expand Up @@ -489,6 +490,43 @@ impl<T: Config> Pallet<T> {
}
}

fn calculate_max_transaction_fee(
transaction_data: &TransactionData,
) -> Result<U256, TransactionValidityError> {
match (
transaction_data.gas_price,
transaction_data.max_fee_per_gas,
transaction_data.max_priority_fee_per_gas,
) {
// Legacy or EIP-2930 transaction
(Some(gas_price), None, None) => {
Ok(gas_price.saturating_mul(transaction_data.gas_limit))
},

// EIP-1559 transaction without tip
(None, Some(max_fee_per_gas), None) => {
Ok(max_fee_per_gas.saturating_mul(transaction_data.gas_limit))
},

// EIP-1559 with tip
(None, Some(max_fee_per_gas), Some(max_priority_fee_per_gas)) => {
if max_priority_fee_per_gas > max_fee_per_gas {
return Err(TransactionValidityError::Invalid(
InvalidTransaction::Custom(TransactionValidationError::PriorityFeeTooHigh as u8)
));
}
Ok(max_fee_per_gas.saturating_mul(transaction_data.gas_limit))
}

_ => {
// must be transactional tx
Err(TransactionValidityError::Invalid(
InvalidTransaction::Custom(TransactionValidationError::InvalidFeeInput as u8)
))
}
}
}

// Controls that must be performed by the pool.
// The controls common with the State Transition Function (STF) are in
// the function `validate_transaction_common`.
Expand Down Expand Up @@ -520,6 +558,22 @@ impl<T: Config> Pallet<T> {
.and_then(|v| v.with_balance_for(&who))
.map_err(|e| e.0)?;

let rent_amount = T::EvmRentCalculator::estimate_rent(origin).0;
if rent_amount > 0 {
let fee = Self::calculate_max_transaction_fee(&transaction_data)?;

let total_payment = transaction_data.value.saturating_add(fee);
let total_with_rent = total_payment.saturating_add(U256::from(rent_amount));

if who.balance < total_with_rent {
return Err(
TransactionValidityError::Invalid(
InvalidTransaction::Custom(TransactionValidationError::InsufficientRent as u8)
)
);
}
}

// EIP-3607: https://eips.ethereum.org/EIPS/eip-3607
// Do not allow transactions for which `tx.sender` has any code deployed.
//
Expand Down Expand Up @@ -948,7 +1002,7 @@ impl<T: Config> Pallet<T> {
chain_id: T::ChainId::get(),
is_transactional: true,
},
transaction_data.into(),
transaction_data.clone().into(),
weight_limit,
proof_size_base_cost,
)
Expand All @@ -958,6 +1012,22 @@ impl<T: Config> Pallet<T> {
.and_then(|v| v.with_balance_for(&who))
.map_err(|e| TransactionValidityError::Invalid(e.0))?;

let rent_amount = T::EvmRentCalculator::estimate_rent(origin).0;
if rent_amount > 0 {
let fee = Self::calculate_max_transaction_fee(&transaction_data)?;

let total_payment = transaction_data.value.saturating_add(fee);
let total_with_rent = total_payment.saturating_add(U256::from(rent_amount));

if who.balance < total_with_rent {
return Err(
TransactionValidityError::Invalid(
InvalidTransaction::Custom(TransactionValidationError::InsufficientRent as u8)
)
);
}
}

Ok(())
}

Expand Down Expand Up @@ -1094,6 +1164,9 @@ impl From<TransactionValidationError> for InvalidTransactionWrapper {
TransactionValidationError::GasPriceTooLow => InvalidTransactionWrapper(
InvalidTransaction::Custom(TransactionValidationError::GasPriceTooLow as u8),
),
TransactionValidationError::InsufficientRent => InvalidTransactionWrapper(
InvalidTransaction::Custom(TransactionValidationError::InsufficientRent as u8),
),
TransactionValidationError::UnknownError => InvalidTransactionWrapper(
InvalidTransaction::Custom(TransactionValidationError::UnknownError as u8),
),
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 @@ -177,6 +177,7 @@ impl pallet_evm::Config for Test {
type GasLimitPovSizeRatio = GasLimitPovSizeRatio;
type SuicideQuickClearLimit = SuicideQuickClearLimit;
type Timestamp = Timestamp;
type EvmRentCalculator = ();
type WeightInfo = ();
}

Expand Down
42 changes: 42 additions & 0 deletions frame/evm-rent/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[package]
name = "pallet-evm-rent"
version = "1.0.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
license = "Apache-2.0"
homepage = "https://substrate.dev"
repository = "https://github.com/paritytech/frontier/"
description = "EVM account rent calculation and processing"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
scale-codec = { package = "parity-scale-codec", workspace = true }
scale-info = { workspace = true }
sp-core = { workspace = true }
sp-runtime = { workspace = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
pallet-timestamp = { workspace = true }

fp-rent = { version = "2.0.0-dev", default-features = false, path = "../../primitives/rent" }

[dev-dependencies]
sp-io = { workspace = true }
sp-std = { workspace = true }

[features]
default = ["std"]
std = [
"scale-codec/std",
"scale-info/std",
"sp-core/std",
"sp-runtime/std",
"frame-support/std",
"frame-system/std",

"pallet-timestamp/std",

"fp-rent/std",
]
Loading