Skip to content

Commit

Permalink
Merge pull request #281 from moonbeam-foundation/ahmad-cancun-eip-6780
Browse files Browse the repository at this point in the history
Cancun self destruct changes (EIP 6780)
  • Loading branch information
crystalin authored Jan 13, 2025
2 parents c5c927d + c4bad3c commit bb2532e
Show file tree
Hide file tree
Showing 14 changed files with 442 additions and 23 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ sha3 = { version = "0.10", default-features = false }

evm-interpreter = { version = "1.0.0-dev", path = "interpreter", default-features = false }

[dev-dependencies]
hex = { version = "0.4", features = [ "serde" ] }

[features]
default = ["std"]
std = [
Expand Down
4 changes: 1 addition & 3 deletions interpreter/src/eval/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,7 @@ pub fn suicide<S: AsRef<RuntimeState>, H: RuntimeEnvironment + RuntimeBackend, T
value: balance,
})?;

handler.mark_delete(address);
handler.reset_balance(address);

handler.mark_delete_reset(address);
Ok(((), ()))
}) {
Ok(()) => Control::Exit(ExitSucceed::Suicided.into()),
Expand Down
8 changes: 6 additions & 2 deletions interpreter/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ pub trait RuntimeBackend: RuntimeBaseBackend {
fn original_storage(&self, address: H160, index: H256) -> H256;
/// Check whether an address has already been deleted.
fn deleted(&self, address: H160) -> bool;
/// Check whether an address has already been created in the transaction.
fn created(&self, address: H160) -> bool;
/// Checks if the address or (address, index) pair has been previously accessed.
fn is_cold(&self, address: H160, index: Option<H256>) -> bool;
fn is_hot(&self, address: H160, index: Option<H256>) -> bool {
Expand All @@ -158,8 +160,10 @@ pub trait RuntimeBackend: RuntimeBaseBackend {
) -> Result<(), ExitError>;
/// Create a log owned by address with given topics and data.
fn log(&mut self, log: Log) -> Result<(), ExitError>;
/// Mark an address to be deleted.
fn mark_delete(&mut self, address: H160);
/// Mark an address to be deleted and its balance to be reset.
fn mark_delete_reset(&mut self, address: H160);
// Mark an address as created in the current transaction.
fn mark_create(&mut self, address: H160);
/// Fully delete storages of an account.
fn reset_storage(&mut self, address: H160);
/// Set code of an account.
Expand Down
14 changes: 11 additions & 3 deletions interpreter/tests/usability.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::rc::Rc;

use evm_interpreter::{
error::{CallCreateTrap, Capture, ExitError, ExitSucceed},
etable::{Control, Etable},
Expand All @@ -12,6 +10,7 @@ use evm_interpreter::{
EtableInterpreter, RunInterpreter,
};
use primitive_types::{H160, H256, U256};
use std::rc::Rc;

const CODE1: &str = "60e060020a6000350480632839e92814601e57806361047ff414603457005b602a6004356024356047565b8060005260206000f35b603d6004356099565b8060005260206000f35b600082600014605457605e565b8160010190506093565b81600014606957607b565b60756001840360016047565b90506093565b609060018403608c85600186036047565b6047565b90505b92915050565b6000816000148060a95750816001145b60b05760b7565b81905060cf565b60c1600283036099565b60cb600184036099565b0190505b91905056";
const DATA1: &str = "2839e92800000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001";
Expand Down Expand Up @@ -135,6 +134,11 @@ impl RuntimeBackend for UnimplementedHandler {
fn deleted(&self, _address: H160) -> bool {
unimplemented!()
}

fn created(&self, _address: H160) -> bool {
unimplemented!()
}

fn is_cold(&self, _address: H160, _index: Option<H256>) -> bool {
unimplemented!()
}
Expand All @@ -157,7 +161,11 @@ impl RuntimeBackend for UnimplementedHandler {
fn log(&mut self, _log: Log) -> Result<(), ExitError> {
unimplemented!()
}
fn mark_delete(&mut self, _address: H160) {
fn mark_delete_reset(&mut self, _address: H160) {
unimplemented!()
}

fn mark_create(&mut self, _address: H160) {
unimplemented!()
}

Expand Down
4 changes: 2 additions & 2 deletions jsontests/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ pub fn run_test(
state,
};

let mut run_backend = OverlayedBackend::new(&base_backend, initial_accessed.clone());
let mut step_backend = OverlayedBackend::new(&base_backend, initial_accessed.clone());
let mut run_backend = OverlayedBackend::new(&base_backend, initial_accessed.clone(), &config);
let mut step_backend = OverlayedBackend::new(&base_backend, initial_accessed.clone(), &config);

// Run
let run_result = evm::transact(args.clone(), Some(4), &mut run_backend, &invoker);
Expand Down
57 changes: 47 additions & 10 deletions src/backend/overlayed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use evm_interpreter::{
};
use primitive_types::{H160, H256, U256};

use crate::{backend::TransactionalBackend, MergeStrategy};
use crate::{backend::TransactionalBackend, standard::Config, MergeStrategy};

#[derive(Clone, Debug)]
pub struct OverlayedChangeSet {
Expand All @@ -25,18 +25,24 @@ pub struct OverlayedChangeSet {
pub deletes: BTreeSet<H160>,
}

pub struct OverlayedBackend<B> {
pub struct OverlayedBackend<'config, B> {
backend: B,
substate: Box<Substate>,
accessed: BTreeSet<(H160, Option<H256>)>,
config: &'config Config,
}

impl<B> OverlayedBackend<B> {
pub fn new(backend: B, accessed: BTreeSet<(H160, Option<H256>)>) -> Self {
impl<'config, B> OverlayedBackend<'config, B> {
pub fn new(
backend: B,
accessed: BTreeSet<(H160, Option<H256>)>,
config: &'config Config,
) -> Self {
Self {
backend,
substate: Box::new(Substate::new()),
accessed,
config,
}
}

Expand All @@ -57,7 +63,7 @@ impl<B> OverlayedBackend<B> {
}
}

impl<B: RuntimeEnvironment> RuntimeEnvironment for OverlayedBackend<B> {
impl<B: RuntimeEnvironment> RuntimeEnvironment for OverlayedBackend<'_, B> {
fn block_hash(&self, number: U256) -> H256 {
self.backend.block_hash(number)
}
Expand Down Expand Up @@ -95,7 +101,7 @@ impl<B: RuntimeEnvironment> RuntimeEnvironment for OverlayedBackend<B> {
}
}

impl<B: RuntimeBaseBackend> RuntimeBaseBackend for OverlayedBackend<B> {
impl<B: RuntimeBaseBackend> RuntimeBaseBackend for OverlayedBackend<'_, B> {
fn balance(&self, address: H160) -> U256 {
if let Some(balance) = self.substate.known_balance(address) {
balance
Expand Down Expand Up @@ -145,11 +151,15 @@ impl<B: RuntimeBaseBackend> RuntimeBaseBackend for OverlayedBackend<B> {
}
}

impl<B: RuntimeBaseBackend> RuntimeBackend for OverlayedBackend<B> {
impl<B: RuntimeBaseBackend> RuntimeBackend for OverlayedBackend<'_, B> {
fn original_storage(&self, address: H160, index: H256) -> H256 {
self.backend.storage(address, index)
}

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

fn deleted(&self, address: H160) -> bool {
self.substate.deleted(address)
}
Expand Down Expand Up @@ -184,8 +194,20 @@ impl<B: RuntimeBaseBackend> RuntimeBackend for OverlayedBackend<B> {
Ok(())
}

fn mark_delete(&mut self, address: H160) {
self.substate.deletes.insert(address);
fn mark_delete_reset(&mut self, address: H160) {
if self.config.suicide_only_in_same_tx {
if self.created(address) {
self.substate.deletes.insert(address);
self.substate.storage_resets.insert(address);
}
} else {
self.substate.deletes.insert(address);
self.substate.storage_resets.insert(address);
}
}

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

fn reset_storage(&mut self, address: H160) {
Expand Down Expand Up @@ -238,7 +260,7 @@ impl<B: RuntimeBaseBackend> RuntimeBackend for OverlayedBackend<B> {
}
}

impl<B: RuntimeBaseBackend> TransactionalBackend for OverlayedBackend<B> {
impl<'config, B: RuntimeBaseBackend> TransactionalBackend for OverlayedBackend<'config, B> {
fn push_substate(&mut self) {
let mut parent = Box::new(Substate::new());
mem::swap(&mut parent, &mut self.substate);
Expand Down Expand Up @@ -278,6 +300,9 @@ impl<B: RuntimeBaseBackend> TransactionalBackend for OverlayedBackend<B> {
for address in child.deletes {
self.substate.deletes.insert(address);
}
for address in child.creates {
self.substate.creates.insert(address);
}
}
MergeStrategy::Revert | MergeStrategy::Discard => {}
}
Expand All @@ -294,6 +319,7 @@ struct Substate {
storages: BTreeMap<(H160, H256), H256>,
transient_storage: BTreeMap<(H160, H256), H256>,
deletes: BTreeSet<H160>,
creates: BTreeSet<H160>,
}

impl Substate {
Expand All @@ -308,6 +334,7 @@ impl Substate {
storages: Default::default(),
transient_storage: Default::default(),
deletes: Default::default(),
creates: Default::default(),
}
}

Expand Down Expand Up @@ -385,4 +412,14 @@ impl Substate {
false
}
}

pub fn created(&self, address: H160) -> bool {
if self.creates.contains(&address) {
true
} else if let Some(parent) = self.parent.as_ref() {
parent.created(address)
} else {
false
}
}
}
17 changes: 14 additions & 3 deletions src/standard/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ pub struct Config {
pub eip_5656_enabled: bool,
/// Uses EIP-1559 (Base fee is burned when this flag is enabled) [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md)
pub eip_1559_enabled: bool,
/// Selfdestruct deletet contract only if called in the same tx as creation [EIP-6780](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-6780.md)
pub suicide_only_in_same_tx: bool,
}

impl Config {
Expand Down Expand Up @@ -159,6 +161,7 @@ impl Config {
eip_1153_enabled: false,
eip_5656_enabled: false,
eip_1559_enabled: false,
suicide_only_in_same_tx: false,
}
}

Expand Down Expand Up @@ -215,6 +218,7 @@ impl Config {
eip_1153_enabled: false,
eip_5656_enabled: false,
eip_1559_enabled: false,
suicide_only_in_same_tx: false,
}
}

Expand Down Expand Up @@ -257,6 +261,7 @@ impl Config {
eip_1153_enabled,
eip_5656_enabled,
eip_1559_enabled,
suicide_only_in_same_tx,
} = inputs;

// See https://eips.ethereum.org/EIPS/eip-2929
Expand Down Expand Up @@ -322,6 +327,7 @@ impl Config {
eip_1153_enabled,
eip_5656_enabled,
eip_1559_enabled,
suicide_only_in_same_tx,
}
}
}
Expand All @@ -344,6 +350,7 @@ struct DerivedConfigInputs {
eip_1153_enabled: bool,
eip_5656_enabled: bool,
eip_1559_enabled: bool,
suicide_only_in_same_tx: bool,
}

impl DerivedConfigInputs {
Expand All @@ -361,6 +368,7 @@ impl DerivedConfigInputs {
eip_1153_enabled: false,
eip_5656_enabled: false,
eip_1559_enabled: false,
suicide_only_in_same_tx: false,
}
}

Expand All @@ -378,6 +386,7 @@ impl DerivedConfigInputs {
eip_1153_enabled: false,
eip_5656_enabled: false,
eip_1559_enabled: true,
suicide_only_in_same_tx: false,
}
}

Expand All @@ -395,6 +404,7 @@ impl DerivedConfigInputs {
eip_1153_enabled: false,
eip_5656_enabled: false,
eip_1559_enabled: true,
suicide_only_in_same_tx: false,
}
}

Expand All @@ -413,9 +423,9 @@ impl DerivedConfigInputs {
eip_1153_enabled: false,
eip_5656_enabled: false,
eip_1559_enabled: true,
suicide_only_in_same_tx: false,
}
}

const fn cancun() -> Self {
Self {
gas_storage_read_warm: 100,
Expand All @@ -428,9 +438,10 @@ impl DerivedConfigInputs {
warm_coinbase_address: true,
// 2 * (MAX_CODE_SIZE = `24576`) = (0xC000 = 49152) as per EIP-3860
max_initcode_size: Some(0xC000),
eip_1153_enabled: true,
eip_5656_enabled: true,
eip_1153_enabled: false,
eip_5656_enabled: false,
eip_1559_enabled: true,
suicide_only_in_same_tx: true,
}
}
}
1 change: 1 addition & 0 deletions src/standard/invoker/routines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ where
}

handler.reset_storage(state.as_ref().context.address);
handler.mark_create(state.as_ref().context.address);

resolver.resolve_create(init_code, state, handler)
}
Expand Down
8 changes: 8 additions & 0 deletions tests/contract/DeployAndDestroy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract DeployAndDestroy {
constructor() {
selfdestruct(payable(msg.sender));
}
}
16 changes: 16 additions & 0 deletions tests/contract/SimpleContract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleContract {
address public owner;

// Constructor sets the owner of the contract
constructor() {
owner = msg.sender;
}

// Function to destroy the contract and send the remaining funds to the target address
function destroy(address target) public {
selfdestruct(payable(target));
}
}
1 change: 1 addition & 0 deletions tests/contract/deploy_and_destroy_init_code
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
6080604052348015600e575f80fd5b503373ffffffffffffffffffffffffffffffffffffffff16fffe
1 change: 1 addition & 0 deletions tests/contract/simple_contract_bytecode.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
608060405234801561000f575f80fd5b50335f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101948061005c5f395ff3fe608060405234801561000f575f80fd5b5060043610610033575f3560e01c8062f55d9d146100375780638da5cb5b14610053575b5f80fd5b610051600480360381019061004c919061010b565b610071565b005b61005b61008a565b6040516100689190610145565b60405180910390f35b8073ffffffffffffffffffffffffffffffffffffffff16ff5b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100da826100b1565b9050919050565b6100ea816100d0565b81146100f4575f80fd5b50565b5f81359050610105816100e1565b92915050565b5f602082840312156101205761011f6100ad565b5b5f61012d848285016100f7565b91505092915050565b61013f816100d0565b82525050565b5f6020820190506101585f830184610136565b9291505056fea26469706673582212201e4165398f9671b365261ccc1129042cbcea13db557b5359b2298c51f2ab274d64736f6c63430008150033
Loading

0 comments on commit bb2532e

Please sign in to comment.