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

feat: eip 1153 #276

Closed
wants to merge 2 commits into from
Closed
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
2 changes: 2 additions & 0 deletions bins/revme/src/statetest/models/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub enum SpecName {
Merge, //done
#[serde(alias = "Merge+3540+3670")]
MergeEOF,
Shanghai,
}

impl SpecName {
Expand All @@ -41,6 +42,7 @@ impl SpecName {
Self::London | Self::BerlinToLondonAt5 => SpecId::LONDON,
Self::Merge => SpecId::MERGE,
Self::MergeEOF => SpecId::MERGE_EOF,
Self::Shanghai => SpecId::SHANGHAI,
Self::ByzantiumToConstantinopleAt5 | Self::Constantinople => {
panic!("Overriden with PETERSBURG")
} //_ => panic!("Conversion failed"),
Expand Down
1 change: 1 addition & 0 deletions crates/revm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ pub fn evm_inner<'a, DB: Database, const INSPECT: bool>(
}
SpecId::MERGE => create_evm!(MergeSpec, db, env, insp),
SpecId::MERGE_EOF => create_evm!(MergeSpec, db, env, insp),
SpecId::SHANGHAI => create_evm!(ShanghaiSpec, db, env, insp),
SpecId::LATEST => create_evm!(LatestSpec, db, env, insp),
}
}
20 changes: 20 additions & 0 deletions crates/revm/src/evm_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,22 @@ impl<'a, GSPEC: Spec, DB: Database + 'a, const INSPECT: bool> Host
.ok()
}

fn tload(
&mut self,
address: H160,
index: U256,
) -> U256 {
self.data
.journaled_state
.tload(address, index)
}

fn tstore(&mut self, address: H160, index: U256, value: U256) {
self.data
.journaled_state
.tstore(address, index, value)
}

