Skip to content

Commit

Permalink
Merge pull request #9 from 0xys/11-simulator
Browse files Browse the repository at this point in the history
11 simulator
  • Loading branch information
0xys authored Apr 2, 2022
2 parents d3c92fb + a5650ff commit a347161
Show file tree
Hide file tree
Showing 19 changed files with 265 additions and 234 deletions.
18 changes: 7 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@

# Toy Example
```rs
let host = TransientHost::new();
let mut executor = Executor::new(Box::new(host));
let mut builder = Code::builder();

let code = builder
let mut emulator = EvmEmulator::new_transient_with(TxContext::default());
let code = Code::builder()
.append(OpCode::PUSH1) // OpCode
.append("02") // hex character
.append(OpCode::PUSH1)
Expand All @@ -17,14 +14,13 @@ let code = builder
.append(OpCode::MSTORE)
.append("60206000") // hex string
.append(OpCode::RETURN);
.clone();

let output = executor.execute_raw(&code);

let data = decode("0000000000000000000000000000000000000000000000000000000000000005").unwrap();
let result = emulator.run_code(code);

assert_eq!(StatusCode::Success, output.status_code);
assert_eq!(Bytes::from(data), output.data);
assert_eq!(24, i64::max() - output.gas_left);
result.expect_status(StatusCode::Success)
.expect_gas(24)
.expect_output("0000000000000000000000000000000000000000000000000000000000000005");
```

# Progress
Expand Down
23 changes: 11 additions & 12 deletions src/tester/mod.rs → src/emulator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,21 @@ use hex::decode;
use crate::{
model::{code::Code, evmc::{Output, StatusCode, TxContext, AccessList}, revision::Revision},
executor::{callstack::CallScope, executor::Executor},
host::stateful::StatefulHost
host::{stateful::StatefulHost, Host, transient::TransientHost}
};

