Skip to content

Commit 789993e

Browse files
TarekkMARomarQAgusrodriahmadkaouk
authored andcommitted
Update evm and Cancun support (polkadot-evm#1588)
* update evm version * Cancun support (polkadot-evm#206) * use Cancun config * feat: support transient storage (EIP-1153) * Update evm dependency * Adds a new opcode (MCOPY) for copying memory * feat: support cancun selfdestruct changes (EIP-6780) --------- Co-authored-by: Agusrodri <[email protected]> Co-authored-by: Ahmad Kaouk <[email protected]> * style: formatting * style: fix clippy errors * style: fix issues * revert: test * fix: solidity pragma * fix: fix tests * fix: fix tests * fix gas tests * test:update gas estimation result * use crates.io version * remove Suicided storage and all related items * Remove SuicideQuickClearLimit configuration from EVM precompile and related modules --------- Co-authored-by: Rodrigo Quelhas <[email protected]> Co-authored-by: Agusrodri <[email protected]> Co-authored-by: Ahmad Kaouk <[email protected]> Co-authored-by: Rodrigo Quelhas <[email protected]>
1 parent e2669ea commit 789993e

File tree

23 files changed

+202
-934
lines changed

23 files changed

+202
-934
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ members = [
1515
"frame/evm/precompile/bls12381",
1616
"frame/evm/precompile/dispatch",
1717
"frame/evm/precompile/curve25519",
18-
"frame/evm/precompile/storage-cleaner",
1918
"frame/evm-chain-id",
2019
"frame/hotfix-sufficients",
2120
"client/api",
@@ -57,7 +56,7 @@ derive_more = "0.99"
5756
environmental = { version = "1.1.4", default-features = false }
5857
ethereum = { version = "0.15.0", default-features = false }
5958
ethereum-types = { version = "0.14.1", default-features = false }
60-
evm = { version = "0.41.1", default-features = false }
59+
evm = { version = "0.42.0", default-features = false }
6160
futures = "0.3.31"
6261
hash-db = { version = "0.16.0", default-features = false }
6362
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }

frame/evm/precompile/dispatch/src/mock.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,6 @@ impl FindAuthor<H160> for FindAuthorTruncated {
167167
parameter_types! {
168168
pub BlockGasLimit: U256 = U256::max_value();
169169
pub WeightPerGas: Weight = Weight::from_parts(20_000, 0);
170-
pub SuicideQuickClearLimit: u32 = 0;
171170
}
172171
impl pallet_evm::Config for Test {
173172
type AccountProvider = pallet_evm::FrameSystemAccountProvider<Self>;
@@ -193,7 +192,6 @@ impl pallet_evm::Config for Test {
193192
type OnChargeTransaction = ();
194193
type OnCreate = ();
195194
type FindAuthor = FindAuthorTruncated;
196-
type SuicideQuickClearLimit = SuicideQuickClearLimit;
197195
type GasLimitPovSizeRatio = ();
198196
type GasLimitStorageGrowthRatio = ();
199197
type Timestamp = Timestamp;

frame/evm/precompile/storage-cleaner/Cargo.toml

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 0 additions & 212 deletions
Original file line numberDiff line numberDiff line change
@@ -1,212 +0,0 @@
1-
// This file is part of Frontier.
2-
3-
// Copyright (C) Parity Technologies (UK) Ltd.
4-
// SPDX-License-Identifier: Apache-2.0
5-
6-
// Licensed under the Apache License, Version 2.0 (the "License");
7-
// you may not use this file except in compliance with the License.
8-
// You may obtain a copy of the License at
9-
//
10-
// http://www.apache.org/licenses/LICENSE-2.0
11-
//
12-
// Unless required by applicable law or agreed to in writing, software
13-
// distributed under the License is distributed on an "AS IS" BASIS,
14-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15-
// See the License for the specific language governing permissions and
16-
// limitations under the License.
17-
18-
//! Storage cleaner precompile. This precompile is used to clean the storage entries of smart contract that
19-
//! has been marked as suicided (self-destructed).
20-
21-
#![cfg_attr(not(feature = "std"), no_std)]
22-
extern crate alloc;
23-
24-
use alloc::vec::Vec;
25-
use core::marker::PhantomData;
26-
use fp_evm::{
27-
AccountProvider, PrecompileFailure, ACCOUNT_BASIC_PROOF_SIZE, ACCOUNT_STORAGE_PROOF_SIZE,
28-
};
29-
use pallet_evm::AddressMapping;
30-
use precompile_utils::{prelude::*, EvmResult};
31-
use sp_core::H160;
32-
use sp_runtime::traits::ConstU32;
33-
34-
#[cfg(test)]
35-
mod mock;
36-
#[cfg(test)]
37-
mod tests;
38-
39-
pub const ARRAY_LIMIT: u32 = 1_000;
40-
type GetArrayLimit = ConstU32<ARRAY_LIMIT>;
41-
// Storage key for suicided contracts: Blake2_128(16) + Key (H160(20))
42-
pub const SUICIDED_STORAGE_KEY: u64 = 36;
43-
44-
#[derive(Debug, Clone)]
45-
pub struct StorageCleanerPrecompile<Runtime>(PhantomData<Runtime>);
46-
47-
#[precompile_utils::precompile]
48-
impl<Runtime> StorageCleanerPrecompile<Runtime>
49-
where
50-
Runtime: pallet_evm::Config,
51-
{
52-
/// Clear Storage entries of smart contracts that has been marked as suicided (self-destructed). It takes a list of
53-
/// addresses and a limit as input. The limit is used to prevent the function from consuming too much gas. The
54-
/// maximum number of storage entries that can be removed is limit - 1.
55-
#[precompile::public("clearSuicidedStorage(address[],uint64)")]
56-
fn clear_suicided_storage(
57-
handle: &mut impl PrecompileHandle,
58-
addresses: BoundedVec<Address, GetArrayLimit>,
59-
limit: u64,
60-
) -> EvmResult {
61-
let addresses: Vec<_> = addresses.into();
62-
let nb_addresses = addresses.len() as u64;
63-
if limit == 0 {
64-
return Err(revert("Limit should be greater than zero"));
65-
}
66-
67-
Self::record_max_cost(handle, nb_addresses, limit)?;
68-
let result = Self::clear_suicided_storage_inner(addresses, limit - 1)?;
69-
Self::refund_cost(handle, result, nb_addresses, limit);
70-
71-
Ok(())
72-
}
73-
74-
/// This function iterates over the addresses, checks if each address is marked as suicided, and then deletes the storage
75-
/// entries associated with that address. If there are no remaining entries, we clear the suicided contract by calling the
76-
/// `clear_suicided_contract` function.
77-
fn clear_suicided_storage_inner(
78-
addresses: Vec<Address>,
79-
limit: u64,
80-
) -> Result<RemovalResult, PrecompileFailure> {
81-
let mut deleted_entries = 0u64;
82-
let mut deleted_contracts = 0u64;
83-
84-
for Address(address) in addresses {
85-
if !pallet_evm::Pallet::<Runtime>::is_account_suicided(&address) {
86-
return Err(revert(alloc::format!("NotSuicided: {}", address)));
87-
}
88-
89-
let deleted = pallet_evm::AccountStorages::<Runtime>::drain_prefix(address)
90-
.take((limit.saturating_sub(deleted_entries)) as usize)
91-
.count();
92-
deleted_entries = deleted_entries.saturating_add(deleted as u64);
93-
94-
// Check if the storage of this contract has been completely removed
95-
if pallet_evm::AccountStorages::<Runtime>::iter_key_prefix(address)
96-
.next()
97-
.is_none()
98-
{
99-
Self::clear_suicided_contract(address);
100-
deleted_contracts = deleted_contracts.saturating_add(1);
101-
}
102-
103-
if deleted_entries >= limit {
104-
break;
105-
}
106-
}
107-
108-
Ok(RemovalResult {
109-
deleted_entries,
110-
deleted_contracts,
111-
})
112-
}
113-
114-
/// Record the maximum cost (Worst case Scenario) of the clear_suicided_storage function.
115-
fn record_max_cost(
116-
handle: &mut impl PrecompileHandle,
117-
nb_addresses: u64,
118-
limit: u64,
119-
) -> EvmResult {
120-
let read_cost = RuntimeHelper::<Runtime>::db_read_gas_cost();
121-
let write_cost = RuntimeHelper::<Runtime>::db_write_gas_cost();
122-
let ref_time = 0u64
123-
// EVM:: Suicided (reads = nb_addresses)
124-
.saturating_add(read_cost.saturating_mul(nb_addresses))
125-
// EVM:: Suicided (writes = nb_addresses)
126-
.saturating_add(write_cost.saturating_mul(nb_addresses))
127-
// System: AccountInfo (reads = nb_addresses) for decrementing sufficients
128-
.saturating_add(read_cost.saturating_mul(nb_addresses))
129-
// System: AccountInfo (writes = nb_addresses) for decrementing sufficients
130-
.saturating_add(write_cost.saturating_mul(nb_addresses))
131-
// EVM: AccountStorage (reads = limit)
132-
.saturating_add(read_cost.saturating_mul(limit))
133-
// EVM: AccountStorage (writes = limit)
134-
.saturating_add(write_cost.saturating_mul(limit));
135-
136-
let proof_size = 0u64
137-
// Proof: EVM::Suicided (SUICIDED_STORAGE_KEY) * nb_addresses
138-
.saturating_add(SUICIDED_STORAGE_KEY.saturating_mul(nb_addresses))
139-
// Proof: EVM::AccountStorage (ACCOUNT_BASIC_PROOF_SIZE) * limit
140-
.saturating_add(ACCOUNT_STORAGE_PROOF_SIZE.saturating_mul(limit))
141-
// Proof: System::AccountInfo (ACCOUNT_BASIC_PROOF_SIZE) * nb_addresses
142-
.saturating_add(ACCOUNT_BASIC_PROOF_SIZE.saturating_mul(nb_addresses));
143-
144-
handle.record_external_cost(Some(ref_time), Some(proof_size), None)?;
145-
Ok(())
146-
}
147-
148-
/// Refund the additional cost recorded for the clear_suicided_storage function.
149-
fn refund_cost(
150-
handle: &mut impl PrecompileHandle,
151-
result: RemovalResult,
152-
nb_addresses: u64,
153-
limit: u64,
154-
) {
155-
let read_cost = RuntimeHelper::<Runtime>::db_read_gas_cost();
156-
let write_cost = RuntimeHelper::<Runtime>::db_write_gas_cost();
157-
158-
let extra_entries = limit.saturating_sub(result.deleted_entries);
159-
let extra_contracts = nb_addresses.saturating_sub(result.deleted_contracts);
160-
161-
let mut ref_time = 0u64;
162-
let mut proof_size = 0u64;
163-
164-
// Refund the cost of the remaining entries
165-
if extra_entries > 0 {
166-
ref_time = ref_time
167-
// EVM:: AccountStorage (reads = extra_entries)
168-
.saturating_add(read_cost.saturating_mul(extra_entries))
169-
// EVM:: AccountStorage (writes = extra_entries)
170-
.saturating_add(write_cost.saturating_mul(extra_entries));
171-
proof_size = proof_size
172-
// Proof: EVM::AccountStorage (ACCOUNT_BASIC_PROOF_SIZE) * extra_entries
173-
.saturating_add(ACCOUNT_STORAGE_PROOF_SIZE.saturating_mul(extra_entries));
174-
}
175-
176-
// Refund the cost of the remaining contracts
177-
if extra_contracts > 0 {
178-
ref_time = ref_time
179-
// EVM:: Suicided (reads = extra_contracts)
180-
.saturating_add(read_cost.saturating_mul(extra_contracts))
181-
// EVM:: Suicided (writes = extra_contracts)
182-
.saturating_add(write_cost.saturating_mul(extra_contracts))
183-
// System: AccountInfo (reads = extra_contracts) for decrementing sufficients
184-
.saturating_add(read_cost.saturating_mul(extra_contracts))
185-
// System: AccountInfo (writes = extra_contracts) for decrementing sufficients
186-
.saturating_add(write_cost.saturating_mul(extra_contracts));
187-
proof_size = proof_size
188-
// Proof: EVM::Suicided (SUICIDED_STORAGE_KEY) * extra_contracts
189-
.saturating_add(SUICIDED_STORAGE_KEY.saturating_mul(extra_contracts))
190-
// Proof: System::AccountInfo (ACCOUNT_BASIC_PROOF_SIZE) * extra_contracts
191-
.saturating_add(ACCOUNT_BASIC_PROOF_SIZE.saturating_mul(extra_contracts));
192-
}
193-
194-
handle.refund_external_cost(Some(ref_time), Some(proof_size));
195-
}
196-
197-
/// Clears the storage of a suicided contract.
198-
///
199-
/// This function will remove the given address from the list of suicided contracts
200-
/// and decrement the sufficients of the account associated with the address.
201-
fn clear_suicided_contract(address: H160) {
202-
pallet_evm::Suicided::<Runtime>::remove(address);
203-
204-
let account_id = Runtime::AddressMapping::into_account_id(address);
205-
Runtime::AccountProvider::remove_account(&account_id);
206-
}
207-
}
208-
209-
struct RemovalResult {
210-
pub deleted_entries: u64,
211-
pub deleted_contracts: u64,
212-
}

0 commit comments

Comments
 (0)