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

VM/Transaction trait/struct refactoring #155

Merged
merged 12 commits into from
Jun 1, 2017
29 changes: 16 additions & 13 deletions regtests/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::collections::HashMap;

use sputnikvm::{Gas, Address};
use bigint::{U256, M256, read_hex};
use sputnikvm::vm::{BlockHeader, Context, SeqContextVM, VM, Patch, AccountCommitment, Account, FRONTIER_PATCH};
use sputnikvm::vm::{BlockHeader, Context, SeqTransactionVM, Transaction, VM, Patch, AccountCommitment, Account, FRONTIER_PATCH};
use sputnikvm::vm::errors::RequireError;
use gethrpc::{regression, GethRPCClient, RPCCall, RPCBlock, RPCTransaction};

Expand All @@ -42,16 +42,14 @@ fn from_rpc_block(block: &RPCBlock) -> BlockHeader {
}
}

fn from_rpc_transaction_and_code(transaction: &RPCTransaction, code: &str) -> Context {
Context {
fn from_rpc_transaction(transaction: &RPCTransaction) -> Transaction {
Transaction::MessageCall {
caller: Address::from_str(&transaction.from).unwrap(),
address: Address::from_str(&transaction.to).unwrap(),
origin: Address::from_str(&transaction.to).unwrap(),
value: U256::from_str(&transaction.value).unwrap(),
code: read_hex(code).unwrap(),
data: read_hex(&transaction.input).unwrap(),
gas_limit: Gas::from_str(&transaction.gas).unwrap(),
gas_price: Gas::from_str(&transaction.gasPrice).unwrap(),
data: read_hex(&transaction.input).unwrap(),
}
}

Expand Down Expand Up @@ -81,14 +79,12 @@ fn main() {
let receipt = client.get_transaction_receipt(&transaction_hash);
println!("receipt: {:?}", receipt);
if transaction.to.is_empty() {
continue;
unimplemented!();
}
let code = client.get_code(&transaction.to, &block.number);
println!("code: {:?}\n", code);

let context = from_rpc_transaction_and_code(&transaction, &code);
let transaction = from_rpc_transaction(&transaction);

let mut vm = SeqContextVM::new(context.clone(), block_header.clone(), &FRONTIER_PATCH);
let mut vm = SeqTransactionVM::new(transaction, block_header.clone(), &FRONTIER_PATCH);
loop {
match vm.fire() {
Ok(()) => {
Expand Down Expand Up @@ -120,6 +116,14 @@ fn main() {
index: index,
value: value,
});
},
Err(RequireError::AccountCode(address)) => {
println!("Feeding VM account code at 0x{:x} ...", address);
let code = read_hex(&client.get_code(&format!("0x{:x}", address), &last_block_number)).unwrap();
vm.commit_account(AccountCommitment::Code {
address: address,
code: code,
});
}
Err(err) => {
println!("Unhandled require: {:?}", err);
Expand All @@ -130,8 +134,7 @@ fn main() {

println!("\ntests after the vm has run:");
println!("1. return status: {:?}", vm.status());
println!("2. test gasUsed == {}, actual VM result: 0x{:x}", receipt.gasUsed,
context.gas_limit + upfront_cost(&transaction.input) - vm.available_gas());
println!("2. test gasUsed == {}, actual VM result: 0x{:x}", receipt.gasUsed, vm.used_gas());
println!("3. logs and order is {:?}, actual VM result: {:?}", receipt.logs, vm.logs());

println!("\nwhen the block is finished, test:");
Expand Down
4 changes: 0 additions & 4 deletions sputnikvm/src/vm/eval/cost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_MEMORY: usize = 3;
const G_TXCREATE: usize = 32000;
const G_TXDATAZERO: usize = 4;
const G_TXDATANONZERO: usize = 68;
const G_TRANSACTION: usize = 21000;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
Expand Down
19 changes: 13 additions & 6 deletions sputnikvm/src/vm/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,28 +94,35 @@ pub enum Control {
impl<M: Memory + Default> Machine<M> {
/// Create a new runtime.
pub fn new(context: Context, block: BlockHeader, patch: &'static Patch, depth: usize) -> Self {
Self::with_states(context, block, patch, depth,
AccountState::default(), BlockhashState::default())
}

pub fn with_states(context: Context, block: BlockHeader, patch: &'static Patch,
depth: usize, account_state: AccountState,
blockhash_state: BlockhashState) -> Self {
Machine {
pc: PC::new(context.code.as_slice()),
status: MachineStatus::Running,
state: State {
memory: M::default(),
stack: Stack::default(),

context: context,
block: block,
patch: patch,
context,
block,
patch,

out: Vec::new(),

memory_cost: Gas::zero(),
used_gas: Gas::zero(),
refunded_gas: Gas::zero(),

account_state: AccountState::default(),
blockhash_state: BlockhashState::default(),
account_state,
blockhash_state,
logs: Vec::new(),

depth: depth,
depth,
},
}
}
Expand Down
51 changes: 22 additions & 29 deletions sputnikvm/src/vm/eval/run/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
use utils::address::Address;
use utils::bigint::{U256, M256};
use utils::gas::Gas;
use vm::{Memory, Log, Context};
use vm::{Memory, Log, Context, Transaction};
use super::State;
use rlp::RlpStream;

use crypto::sha3::Sha3;
use crypto::digest::Digest;
Expand Down Expand Up @@ -52,27 +51,18 @@ pub fn create<M: Memory + Default>(state: &mut State<M>, after_gas: Gas) -> Opti
}

let init = copy_from_memory(&state.memory, init_start, init_len);
let nonce = state.account_state.nonce(state.context.address).unwrap();
let mut rlp = RlpStream::new();
rlp.begin_list(2);
rlp.append(&state.context.address);
rlp.append(&nonce);
let mut address_array = [0u8; 32];
let mut sha3 = Sha3::keccak256();
sha3.input(rlp.out().as_slice());
sha3.result(&mut address_array);
let address = Address::from(M256::from(address_array));
let context = Context {
address: address,
let transaction = Transaction::ContractCreation {
caller: state.context.address,
code: init,
data: Vec::new(),
gas_limit: after_gas,
gas_price: state.context.gas_price,
origin: state.context.origin,
gas_limit: after_gas,
value: value,
init: init,
};
push!(state, address.into());
let context = transaction.into_context(
Gas::zero(), Some(state.context.origin), &state.account_state
).unwrap();

push!(state, context.address.into());
Some(context)
}

Expand All @@ -87,16 +77,18 @@ pub fn call<M: Memory + Default>(state: &mut State<M>, stipend_gas: Gas, after_g

let input = copy_from_memory(&state.memory, in_start, in_len);
let gas_limit = gas + stipend_gas;
let context = Context {

let transaction = Transaction::MessageCall {
address: to,
caller: state.context.address,
code: state.account_state.code(to).unwrap().into(),
data: input,
gas_limit: gas_limit,
gas_price: state.context.gas_price,
origin: state.context.origin,
gas_limit: gas_limit,
value: value,
data: input,
};
let context = transaction.into_context(
Gas::zero(), Some(state.context.origin), &state.account_state
).unwrap();
push!(state, M256::zero());
Some((context, (out_start, out_len)))
}
Expand All @@ -112,16 +104,17 @@ pub fn callcode<M: Memory + Default>(state: &mut State<M>, stipend_gas: Gas, aft

let input = copy_from_memory(&state.memory, in_start, in_len);
let gas_limit = gas + stipend_gas;
let context = Context {
let transaction = Transaction::MessageCall {
address: state.context.address,
caller: state.context.address,
code: state.account_state.code(to).unwrap().into(),
data: input,
gas_limit: gas_limit,
gas_price: state.context.gas_price,
origin: state.context.origin,
gas_limit: gas_limit,
value: value,
data: input,
};
let context = transaction.into_context(
Gas::zero(), Some(state.context.origin), &state.account_state
).unwrap();
push!(state, M256::zero());
Some((context, (out_start, out_len)))
}
14 changes: 13 additions & 1 deletion sputnikvm/src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub use self::params::*;
pub use self::patch::*;
pub use self::eval::{State, Machine, MachineStatus};
pub use self::commit::{AccountCommitment, Account, AccountState, BlockhashState};
pub use self::transaction::{Transaction, TransactionVM};

use std::collections::hash_map;
use utils::bigint::M256;
Expand Down Expand Up @@ -73,6 +74,7 @@ pub trait VM {
/// A sequencial VM. It uses sequencial memory representation and hash
/// map storage for accounts.
pub type SeqContextVM = ContextVM<SeqMemory>;
pub type SeqTransactionVM = TransactionVM<SeqMemory>;

/// A VM that executes using a context and block information.
pub struct ContextVM<M> {
Expand All @@ -91,6 +93,16 @@ impl<M: Memory + Default> ContextVM<M> {
}
}

pub fn with_states(context: Context, block: BlockHeader, patch: &'static Patch,
account_state: AccountState, blockhash_state: BlockhashState) -> Self {
let mut machines = Vec::new();
machines.push(Machine::with_states(context, block, patch, 1, account_state, blockhash_state));
ContextVM {
machines,
history: Vec::new()
}
}

/// Returns the call create history. Only used in testing.
pub fn history(&self) -> &[Context] {
self.history.as_slice()
Expand Down Expand Up @@ -182,7 +194,7 @@ impl<M: Memory + Default> VM for ContextVM<M> {

/// Returns the used gas of this VM.
fn used_gas(&self) -> Gas {
self.machines[0].state().used_gas
self.machines[0].state().memory_gas() + self.machines[0].state().used_gas
}

/// Returns the refunded gas of this VM.
Expand Down
16 changes: 16 additions & 0 deletions sputnikvm/src/vm/patch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub struct Patch {
pub gas_suicide: usize,
pub gas_call: usize,
pub gas_expbyte: usize,
pub gas_transaction_create: usize,
}

pub static FRONTIER_PATCH: Patch = Patch {
Expand All @@ -16,6 +17,18 @@ pub static FRONTIER_PATCH: Patch = Patch {
gas_suicide: 0,
gas_call: 40,
gas_expbyte: 10,
gas_transaction_create: 0,
};

pub static HOMESTEAD_PATCH: Patch = Patch {
callstack_limit: 1024,
gas_extcode: 20,
gas_balance: 20,
gas_sload: 50,
gas_suicide: 0,
gas_call: 40,
gas_expbyte: 10,
gas_transaction_create: 32000,
};

pub static VMTEST_PATCH: Patch = Patch {
Expand All @@ -26,6 +39,7 @@ pub static VMTEST_PATCH: Patch = Patch {
gas_suicide: 0,
gas_call: 40,
gas_expbyte: 10,
gas_transaction_create: 0,
};

pub static EIP150_PATCH: Patch = Patch {
Expand All @@ -36,6 +50,7 @@ pub static EIP150_PATCH: Patch = Patch {
gas_suicide: 5000,
gas_call: 700,
gas_expbyte: 10,
gas_transaction_create: 32000,
};

pub static EIP160_PATCH: Patch = Patch {
Expand All @@ -46,4 +61,5 @@ pub static EIP160_PATCH: Patch = Patch {
gas_suicide: 5000,
gas_call: 700,
gas_expbyte: 50,
gas_transaction_create: 32000,
};
Loading