#[derive(Clone)]
pub struct EvmTester {
pub struct EvmEmulator {
scope: CallScope,
host: Rc<RefCell<StatefulHost>>,
host: Rc<RefCell<dyn Host>>,

is_execution_cost_enabled: bool,
access_list: AccessList,
}

pub struct EvmResult {
host: Rc<RefCell<StatefulHost>>,
host: Rc<RefCell<dyn Host>>,
scope: CallScope,
output: Output,
pub output: Output,
}

impl EvmResult {
Expand Down Expand Up @@ -50,22 +49,22 @@ impl EvmResult {
}
}

impl EvmTester {
pub fn new() -> Self {
let host = StatefulHost::new();
impl EvmEmulator {
pub fn new_transient_with(context: TxContext) -> Self {
let host = TransientHost::new_with(context);
let host = Rc::new(RefCell::new(host));
EvmTester{
EvmEmulator{
scope: CallScope::default(),
host,
is_execution_cost_enabled: false,
access_list: AccessList::default(),
}
}

pub fn new_with(context: TxContext) -> Self {
pub fn new_stateful_with(context: TxContext) -> Self {
let host = StatefulHost::new_with(context);
let host = Rc::new(RefCell::new(host));
EvmTester{
EvmEmulator{
scope: CallScope::default(),
host,
is_execution_cost_enabled: false,
Expand Down
16 changes: 12 additions & 4 deletions src/host/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
pub mod host;
pub mod transient;
pub mod stateful;

use ethereum_types::{Address, U256};
use bytes::Bytes;

use crate::{model::evmc::{
use crate::{model::{evmc::{
Message, Output, TxContext, AccessStatus, StorageStatus
}, executor::journal::Snapshot};
}, code::Code}, executor::journal::Snapshot};

use self::stateful::Account;

/// EVMC Host interface
/// https://evmc.ethereum.org/structevmc__host__interface.html
Expand All @@ -29,11 +31,17 @@ pub trait Host {
fn access_storage(&mut self, address: Address, key: U256) -> AccessStatus;

// extensions
fn add_account(&mut self, address: Address, account: Account);
fn debug_get_storage(&self, address: Address, key: U256) -> U256;
fn debug_set_storage(&mut self, address: Address, key: U256, new_value: U256);
fn debug_set_storage_as_warm(&mut self);
fn debug_deploy_contract(&mut self, address_hex: &str, code: Code, balance: U256);
fn debug_deploy_contract2(&mut self, address: Address, code: Code, balance: U256);
fn get_blockhash(&self, height: usize) -> U256;
fn get_code(&self, address: Address, offset: usize, size: usize) -> Bytes;
fn add_balance(&mut self, address: Address, amount: U256);
fn subtract_balance(&mut self, address: Address, amount: U256);
fn take_snapshot(&self) -> Snapshot;
fn rollback(&mut self, snapshot: Snapshot);
fn force_set_storage(&mut self, address: Address, key: U256, value: U256);
fn force_update_storage(&mut self, address: Address, key: U256, value: U256);
}
56 changes: 54 additions & 2 deletions src/host/stateful/mod.rs → src/host/stateful.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,58 @@ impl Host for StatefulHost {
access_status
}

fn add_account(&mut self, address: Address, account: Account) {
self.accounts.insert(address, account);
}
fn debug_get_storage(&self, address: Address, key: U256) -> U256 {
self.accounts
.get(&address)
.and_then(|account| account.storage.get(&key).map(|value| value.current_value))
.unwrap_or_else(U256::zero)
}
fn debug_set_storage(&mut self, address: Address, key: U256, new_value: U256) {
let value = self
.accounts
.entry(address)
.or_default()
.storage
.entry(key)
.or_default();

value.original_value = new_value;
value.current_value = new_value;
}
fn debug_set_storage_as_warm(&mut self) {
self.is_always_warm = true;
}
fn debug_deploy_contract(&mut self, address_hex: &str, code: Code, balance: U256) {
let mut dst = [0u8; 20];
let hex = decode(address_hex).unwrap();
for i in 0..hex.len() {
dst[hex.len() - 1 - i] = hex[hex.len() - 1 - i];
}

let account = Account {
balance,
code: code.0.into(),
code_hash: U256::from(0x123456),
nonce: 0,
storage: Default::default(),
};
let address = Address::from_slice(&dst);
self.accounts.insert(address, account);
}
fn debug_deploy_contract2(&mut self, address: Address, code: Code, balance: U256) {
let account = Account {
balance,
code: code.0.into(),
code_hash: U256::from(0x123456),
nonce: 0,
storage: Default::default(),
};
self.accounts.insert(address, account);
}

fn get_blockhash(&self, height: usize) -> U256 {
U256::from(height)
}
Expand Down Expand Up @@ -390,11 +442,11 @@ impl Host for StatefulHost {
let length = self.journal.storage_log.len();
for _ in 0..length - snapshot {
if let Some(delta) = self.journal.storage_log.pop() {
self.force_set_storage(delta.address, delta.key, delta.previous);
self.force_update_storage(delta.address, delta.key, delta.previous);
}
}
}
fn force_set_storage(&mut self, address: Address, key: U256, new_value: U256) {
fn force_update_storage(&mut self, address: Address, key: U256, new_value: U256) {
let value = self
.accounts
.entry(address)
Expand Down
25 changes: 23 additions & 2 deletions src/host/host.rs → src/host/transient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ use bytes::Bytes;

use crate::executor::journal::Snapshot;
use crate::host::Host;
use crate::model::code::Code;
use crate::model::evmc::{
Message, Output, TxContext, AccessStatus, StatusCode, StorageStatus
};

use super::stateful::Account;

/// host without no persistent storage
pub struct TransientHost {
context: TxContext,
Expand All @@ -29,7 +32,7 @@ impl TransientHost {
}
}

pub fn new_with_context(context: TxContext) -> Self {
pub fn new_with(context: TxContext) -> Self {
TransientHost{
context: context,
}
Expand Down Expand Up @@ -83,6 +86,24 @@ impl Host for TransientHost {
AccessStatus::Warm
}

fn add_account(&mut self, address: Address, account: Account) {

}
fn debug_get_storage(&self, address: Address, key: U256) -> U256 {
U256::zero()
}
fn debug_set_storage(&mut self, address: Address, key: U256, new_value: U256) {

}
fn debug_set_storage_as_warm(&mut self) {

}
fn debug_deploy_contract(&mut self, address_hex: &str, code: Code, balance: U256) {

}
fn debug_deploy_contract2(&mut self, address: Address, code: Code, balance: U256) {

}

fn get_blockhash(&self, height: usize) -> U256 {
U256::from(0x0101)
Expand All @@ -102,7 +123,7 @@ impl Host for TransientHost {
fn rollback(&mut self, snapshot: Snapshot){

}
fn force_set_storage(&mut self, address: Address, key: U256, value: U256){
fn force_update_storage(&mut self, address: Address, key: U256, value: U256){

}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ pub mod interpreter;
pub mod executor;
pub mod utils;
pub mod host;
pub mod tester;
pub mod emulator;
16 changes: 16 additions & 0 deletions src/model/evmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,22 @@ pub struct TxContext {
pub base_fee: U256,
}

impl Default for TxContext {
fn default() -> Self {
TxContext {
gas_price: U256::default(),
origin: Address::from_low_u64_be(0),
coinbase: Address::from_low_u64_be(0),
block_number: 0,
block_timestamp: 0,
gas_limit: i64::max_value(),
difficulty: U256::default(),
chain_id: U256::from(0),
base_fee: U256::from(0),
}
}
}

/// https://evmc.ethereum.org/group__EVMC.html#ga9f71195f3873f9979d81d7a5e1b3aaf0
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum AccessStatus {
Expand Down
Loading

0 comments on commit a347161

Please sign in to comment.