Skip to content

Commit

Permalink
feat: revm-interpreter created (#320)
Browse files Browse the repository at this point in the history
  • Loading branch information
rakita committed Jan 8, 2023
1 parent 6603126 commit 2be3798
Show file tree
Hide file tree
Showing 61 changed files with 1,099 additions and 665 deletions.
464 changes: 319 additions & 145 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions bins/revm-test/Cargo.toml
Expand Up @@ -8,6 +8,7 @@ edition = "2021"
bytes = "1.1"
hex = "0.4"
revm = { path = "../../crates/revm", version = "2.3.1" }
revm-interpreter = { path = "../../crates/interpreter", version = "3.0.0" }
microbench = "0.5"

[[bin]]
Expand Down
41 changes: 35 additions & 6 deletions bins/revm-test/src/bin/snailtracer.rs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bins/revme/Cargo.toml
Expand Up @@ -21,7 +21,7 @@ revm = { path = "../../crates/revm", version = "2.3.1", default-features = false
"ethersdb",
"std",
"secp256k1",
"with-serde",
"serde",
] }
rlp = { version = "0.5", default-features = false }
ruint = { version = "1.7.0", features = ["rlp", "serde"] }
Expand Down
5 changes: 4 additions & 1 deletion bins/revme/src/statetest/models/spec.rs
Expand Up @@ -27,6 +27,8 @@ pub enum SpecName {
MergeMeterInitCode,
#[serde(alias = "Merge+3855")]
MergePush0,
#[serde(other)]
Unknown,
}

impl SpecName {
Expand All @@ -49,7 +51,8 @@ impl SpecName {
Self::MergePush0 => SpecId::MERGE_EOF,
Self::ByzantiumToConstantinopleAt5 | Self::Constantinople => {
panic!("Overriden with PETERSBURG")
} //_ => panic!("Conversion failed"),
}
Self::Unknown => panic!("Unknown spec"),
}
}
}
7 changes: 3 additions & 4 deletions bins/revme/src/statetest/runner.rs
Expand Up @@ -8,10 +8,8 @@ use std::{

use indicatif::ProgressBar;
use revm::{
bits::{B160, B256},
db::AccountState,
inspectors::CustomPrintTracer,
Bytecode, CreateScheme, Env, ExecutionResult, SpecId, TransactTo, U256,
db::AccountState, inspectors::CustomPrintTracer, Bytecode, CreateScheme, Env, ExecutionResult,
SpecId, TransactTo, B160, B256, U256,
};
use std::sync::atomic::Ordering;
use walkdir::{DirEntry, WalkDir};
Expand Down Expand Up @@ -189,6 +187,7 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc<Mutex<Duration>>) -> Result<
| SpecName::MergeEOF
| SpecName::MergeMeterInitCode
| SpecName::MergePush0
| SpecName::Unknown
) {
continue;
}
Expand Down
3 changes: 3 additions & 0 deletions crates/interpreter/CHANGELOG.md
@@ -0,0 +1,3 @@
# v3.0.0

Interpreter was extracted from main REVM crate. Before v3.0.0 version, this code was part of REVM.
71 changes: 71 additions & 0 deletions crates/interpreter/Cargo.toml
@@ -0,0 +1,71 @@
[package]
authors = ["Dragan Rakita <dragan0rakita@gmail.com>"]
description = "REVM Interpreter"
edition = "2021"
keywords = ["no_std", "ethereum", "vm", "evm", "revm", "interpreter"]
license = "MIT"
name = "revm-interpreter"
repository = "https://github.com/bluealloy/revm"
version = "3.0.0"
readme = "../../README.md"

[dependencies]
bytes = { version = "1.1", default-features = false }
hashbrown = { version = "0.13" }
hex = { version = "0.4", default-features = false }
rlp = { version = "0.5", default-features = false } # used for create2 address calculation
ruint = { version = "1.7.0", features = ["primitive-types", "rlp"] }


# bits B256 B160 crate
fixed-hash = { version = "0.8", default-features = false, features = [
"rustc-hex",
] }

