Skip to content

Commit 4f30b70

Browse files
committed
Add EVM rent calculation pallet and validation
1 parent 3f44d54 commit 4f30b70

17 files changed

Lines changed: 687 additions & 2 deletions

File tree

Cargo.lock

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ members = [
1616
"frame/evm/precompile/bls12377",
1717
"frame/evm/precompile/dispatch",
1818
"frame/evm/precompile/curve25519",
19+
"frame/evm-rent",
1920
"client/api",
2021
"client/consensus",
2122
"client/rpc-core",
@@ -41,6 +42,7 @@ members = [
4142
"primitives/bifrost/rpc/evm-tracing-events",
4243
"primitives/bifrost/rpc/debug",
4344
"primitives/bifrost/rpc/txpool",
45+
"primitives/rent",
4446
"runtime/evm-tracer",
4547
"template/node",
4648
"template/runtime",
@@ -192,6 +194,7 @@ fp-evm = { version = "3.0.0-dev", path = "primitives/evm", default-features = fa
192194
fp-rpc = { version = "3.0.0-dev", path = "primitives/rpc", default-features = false }
193195
fp-self-contained = { version = "1.0.0-dev", path = "primitives/self-contained", default-features = false }
194196
fp-storage = { version = "2.0.0", path = "primitives/storage", default-features = false }
197+
fp-rent = { version = "2.0.0-dev", path = "primitives/rent", default-features = false }
195198
# Frontier BIFROST Primitive
196199
fp-ext = { version = "0.1.0", path = "primitives/bifrost/ext", default-features = false }
197200
fp-rpc-debug = { version = "0.1.0", path = "primitives/bifrost/rpc/debug", default-features = false }
@@ -211,6 +214,7 @@ pallet-evm-precompile-sha3fips = { version = "2.0.0-dev", path = "frame/evm/prec
211214
pallet-evm-precompile-simple = { version = "2.0.0-dev", path = "frame/evm/precompile/simple", default-features = false }
212215
pallet-evm-test-vector-support = { version = "1.0.0-dev", path = "frame/evm/test-vector-support" }
213216
pallet-hotfix-sufficients = { version = "1.0.0", path = "frame/hotfix-sufficients", default-features = false }
217+
pallet-evm-rent = { version = "1.0.0", path = "frame/evm-rent", default-features = false}
214218
# Frontier Template
215219
frontier-template-runtime = { path = "template/runtime", default-features = false }
216220
# Frontier Utility

client/rpc/src/eth/format.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ impl Geth {
4848
"max priority fee per gas higher than max fee per gas".into()
4949
}
5050
VError::InvalidFeeInput => "invalid fee input".into(),
51+
VError::InsufficientRent => "insufficient balance for rent + gas * price + value".into(),
5152
_ => "transaction validation error".into(),
5253
},
5354
_ => "unknown error".into(),

frame/ethereum/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ fp-evm = { workspace = true }
2929
fp-rpc = { workspace = true }
3030
fp-storage = { workspace = true }
3131
pallet-evm = { workspace = true }
32+
fp-rent = { workspace = true }
3233

3334
[dev-dependencies]
3435
hex = { workspace = true }
@@ -64,6 +65,7 @@ std = [
6465
"fp-self-contained/std",
6566
"fp-storage/std",
6667
"pallet-evm/std",
68+
"fp-rent/std",
6769
]
6870
runtime-benchmarks = [
6971
"frame-support/runtime-benchmarks",

frame/ethereum/src/lib.rs

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ use fp_evm::{
6464
CallOrCreateInfo, CheckEvmTransaction, CheckEvmTransactionConfig, TransactionValidationError,
6565
};
6666
pub use fp_rpc::TransactionStatus;
67+
pub use fp_rent::EvmRentCalculator;
6768
use fp_storage::{EthereumStorageSchema, PALLET_ETHEREUM_SCHEMA};
6869
use pallet_evm::{BlockHashMapping, FeeCalculator, GasWeightMapping, Runner};
6970

@@ -489,6 +490,43 @@ impl<T: Config> Pallet<T> {
489490
}
490491
}
491492

493+
fn calculate_max_transaction_fee(
494+
transaction_data: &TransactionData,
495+
) -> Result<U256, TransactionValidityError> {
496+
match (
497+
transaction_data.gas_price,
498+
transaction_data.max_fee_per_gas,
499+
transaction_data.max_priority_fee_per_gas,
500+
) {
501+
// Legacy or EIP-2930 transaction
502+
(Some(gas_price), None, None) => {
503+
Ok(gas_price.saturating_mul(transaction_data.gas_limit))
504+
},
505+
506+
// EIP-1559 transaction without tip
507+
(None, Some(max_fee_per_gas), None) => {
508+
Ok(max_fee_per_gas.saturating_mul(transaction_data.gas_limit))
509+
},
510+
511+
// EIP-1559 with tip
512+
(None, Some(max_fee_per_gas), Some(max_priority_fee_per_gas)) => {
513+
if max_priority_fee_per_gas > max_fee_per_gas {
514+
return Err(TransactionValidityError::Invalid(
515+
InvalidTransaction::Custom(TransactionValidationError::PriorityFeeTooHigh as u8)
516+
));
517+
}
518+
Ok(max_fee_per_gas.saturating_mul(transaction_data.gas_limit))
519+
}
520+
521+
_ => {
522+
// must be transactional tx
523+
Err(TransactionValidityError::Invalid(
524+
InvalidTransaction::Custom(TransactionValidationError::InvalidFeeInput as u8)
525+
))
526+
}
527+
}
528+
}
529+
492530
// Controls that must be performed by the pool.
493531
// The controls common with the State Transition Function (STF) are in
494532
// the function `validate_transaction_common`.
@@ -520,6 +558,22 @@ impl<T: Config> Pallet<T> {
520558
.and_then(|v| v.with_balance_for(&who))
521559
.map_err(|e| e.0)?;
522560

561+
let rent_amount = T::EvmRentCalculator::estimate_rent(origin).0;
562+
if rent_amount > 0 {
563+
let fee = Self::calculate_max_transaction_fee(&transaction_data)?;
564+
565+
let total_payment = transaction_data.value.saturating_add(fee);
566+
let total_with_rent = total_payment.saturating_add(U256::from(rent_amount));
567+
568+
if who.balance < total_with_rent {
569+
return Err(
570+
TransactionValidityError::Invalid(
571+
InvalidTransaction::Custom(TransactionValidationError::InsufficientRent as u8)
572+
)
573+
);
574+
}
575+
}
576+
523577
// EIP-3607: https://eips.ethereum.org/EIPS/eip-3607
524578
// Do not allow transactions for which `tx.sender` has any code deployed.
525579
//
@@ -948,7 +1002,7 @@ impl<T: Config> Pallet<T> {
9481002
chain_id: T::ChainId::get(),
9491003
is_transactional: true,
9501004
},
951-
transaction_data.into(),
1005+
transaction_data.clone().into(),
9521006
weight_limit,
9531007
proof_size_base_cost,
9541008
)
@@ -958,6 +1012,22 @@ impl<T: Config> Pallet<T> {
9581012
.and_then(|v| v.with_balance_for(&who))
9591013
.map_err(|e| TransactionValidityError::Invalid(e.0))?;
9601014

1015+
let rent_amount = T::EvmRentCalculator::estimate_rent(origin).0;
1016+
if rent_amount > 0 {
1017+
let fee = Self::calculate_max_transaction_fee(&transaction_data)?;
1018+
1019+
let total_payment = transaction_data.value.saturating_add(fee);
1020+
let total_with_rent = total_payment.saturating_add(U256::from(rent_amount));
1021+
1022+
if who.balance < total_with_rent {
1023+
return Err(
1024+
TransactionValidityError::Invalid(
1025+
InvalidTransaction::Custom(TransactionValidationError::InsufficientRent as u8)
1026+
)
1027+
);
1028+
}
1029+
}
1030+
9611031
Ok(())
9621032
}
9631033

@@ -1094,6 +1164,9 @@ impl From<TransactionValidationError> for InvalidTransactionWrapper {
10941164
TransactionValidationError::GasPriceTooLow => InvalidTransactionWrapper(
10951165
InvalidTransaction::Custom(TransactionValidationError::GasPriceTooLow as u8),
10961166
),
1167+
TransactionValidationError::InsufficientRent => InvalidTransactionWrapper(
1168+
InvalidTransaction::Custom(TransactionValidationError::InsufficientRent as u8),
1169+
),
10971170
TransactionValidationError::UnknownError => InvalidTransactionWrapper(
10981171
InvalidTransaction::Custom(TransactionValidationError::UnknownError as u8),
10991172
),

frame/ethereum/src/mock.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ impl pallet_evm::Config for Test {
177177
type GasLimitPovSizeRatio = GasLimitPovSizeRatio;
178178
type SuicideQuickClearLimit = SuicideQuickClearLimit;
179179
type Timestamp = Timestamp;
180+
type EvmRentCalculator = ();
180181
type WeightInfo = ();
181182
}
182183

frame/evm-rent/Cargo.toml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
[package]
2+
name = "pallet-evm-rent"
3+
version = "1.0.0"
4+
authors = ["Parity Technologies <admin@parity.io>"]
5+
edition = "2021"
6+
license = "Apache-2.0"
7+
homepage = "https://substrate.dev"
8+
repository = "https://github.com/paritytech/frontier/"
9+
description = "EVM account rent calculation and processing"
10+
11+
[package.metadata.docs.rs]
12+
targets = ["x86_64-unknown-linux-gnu"]
13+
14+
[dependencies]
15+
scale-codec = { package = "parity-scale-codec", workspace = true }
16+
scale-info = { workspace = true }
17+
sp-core = { workspace = true }
18+
sp-runtime = { workspace = true }
19+
frame-support = { workspace = true }
20+
frame-system = { workspace = true }
21+
pallet-timestamp = { workspace = true }
22+
23+
fp-rent = { version = "2.0.0-dev", default-features = false, path = "../../primitives/rent" }
24+
25+
[dev-dependencies]
26+
sp-io = { workspace = true }
27+
sp-std = { workspace = true }
28+
29+
[features]
30+
default = ["std"]
31+
std = [
32+
"scale-codec/std",
33+
"scale-info/std",
34+
"sp-core/std",
35+
"sp-runtime/std",
36+
"frame-support/std",
37+
"frame-system/std",
38+
39+
"pallet-timestamp/std",
40+
41+
"fp-rent/std",
42+
]

0 commit comments

Comments
 (0)