Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update evm and Cancun support #1588

16 changes: 8 additions & 8 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ derive_more = "0.99"
environmental = { version = "1.1.4", default-features = false }
ethereum = { version = "0.15.0", default-features = false }
ethereum-types = { version = "0.14.1", default-features = false }
evm = { version = "0.41.1", default-features = false }
evm = { version = "0.42.0", default-features = false }
futures = "0.3.31"
hash-db = { version = "0.16.0", default-features = false }
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
Expand Down
29 changes: 5 additions & 24 deletions frame/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ use scale_info::TypeInfo;
// Substrate
use frame_support::{
dispatch::{DispatchResultWithPostInfo, Pays, PostDispatchInfo},
storage::{child::KillStorageResult, KeyPrefixIterator},
storage::KeyPrefixIterator,
traits::{
fungible::{Balanced, Credit, Debt},
tokens::{
Expand Down Expand Up @@ -207,7 +207,7 @@ pub mod pallet {

/// EVM config used in the module.
fn config() -> &'static EvmConfig {
&SHANGHAI_CONFIG
&CANCUN_CONFIG
}
}

Expand Down Expand Up @@ -906,7 +906,7 @@ where
}
}

static SHANGHAI_CONFIG: EvmConfig = EvmConfig::shanghai();
static CANCUN_CONFIG: EvmConfig = EvmConfig::cancun();