fn log(&mut self, address: H160, topics: Vec<H256>, data: Bytes) {
if INSPECT {
self.inspector.log(&mut self.data, &address, &topics, &data);
Expand Down Expand Up @@ -881,6 +897,10 @@ pub trait Host {
index: U256,
value: U256,
) -> Option<(U256, U256, U256, bool)>;

fn tload(&mut self, address: H160, index: U256) -> U256;
fn tstore(&mut self, address: H160, index: U256, value: U256);

/// Create a log owned by address with given topics and data.
fn log(&mut self, address: H160, topics: Vec<H256>, data: Bytes);
/// Mark an address to be deleted, with funds transferred to target.
Expand Down
2 changes: 2 additions & 0 deletions crates/revm/src/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ pub fn eval<H: Host, S: Spec>(opcode: u8, interp: &mut Interpreter, host: &mut H
opcode::GASLIMIT => host_env::gaslimit(interp, host),
opcode::SLOAD => host::sload::<H, S>(interp, host),
opcode::SSTORE => host::sstore::<H, S>(interp, host),
opcode::TSTORE => host::tstore::<H, S>(interp, host),
opcode::TLOAD => host::tload::<H, S>(interp, host),
opcode::GAS => system::gas(interp),
opcode::LOG0 => host::log::<H, S>(interp, 0, host),
opcode::LOG1 => host::log::<H, S>(interp, 1, host),
Expand Down
20 changes: 20 additions & 0 deletions crates/revm/src/instructions/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,26 @@ pub fn sstore<H: Host, SPEC: Spec>(interp: &mut Interpreter, host: &mut H) -> Re
interp.add_next_gas_block(interp.program_counter() - 1)
}

pub fn tstore<H: Host, SPEC: Spec>(interp: &mut Interpreter, host: &mut H) -> Return {
check!(!SPEC::IS_STATIC_CALL);
gas!(interp, gas::WARM_STORAGE_READ_COST);

pop!(interp, index, value);

host.tstore(interp.contract.address, index, value);
Return::Continue
}

pub fn tload<H: Host, SPEC: Spec>(interp: &mut Interpreter, host: &mut H) -> Return {
gas!(interp, gas::WARM_STORAGE_READ_COST);

pop!(interp, index);

let value = host.tload(interp.contract.address, index);
push!(interp, value);
Return::Continue
}

pub fn log<H: Host, SPEC: Spec>(interp: &mut Interpreter, n: u8, host: &mut H) -> Return {
check!(!SPEC::IS_STATIC_CALL);

Expand Down
24 changes: 20 additions & 4 deletions crates/revm/src/instructions/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ pub const LOG1: u8 = 0xa1;
pub const LOG2: u8 = 0xa2;
pub const LOG3: u8 = 0xa3;
pub const LOG4: u8 = 0xa4;
pub const TLOAD: u8 = 0xb3;
pub const TSTORE: u8 = 0xb4;
pub const CREATE: u8 = 0xf0;
pub const CREATE2: u8 = 0xf5;
pub const CALL: u8 = 0xf1;
Expand Down Expand Up @@ -473,8 +475,18 @@ macro_rules! gas_opcodee {
/* 0xb0 */ OpInfo::none(),
/* 0xb1 */ OpInfo::none(),
/* 0xb2 */ OpInfo::none(),
/* 0xb3 */ OpInfo::none(),
/* 0xb4 */ OpInfo::none(),
/* 0xb3 TLOAD */
OpInfo::gas(if SpecId::enabled($spec_id, SpecId::SHANGHAI) {
gas::WARM_STORAGE_READ_COST
} else {
0
}),
/* 0xb4 TSTORE */
OpInfo::gas(if SpecId::enabled($spec_id, SpecId::SHANGHAI) {
gas::WARM_STORAGE_READ_COST
} else {
0
}),
/* 0xb5 */ OpInfo::none(),
/* 0xb6 */ OpInfo::none(),
/* 0xb7 */ OpInfo::none(),
Expand Down Expand Up @@ -620,6 +632,10 @@ pub const fn spec_opcode_gas(spec_id: SpecId) -> &'static [OpInfo; 256] {
gas_opcodee!(MERGE, SpecId::MERGE);
MERGE
}
SpecId::SHANGHAI => {
gas_opcodee!(SHANGHAI, SpecId::SHANGHAI);
SHANGHAI
}
SpecId::MERGE_EOF => {
gas_opcodee!(MERGE_EOF, SpecId::MERGE_EOF);
MERGE_EOF
Expand Down Expand Up @@ -811,8 +827,8 @@ pub const OPCODE_JUMPMAP: [Option<&'static str>; 256] = [
/* 0xb0 */ None,
/* 0xb1 */ None,
/* 0xb2 */ None,
/* 0xb3 */ None,
/* 0xb4 */ None,
/* 0xb3 */ Some("TLOAD"),
/* 0xb4 */ Some("TSTORE"),
/* 0xb5 */ None,
/* 0xb6 */ None,
/* 0xb7 */ None,
Expand Down
2 changes: 2 additions & 0 deletions crates/revm/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ pub mod bytecode;
mod contract;
pub(crate) mod memory;
mod stack;
mod transient;

pub use bytecode::{Bytecode, BytecodeLocked, BytecodeState};
pub use contract::Contract;
pub use memory::Memory;
pub use stack::Stack;
pub use transient::TransientStorage;

use crate::{
instructions::{eval, Return},
Expand Down
49 changes: 49 additions & 0 deletions crates/revm/src/interpreter/transient.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use std::collections::HashMap;
use ruint::aliases::U256;
use primitive_types::H160;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TransientStorage {
data: HashMap<H160, HashMap<U256, U256>>
}

impl Default for TransientStorage {
fn default() -> Self {
Self::new()
}
}

impl TransientStorage {
pub fn new() -> Self {
Self {
data: HashMap::default()
}
}

pub fn set(&mut self, address: H160, key: U256, value: U256) {
match self.data.get_mut(&address) {
Some(storage) => {
let _ = storage.insert(key, value);
return
}
None => {
let mut storage: HashMap<U256, U256> = HashMap::default();
let _ = storage.insert(key, value);
self.data.insert(address, storage);
return
}
}
}

pub fn get(&self, address: H160, key: U256) -> U256 {
match self.data.get(&address) {
Some(storage) => {
match storage.get(&key) {
Some(value) => *value,
None => U256::default(),
}
}
None => U256::default()
}
}
}
61 changes: 59 additions & 2 deletions crates/revm/src/journaled_state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
use crate::{interpreter::bytecode::Bytecode, models::SelfDestructResult, Return, KECCAK_EMPTY};
use crate::{
interpreter::{
bytecode::Bytecode,
TransientStorage
},
models::SelfDestructResult, Return, KECCAK_EMPTY
};
use alloc::{vec, vec::Vec};
use core::mem::{self};
use hashbrown::{hash_map::Entry, HashMap as Map};
Expand All @@ -12,6 +18,8 @@ use crate::{db::Database, AccountInfo, Log};
pub struct JournaledState {
/// Current state.
pub state: State,
/// EIP 1153 transient storage
pub transient_storage: TransientStorage,
/// logs
pub logs: Vec<Log>,
/// how deep are we in call stack.
Expand Down Expand Up @@ -147,6 +155,13 @@ pub enum JournalEntry {
key: U256,
had_value: Option<U256>, //if none, storage slot was cold loaded from db and needs to be removed
},

TransientStorageChange {
address: H160,
key: U256,
had_value: Option<U256>,
},

/// Code changed
/// Action: Account code changed
/// Revert: Revert to previous bytecode.
Expand All @@ -163,6 +178,7 @@ impl JournaledState {
pub fn new(num_of_precompiles: usize) -> JournaledState {
Self {
state: Map::new(),
transient_storage: TransientStorage::new(),
logs: Vec::new(),
journal: vec![vec![]],
depth: 0,
Expand Down Expand Up @@ -342,6 +358,7 @@ impl JournaledState {

fn journal_revert(
state: &mut State,
transient_storage: &mut TransientStorage,
journal_entries: Vec<JournalEntry>,
is_spurious_dragon_enabled: bool,
) {
Expand Down Expand Up @@ -396,6 +413,13 @@ impl JournaledState {
storage.remove(&key);
}
}
JournalEntry::TransientStorageChange {
address,
key,
had_value,
} => {
transient_storage.set(address, key, had_value.unwrap());
}
JournalEntry::CodeChange { address, had_code } => {
let acc = state.get_mut(&address).unwrap();
acc.info.code_hash = had_code.hash();
Expand All @@ -422,14 +446,15 @@ impl JournaledState {
pub fn checkpoint_revert(&mut self, checkpoint: JournalCheckpoint) {
let is_spurious_dragon_enabled = !self.is_before_spurious_dragon;
let state = &mut self.state;
let transient_storage = &mut self.transient_storage;
self.depth -= 1;
// iterate over last N journals sets and revert our global state
let leng = self.journal.len();
self.journal
.iter_mut()
.rev()
.take(leng - checkpoint.journal_i)
.for_each(|cs| Self::journal_revert(state, mem::take(cs), is_spurious_dragon_enabled));
.for_each(|cs| Self::journal_revert(state, transient_storage, mem::take(cs), is_spurious_dragon_enabled));

self.logs.truncate(checkpoint.log_i);
self.journal.truncate(checkpoint.journal_i);
Expand Down Expand Up @@ -608,6 +633,38 @@ impl JournaledState {
Ok((slot.original_value, present, new, is_cold))
}

pub fn tload(
&mut self,
address: H160,
key: U256,
) -> U256 {
self.transient_storage.get(address, key)
}

pub fn tstore(
&mut self,
address: H160,
key: U256,
new: U256,
) {
let present = self.tload(address, key);

if present == new {
return
}

self.journal
.last_mut()
.unwrap()
.push(JournalEntry::TransientStorageChange {
address,
key,
had_value: Some(present),
});

self.transient_storage.set(address, key, new)
}

/// push log into subroutine
pub fn log(&mut self, log: Log) {
self.logs.push(log);
Expand Down
8 changes: 6 additions & 2 deletions crates/revm/src/specification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ pub enum SpecId {
GRAY_GLACIER = 14, // Gray Glacier 15050000
MERGE = 15, // Paris/Merge TBD (Depends on difficulty)
MERGE_EOF = 16, // Merge+EOF TBD
LATEST = 17,
SHANGHAI = 17, // Shanghai TBD
LATEST = 18,
}

impl SpecId {
Expand All @@ -37,7 +38,7 @@ impl SpecId {
}
BYZANTIUM | CONSTANTINOPLE | PETERSBURG => PrecompileId::BYZANTIUM,
ISTANBUL | MUIR_GLACIER => PrecompileId::ISTANBUL,
BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | MERGE_EOF | LATEST => {
BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | MERGE_EOF | SHANGHAI | LATEST => {
PrecompileId::BERLIN
}
}
Expand Down Expand Up @@ -66,6 +67,7 @@ impl From<&str> for SpecId {
"London" => SpecId::LONDON,
"Merge" => SpecId::MERGE,
"MergeEOF" => SpecId::MERGE_EOF,
"Shanghai" => SpecId::SHANGHAI,
_ => SpecId::LATEST,
}
}
Expand Down Expand Up @@ -147,6 +149,7 @@ pub(crate) mod spec_impl {
// ARROW_GLACIER no EVM spec change
// GRAT_GLACIER no EVM spec change
spec!(MERGE);
spec!(SHANGHAI);
spec!(LATEST);
}

Expand All @@ -158,6 +161,7 @@ pub use spec_impl::ISTANBUL::SpecImpl as IstanbulSpec;
pub use spec_impl::LATEST::SpecImpl as LatestSpec;
pub use spec_impl::LONDON::SpecImpl as LondonSpec;
pub use spec_impl::MERGE::SpecImpl as MergeSpec;
pub use spec_impl::SHANGHAI::SpecImpl as ShanghaiSpec;
pub use spec_impl::PETERSBURG::SpecImpl as PetersburgSpec;
pub use spec_impl::SPURIOUS_DRAGON::SpecImpl as SpuriousDragonSpec;
pub use spec_impl::TANGERINE::SpecImpl as TangerineSpec;