#utility
hex-literal = "0.3"
derive_more = "0.99"
enumn = "0.1"

# sha3 keccak hasher
sha3 = { version = "0.10", default-features = false, features = [] }

# optional
serde = { version = "1.0", features = ["derive", "rc"], optional = true }
arbitrary = { version = "1.2", features = ["derive"], optional = true }

[dev-dependencies]
arbitrary = { version = "1.2", features = ["derive"] }
proptest = { version = "1.0" }
proptest-derive = "0.2.0"
ruint = { version = "1.7.0", features = [
"primitive-types",
"rlp",
"proptest",
"arbitrary",
] }

[features]
default = ["std"]
dev = [
"memory_limit",
"optional_balance_check",
"optional_block_gas_limit",
"optional_eip3607",
"optional_gas_refund",
]
memory_limit = []
no_gas_measuring = []
optional_balance_check = []
optional_block_gas_limit = []
optional_eip3607 = []
optional_gas_refund = []
std = ["bytes/std", "rlp/std", "hex/std"]
serde = [
"dep:serde",
"hex/serde",
"hashbrown/serde",
"ruint/serde",
"bytes/serde",
]
arbitrary = ["dep:arbitrary", "ruint/arbitrary", "ruint/proptest"]
File renamed without changes.
30 changes: 25 additions & 5 deletions crates/revm/src/bits.rs → crates/interpreter/src/bits.rs
@@ -1,14 +1,24 @@
use derive_more::{AsRef, Deref};
use fixed_hash::{construct_fixed_hash, impl_fixed_hash_conversions};

#[cfg(test)]
use proptest_derive::Arbitrary as PropTestArbitrary;

#[cfg(any(test, feature = "arbitrary"))]
use arbitrary::Arbitrary;

construct_fixed_hash! {
/// revm 256 bits type.
#[cfg_attr(test, derive(PropTestArbitrary))]
#[cfg_attr(any(test, feature = "arbitrary"), derive(Arbitrary))]
#[derive(AsRef,Deref)]
pub struct B256(32);
}

construct_fixed_hash! {
/// revm 160 bits type.
#[cfg_attr(test, derive(PropTestArbitrary))]
#[cfg_attr(any(test, feature = "arbitrary"), derive(Arbitrary))]
#[derive(AsRef,Deref)]
pub struct B160(20);
}
Expand All @@ -25,7 +35,7 @@ impl From<u64> for B160 {

impl_fixed_hash_conversions!(B256, B160);

#[cfg(feature = "with-serde")]
#[cfg(feature = "serde")]
impl serde::Serialize for B256 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
Expand All @@ -35,7 +45,7 @@ impl serde::Serialize for B256 {
serialize::serialize_raw(&mut slice, &self.0, serializer)
}
}
#[cfg(feature = "with-serde")]
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for B256 {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand All @@ -46,7 +56,7 @@ impl<'de> serde::Deserialize<'de> for B256 {
Ok(B256(bytes))
}
}
#[cfg(feature = "with-serde")]
#[cfg(feature = "serde")]
impl serde::Serialize for B160 {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
Expand All @@ -57,7 +67,7 @@ impl serde::Serialize for B160 {
}
}