impl<T: Config> Pallet<T> {
/// Check whether an account is empty.
Expand Down Expand Up @@ -935,32 +935,13 @@ impl<T: Config> Pallet<T> {
/// Remove an account.
pub fn remove_account(address: &H160) {
if <AccountCodes<T>>::contains_key(address) {
// Remember to call `dec_sufficients` when clearing Suicided.
<Suicided<T>>::insert(address, ());
TarekkMA marked this conversation as resolved.
Show resolved Hide resolved

// In theory, we can always have pre-EIP161 contracts, so we
// make sure the account nonce is at least one.
let account_id = T::AddressMapping::into_account_id(*address);
T::AccountProvider::inc_account_nonce(&account_id);
T::AccountProvider::remove_account(&account_id);
}

<AccountCodes<T>>::remove(address);
<AccountCodesMetadata<T>>::remove(address);

if T::SuicideQuickClearLimit::get() > 0 {
TarekkMA marked this conversation as resolved.
Show resolved Hide resolved
#[allow(deprecated)]
let res = <AccountStorages<T>>::remove_prefix(address, Some(T::SuicideQuickClearLimit::get()));

match res {
KillStorageResult::AllRemoved(_) => {
<Suicided<T>>::remove(address);

let account_id = T::AddressMapping::into_account_id(*address);
T::AccountProvider::remove_account(&account_id);
}
KillStorageResult::SomeRemaining(_) => (),
}
}
let _ = <AccountStorages<T>>::clear_prefix(address, u32::MAX, None);
}

/// Create an account.
Expand Down
42 changes: 41 additions & 1 deletion frame/evm/src/runner/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ where
struct SubstrateStackSubstate<'config> {
metadata: StackSubstateMetadata<'config>,
deletes: BTreeSet<H160>,
creates: BTreeSet<H160>,
logs: Vec<Log>,
parent: Option<Box<SubstrateStackSubstate<'config>>>,
}
Expand All @@ -636,6 +637,7 @@ impl<'config> SubstrateStackSubstate<'config> {
metadata: self.metadata.spit_child(gas_limit, is_static),
parent: None,
deletes: BTreeSet::new(),
creates: BTreeSet::new(),
logs: Vec::new(),
};
mem::swap(&mut entering, self);
Expand All @@ -652,7 +654,7 @@ impl<'config> SubstrateStackSubstate<'config> {
self.metadata.swallow_commit(exited.metadata)?;
self.logs.append(&mut exited.logs);
self.deletes.append(&mut exited.deletes);

self.creates.append(&mut exited.creates);
sp_io::storage::commit_transaction();
Ok(())
}
Expand Down Expand Up @@ -687,10 +689,26 @@ impl<'config> SubstrateStackSubstate<'config> {
false
}

pub fn created(&self, address: H160) -> bool {
if self.creates.contains(&address) {
return true;
}

if let Some(parent) = self.parent.as_ref() {
return parent.created(address);
}

false
}

pub fn set_deleted(&mut self, address: H160) {
self.deletes.insert(address);
}

pub fn set_created(&mut self, address: H160) {
self.creates.insert(address);
}

pub fn log(&mut self, address: H160, topics: Vec<H256>, data: Vec<u8>) {
self.logs.push(Log {
address,
Expand Down Expand Up @@ -723,6 +741,7 @@ pub struct SubstrateStackState<'vicinity, 'config, T> {
vicinity: &'vicinity Vicinity,
substate: SubstrateStackSubstate<'config>,
original_storage: BTreeMap<(H160, H256), H256>,
transient_storage: BTreeMap<(H160, H256), H256>,
recorded: Recorded,
weight_info: Option<WeightInfo>,
storage_meter: Option<StorageMeter>,
Expand All @@ -743,11 +762,13 @@ impl<'vicinity, 'config, T: Config> SubstrateStackState<'vicinity, 'config, T> {
substate: SubstrateStackSubstate {
metadata,
deletes: BTreeSet::new(),
creates: BTreeSet::new(),
logs: Vec::new(),
parent: None,
},
_marker: PhantomData,
original_storage: BTreeMap::new(),
transient_storage: BTreeMap::new(),
recorded: Default::default(),
weight_info,
storage_meter,
Expand Down Expand Up @@ -842,6 +863,13 @@ where
<AccountStorages<T>>::get(address, index)
}

fn transient_storage(&self, address: H160, index: H256) -> H256 {
self.transient_storage
.get(&(address, index))
.copied()
.unwrap_or_default()
}

fn original_storage(&self, address: H160, index: H256) -> Option<H256> {
Some(
self.original_storage
Expand Down Expand Up @@ -889,6 +917,10 @@ where
self.substate.deleted(address)
}

fn created(&self, address: H160) -> bool {
self.substate.created(address)
}

fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError> {
let account_id = T::AddressMapping::into_account_id(address);
T::AccountProvider::inc_account_nonce(&account_id);
Expand Down Expand Up @@ -928,6 +960,10 @@ where
}
}

fn set_transient_storage(&mut self, address: H160, key: H256, value: H256) {
self.transient_storage.insert((address, key), value);
}

fn reset_storage(&mut self, address: H160) {
#[allow(deprecated)]
let _ = <AccountStorages<T>>::remove_prefix(address, None);
Expand All @@ -941,6 +977,10 @@ where
self.substate.set_deleted(address)
}

fn set_created(&mut self, address: H160) {
self.substate.set_created(address);
}

fn set_code(&mut self, address: H160, code: Vec<u8>) {
log::debug!(
target: "evm",
Expand Down
2 changes: 1 addition & 1 deletion frame/evm/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1246,7 +1246,7 @@ fn handle_sufficient_reference() {
assert_eq!(account_2.sufficients, 1);
EVM::remove_account(&addr_2);
let account_2 = frame_system::Account::<Test>::get(substrate_addr_2);
assert_eq!(account_2.sufficients, 1);
assert_eq!(account_2.sufficients, 0);
});
}

Expand Down
2 changes: 1 addition & 1 deletion precompiles/src/testing/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl PrecompileHandle for MockHandle {
if self
.record_cost(crate::evm::costs::call_cost(
context.apparent_value,
&evm::Config::london(),
&evm::Config::cancun(),
))
.is_err()
{
Expand Down
4 changes: 2 additions & 2 deletions primitives/evm/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ mod tests {
UnknownError,
}

static SHANGHAI_CONFIG: evm::Config = evm::Config::shanghai();
static CANCUN_CONFIG: evm::Config = evm::Config::cancun();

impl From<TransactionValidationError> for TestError {
fn from(e: TransactionValidationError) -> Self {
Expand Down Expand Up @@ -337,7 +337,7 @@ mod tests {
} = input;
CheckEvmTransaction::<TestError>::new(
CheckEvmTransactionConfig {
evm_config: &SHANGHAI_CONFIG,
evm_config: &CANCUN_CONFIG,
block_gas_limit: blockchain_gas_limit,
base_fee: blockchain_base_fee,
chain_id: blockchain_chain_id,
Expand Down
2 changes: 1 addition & 1 deletion ts-tests/contracts/ECRecoverTests.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity 0.8.2;
pragma solidity >=0.8.2 <0.9.0;

contract ECRecoverTests {
function ecrecover(bytes memory input) public returns(bytes memory) {
Expand Down
2 changes: 1 addition & 1 deletion ts-tests/contracts/ExplicitRevertReason.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity 0.8.2;
pragma solidity >=0.8.2 <0.9.0;

contract ExplicitRevertReason {
function max10(uint256 a) public returns (uint256) {
Expand Down
2 changes: 1 addition & 1 deletion ts-tests/contracts/Test.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity 0.8.2;
pragma solidity >=0.8.2 <0.9.0;

contract Test {
function multiply(uint a) public pure returns(uint d) {
Expand Down
57 changes: 57 additions & 0 deletions ts-tests/contracts/eip1153.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract ReentrancyProtected {
// A constant key for the reentrancy guard stored in Transient Storage.
// This acts as a unique identifier for the reentrancy lock.
bytes32 constant REENTRANCY_GUARD = keccak256("REENTRANCY_GUARD");

// Modifier to prevent reentrant calls.
// It checks if the reentrancy guard is set (indicating an ongoing execution)
// and sets the guard before proceeding with the function execution.
// After the function executes, it resets the guard to allow future calls.
modifier nonReentrant() {
// Ensure the guard is not set (i.e., no ongoing execution).
require(tload(REENTRANCY_GUARD) == 0, "Reentrant call detected.");

// Set the guard to block reentrant calls.
tstore(REENTRANCY_GUARD, 1);

_; // Execute the function body.

// Reset the guard after execution to allow future calls.
tstore(REENTRANCY_GUARD, 0);
}

// Uses inline assembly to access the Transient Storage's tstore operation.
function tstore(bytes32 location, uint value) private {
assembly {
tstore(location, value)
}
}

// Uses inline assembly to access the Transient Storage's tload operation.
// Returns the value stored at the given location.
function tload(bytes32 location) private returns (uint value) {
assembly {
value := tload(location)
}
}

function nonReentrantMethod() public nonReentrant() {
(bool success, bytes memory result) = msg.sender.call("");
if (!success) {
assembly {
revert(add(32, result), mload(result))
}
}
}

function test() external {
this.nonReentrantMethod();
}

receive() external payable {
this.nonReentrantMethod();
}
}
6 changes: 3 additions & 3 deletions ts-tests/tests/test-contract-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ describeWithFrontier("Frontier RPC (Contract)", (context) => {
const baseCost = 24029;

// going from unset storage to some value (original = 0)
expect(tx1.gasUsed - baseCost).to.be.eq(20000);
expect(tx1.gasUsed - baseCost).to.be.eq(19993);
// in London config, setting back the same value have cost of warm read
expect(tx2.gasUsed - baseCost).to.be.eq(100);
expect(tx2.gasUsed - baseCost).to.be.eq(93);
// - the original storage didn't change in the current transaction
// - the original storage is not zero (otherwise tx1)
expect(tx3.gasUsed - baseCost).to.be.eq(2900);
expect(tx3.gasUsed - baseCost).to.be.eq(2893);
});
});
Loading
Loading