#[cfg(feature = "with-serde")]
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for B160 {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
Expand All @@ -70,7 +80,7 @@ impl<'de> serde::Deserialize<'de> for B160 {
}

// code optained from: https://docs.rs/impl-serde/0.4.0/impl_serde/
#[cfg(feature = "with-serde")]
#[cfg(feature = "serde")]
mod serialize {

use alloc::{string::String, vec::Vec};
Expand Down Expand Up @@ -294,3 +304,13 @@ mod serialize {
deserializer.deserialize_str(Visitor { len })
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn arbitrary() {
proptest::proptest!(|(_v1: B160, _v2: B256)| {});
}
}
55 changes: 55 additions & 0 deletions crates/interpreter/src/common.rs
@@ -0,0 +1,55 @@
use crate::{B160, B256, U256};
use sha3::{Digest, Keccak256};

#[inline(always)]
pub fn keccak256(input: &[u8]) -> B256 {
B256::from_slice(Keccak256::digest(input).as_slice())
}

/// Returns the address for the legacy `CREATE` scheme: [`CreateScheme::Create`]
pub fn create_address(caller: B160, nonce: u64) -> B160 {
let mut stream = rlp::RlpStream::new_list(2);
stream.append(&caller.0.as_ref());
stream.append(&nonce);
let out = keccak256(&stream.out());
B160(out[12..].try_into().unwrap())
}

/// Returns the address for the `CREATE2` scheme: [`CreateScheme::Create2`]
pub fn create2_address(caller: B160, code_hash: B256, salt: U256) -> B160 {
let mut hasher = Keccak256::new();
hasher.update([0xff]);
hasher.update(&caller[..]);
hasher.update(salt.to_be_bytes::<{ U256::BYTES }>());
hasher.update(&code_hash[..]);

B160(hasher.finalize().as_slice()[12..].try_into().unwrap())
}

/// Serde functions to serde as [bytes::Bytes] hex string
#[cfg(feature = "serde")]
pub(crate) mod serde_hex_bytes {
use serde::{Deserialize, Deserializer, Serializer};

pub fn serialize<S, T>(x: T, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
s.serialize_str(&format!("0x{}", hex::encode(x.as_ref())))
}

pub fn deserialize<'de, D>(d: D) -> Result<bytes::Bytes, D::Error>
where
D: Deserializer<'de>,
{
let value = String::deserialize(d)?;
if let Some(value) = value.strip_prefix("0x") {
hex::decode(value)
} else {
hex::decode(&value)
}
.map(Into::into)
.map_err(|e| serde::de::Error::custom(e.to_string()))
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
44 changes: 44 additions & 0 deletions crates/interpreter/src/host.rs
@@ -0,0 +1,44 @@
mod dummy_host;

use crate::{
Bytecode, Bytes, CallInputs, CreateInputs, Env, Gas, Interpreter, Return, SelfDestructResult,
B160, B256, U256,
};
pub use dummy_host::DummyHost;

/// EVM context host.
pub trait Host {
fn step(&mut self, interpreter: &mut Interpreter, is_static: bool) -> Return;
fn step_end(&mut self, interpreter: &mut Interpreter, is_static: bool, ret: Return) -> Return;

fn env(&mut self) -> &mut Env;

/// load account. Returns (is_cold,is_new_account)
fn load_account(&mut self, address: B160) -> Option<(bool, bool)>;
/// Get environmental block hash.
fn block_hash(&mut self, number: U256) -> Option<B256>;
/// Get balance of address and if account is cold loaded.
fn balance(&mut self, address: B160) -> Option<(U256, bool)>;
/// Get code of address and if account is cold loaded.
fn code(&mut self, address: B160) -> Option<(Bytecode, bool)>;
/// Get code hash of address and if account is cold loaded.
fn code_hash(&mut self, address: B160) -> Option<(B256, bool)>;
/// Get storage value of address at index and if account is cold loaded.
fn sload(&mut self, address: B160, index: U256) -> Option<(U256, bool)>;
/// Set storage value of account address at index.
/// Returns (original, present, new, sis_cold)
fn sstore(
&mut self,
address: B160,
index: U256,
value: U256,
) -> Option<(U256, U256, U256, bool)>;
/// Create a log owned by address with given topics and data.
fn log(&mut self, address: B160, topics: Vec<B256>, data: Bytes);
/// Mark an address to be deleted, with funds transferred to target.
fn selfdestruct(&mut self, address: B160, target: B160) -> Option<SelfDestructResult>;
/// Invoke a create operation.
fn create(&mut self, inputs: &mut CreateInputs) -> (Return, Option<B160>, Gas, Bytes);
/// Invoke a call operation.
fn call(&mut self, input: &mut CallInputs) -> (Return, Gas, Bytes);
}

0 comments on commit 2be3798

Please sign in to comment.