diff --git a/Cargo.toml b/Cargo.toml index f8279eaa7..04b99f707 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,3 +21,4 @@ evmjit = { path = "rust-evmjit", optional = true } [features] jit = ["evmjit"] +evm_debug = [] diff --git a/src/evm/evm.rs b/src/evm/evm.rs index 9d5195469..696d49474 100644 --- a/src/evm/evm.rs +++ b/src/evm/evm.rs @@ -47,5 +47,5 @@ pub type Result = result::Result; /// Evm interface. pub trait Evm { /// This function should be used to execute transaction. - fn exec(&self, params: &ActionParams, ext: &mut Ext) -> Result; + fn exec(&self, params: ActionParams, ext: &mut Ext) -> Result; } diff --git a/src/evm/ext.rs b/src/evm/ext.rs index bc6e7d8f2..924db7a71 100644 --- a/src/evm/ext.rs +++ b/src/evm/ext.rs @@ -6,12 +6,35 @@ use util::uint::*; use evm::{Schedule, Error}; use env_info::*; +/// Result of externalities create function. +pub enum ContractCreateResult { + /// Returned when creation was successfull. + /// Contains an address of newly created contract and gas left. + Created(Address, U256), + /// Returned when contract creation failed. + /// VM doesn't have to know the reason. + Failed +} + +/// Result of externalities call function. +pub enum MessageCallResult { + /// Returned when message call was successfull. + /// Contains gas left. + Success(U256), + /// Returned when message call failed. + /// VM doesn't have to know the reason. + Failed +} + pub trait Ext { /// Returns a value for given key. fn storage_at(&self, key: &H256) -> H256; /// Stores a value for given key. - fn set_storage_at(&mut self, key: H256, value: H256); + fn set_storage(&mut self, key: H256, value: H256); + + /// Determine whether an account exists. + fn exists(&self, address: &Address) -> bool; /// Returns address balance. fn balance(&self, address: &Address) -> U256; @@ -22,7 +45,7 @@ pub trait Ext { /// Creates new contract. /// /// Returns gas_left and contract address if contract creation was succesfull. - fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> (U256, Option
); + fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult; /// Message call. /// @@ -31,12 +54,11 @@ pub trait Ext { /// and true if subcall was successfull. fn call(&mut self, gas: &U256, - call_gas: &U256, - receive_address: &Address, + address: &Address, value: &U256, data: &[u8], code_address: &Address, - output: &mut [u8]) -> Result<(U256, bool), Error>; + output: &mut [u8]) -> MessageCallResult; /// Returns code at given address fn extcode(&self, address: &Address) -> Bytes; @@ -57,4 +79,13 @@ pub trait Ext { /// Returns environment info. fn env_info(&self) -> &EnvInfo; + + /// Returns current depth of execution. + /// + /// If contract A calls contract B, and contract B calls C, + /// then A depth is 0, B is 1, C is 2 and so on. + fn depth(&self) -> usize; + + /// Increments sstore refunds count by 1. + fn inc_sstore_clears(&mut self); } diff --git a/src/evm/interpreter.rs b/src/evm/interpreter.rs index 687bdeec5..ddb636a36 100644 --- a/src/evm/interpreter.rs +++ b/src/evm/interpreter.rs @@ -6,11 +6,17 @@ use super::instructions as instructions; use super::instructions::Instruction; use std::num::wrapping::OverflowingOps; use std::marker::Copy; +use evm::{MessageCallResult, ContractCreateResult}; + +#[cfg(not(feature = "evm_debug"))] +macro_rules! evm_debug { + ($x: expr) => {} +} #[cfg(feature = "evm_debug")] macro_rules! evm_debug { ($x: expr) => { - println!($x); + $x } } @@ -21,11 +27,6 @@ fn color(instruction: Instruction, name: &'static str) -> String { format!("\x1B[1;{}m{}\x1B[0m", colors[c], name) } -#[cfg(not(feature = "evm_debug"))] -macro_rules! evm_debug { - ($x: expr) => {} -} - type CodePosition = usize; type Gas = U256; type ProgramCounter = usize; @@ -81,7 +82,7 @@ impl Stack for VecStack { match val { Some(x) => { evm_debug!({ - format!(" POP: {}", x) + println!(" POP: {}", x) }); x }, @@ -100,7 +101,7 @@ impl Stack for VecStack { fn push(&mut self, elem: S) { evm_debug!({ - format!(" PUSH: {}", elem) + println!(" PUSH: {}", elem) }); self.stack.push(elem); } @@ -246,7 +247,9 @@ enum InstructionCost { } enum InstructionResult { - AdditionalGasCost(U256), + Ok, + UseAllGas, + UnusedGas(U256), JumpToPosition(U256), StopExecutionWithGasCost(U256), StopExecution @@ -256,7 +259,7 @@ enum InstructionResult { pub struct Interpreter; impl evm::Evm for Interpreter { - fn exec(&self, params: &ActionParams, ext: &mut evm::Ext) -> evm::Result { + fn exec(&self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result { let code = ¶ms.code.clone().unwrap(); let valid_jump_destinations = self.find_jump_destinations(&code); @@ -279,29 +282,33 @@ impl evm::Evm for Interpreter { current_gas = current_gas - gas_cost; evm_debug!({ - format!("[0x{:x}][{}(0x{:x}) Gas: {}\n Gas Before: {}", + println!("[0x{:x}][{}(0x{:x}) Gas: {:x}\n Gas Before: {:x}", reader.position, color(instruction, instructions::get_info(instruction).name), instruction, gas_cost, current_gas + gas_cost - ) + ); }); // Execute instruction let result = try!(self.exec_instruction( - current_gas, params, ext, instruction, &mut reader, &mut mem, &mut stack + current_gas, ¶ms, ext, instruction, &mut reader, &mut mem, &mut stack )); // Advance match result { + InstructionResult::Ok => {}, + InstructionResult::UnusedGas(gas) => { + current_gas = current_gas + gas; + }, + InstructionResult::UseAllGas => { + current_gas = U256::zero(); + }, InstructionResult::JumpToPosition(position) => { let pos = try!(self.verify_jump(position, &valid_jump_destinations)); reader.position = pos; }, - InstructionResult::AdditionalGasCost(gas_cost) => { - current_gas = current_gas - gas_cost; - }, InstructionResult::StopExecutionWithGasCost(gas_cost) => { current_gas = current_gas - gas_cost; reader.position = code.len(); @@ -351,6 +358,7 @@ impl Interpreter { let gas = if self.is_zero(&val) && !self.is_zero(newval) { schedule.sstore_set_gas } else if !self.is_zero(&val) && self.is_zero(newval) { + // Refund is added when actually executing sstore schedule.sstore_reset_gas } else { schedule.sstore_reset_gas @@ -397,18 +405,34 @@ impl Interpreter { instructions::LOG0...instructions::LOG4 => { let no_of_topics = instructions::get_log_topics(instruction); let log_gas = schedule.log_gas + schedule.log_topic_gas * no_of_topics; + // TODO [todr] potential overflow of datagass let data_gas = stack.peek(1).clone() * U256::from(schedule.log_data_gas); let gas = try!(self.gas_add(data_gas, U256::from(log_gas))); InstructionCost::GasMem(gas, self.mem_needed(stack.peek(0), stack.peek(1))) }, instructions::CALL | instructions::CALLCODE => { - // [todr] we actuall call gas_cost is calculated in ext - let gas = U256::from(schedule.call_gas); - let mem = self.mem_max( - self.mem_needed(stack.peek(5), stack.peek(6)), - self.mem_needed(stack.peek(3), stack.peek(4)) - ); - InstructionCost::GasMem(gas, mem) + match add_u256_usize(stack.peek(0), schedule.call_gas) { + (_gas, true) => InstructionCost::GasMem(U256::zero(), RequiredMem::OutOfMemory), + (mut gas, false) => { + let mem = self.mem_max( + self.mem_needed(stack.peek(5), stack.peek(6)), + self.mem_needed(stack.peek(3), stack.peek(4)) + ); + + let address = u256_to_address(stack.peek(1)); + + // TODO [todr] Potential overflows + if instruction == instructions::CALL && !ext.exists(&address) { + gas = gas + U256::from(schedule.call_new_account_gas); + }; + + if stack.peek(2).clone() > U256::zero() { + gas = gas + U256::from(schedule.call_value_transfer_gas) + }; + + InstructionCost::GasMem(gas,mem) + } + } }, instructions::DELEGATECALL => { match add_u256_usize(stack.peek(0), schedule.call_gas) { @@ -554,30 +578,41 @@ impl Interpreter { let init_size = stack.pop_back(); let contract_code = mem.read_slice(init_off, init_size); - let (gas_left, maybe_address) = ext.create(&gas, &endowment, &contract_code); - match maybe_address { - Some(address) => stack.push(address_to_u256(address)), - None => stack.push(U256::zero()) + let can_create = ext.balance(¶ms.address) >= endowment && ext.depth() < ext.schedule().max_depth; + + if !can_create { + stack.push(U256::zero()); + return Ok(InstructionResult::Ok); } - return Ok(InstructionResult::AdditionalGasCost( - gas - gas_left - )); + + let create_result = ext.create(&gas, &endowment, &contract_code); + return match create_result { + ContractCreateResult::Created(address, gas_left) => { + stack.push(address_to_u256(address)); + Ok(InstructionResult::UnusedGas(gas - gas_left)) + }, + ContractCreateResult::Failed => { + stack.push(U256::zero()); + // TODO [todr] Should we just StopExecution here? + Ok(InstructionResult::UseAllGas) + } + }; }, instructions::CALL | instructions::CALLCODE | instructions::DELEGATECALL => { + assert!(ext.schedule().call_value_transfer_gas > ext.schedule().call_stipend, "overflow possible"); let call_gas = stack.pop_back(); let code_address = stack.pop_back(); let code_address = u256_to_address(&code_address); + let is_delegatecall = instruction == instructions::DELEGATECALL; - let value = if instruction == instructions::DELEGATECALL { - params.value - } else { - stack.pop_back() + let value = match is_delegatecall { + true => params.value, + false => stack.pop_back() }; - let address = if instruction == instructions::CALL { - &code_address - } else { - ¶ms.address + let address = match instruction == instructions::CALL { + true => &code_address, + false => ¶ms.address }; let in_off = stack.pop_back(); @@ -585,23 +620,37 @@ impl Interpreter { let out_off = stack.pop_back(); let out_size = stack.pop_back(); - let (gas_left, call_successful) = { + let call_gas = call_gas + match !is_delegatecall && value > U256::zero() { + true => U256::from(ext.schedule().call_stipend), + false => U256::zero() + }; + + let can_call = (is_delegatecall || ext.balance(¶ms.address) >= value) && ext.depth() < ext.schedule().max_depth; + + if !can_call { + stack.push(U256::zero()); + return Ok(InstructionResult::UnusedGas(call_gas)); + } + + let call_result = { // we need to write and read from memory in the same time // and we don't want to copy let input = unsafe { ::std::mem::transmute(mem.read_slice(in_off, in_size)) }; let output = mem.writeable_slice(out_off, out_size); - try!( - ext.call(&gas, &call_gas, address, &value, input, &code_address, output) - ) + ext.call(&call_gas, address, &value, input, &code_address, output) + }; + + return match call_result { + MessageCallResult::Success(gas_left) => { + println!("Unused: {}", gas_left); + stack.push(U256::one()); + Ok(InstructionResult::UnusedGas(gas_left)) + }, + MessageCallResult::Failed => { + stack.push(U256::zero()); + Ok(InstructionResult::Ok) + } }; - if call_successful { - stack.push(U256::one()); - } else { - stack.push(U256::zero()); - } - return Ok(InstructionResult::AdditionalGasCost( - gas - gas_left - )); }, instructions::RETURN => { let init_off = stack.pop_back(); @@ -665,9 +714,15 @@ impl Interpreter { stack.push(word); }, instructions::SSTORE => { - let key = H256::from(&stack.pop_back()); - let word = H256::from(&stack.pop_back()); - ext.set_storage_at(key, word); + let address = H256::from(&stack.pop_back()); + let val = stack.pop_back(); + + let current_val = U256::from(ext.storage_at(&address).as_slice()); + // Increase refund for clear + if !self.is_zero(¤t_val) && self.is_zero(&val) { + ext.inc_sstore_clears(); + } + ext.set_storage(address, H256::from(&val)); }, instructions::PC => { stack.push(U256::from(code.position - 1)); @@ -755,7 +810,7 @@ impl Interpreter { try!(self.exec_stack_instruction(instruction, stack)); } }; - Ok(InstructionResult::AdditionalGasCost(U256::zero())) + Ok(InstructionResult::Ok) } fn copy_data_to_memory(&self, @@ -769,10 +824,9 @@ impl Interpreter { if index < U256::from(data_size) { let u_index = index.low_u64() as usize; - let bound_size = if size + index > U256::from(data_size) { - data_size - } else { - size.low_u64() as usize + u_index + let bound_size = match size + index > U256::from(data_size) { + true => data_size, + false => size.low_u64() as usize + u_index }; mem.write_slice(offset, &data[u_index..bound_size]); @@ -801,10 +855,9 @@ impl Interpreter { } fn verify_gas(&self, current_gas: &U256, gas_cost: &U256) -> Result<(), evm::Error> { - if current_gas < gas_cost { - Err(evm::Error::OutOfGas) - } else { - Ok(()) + match current_gas < gas_cost { + true => Err(evm::Error::OutOfGas), + false => Ok(()) } } @@ -867,21 +920,23 @@ impl Interpreter { instructions::DIV => { let a = stack.pop_back(); let b = stack.pop_back(); - stack.push(if !self.is_zero(&b) { - let (c, _overflow) = a.overflowing_div(b); - c - } else { - U256::zero() + stack.push(match !self.is_zero(&b) { + true => { + let (c, _overflow) = a.overflowing_div(b); + c + }, + false => U256::zero() }); }, instructions::MOD => { let a = stack.pop_back(); let b = stack.pop_back(); - stack.push(if !self.is_zero(&b) { - let (c, _overflow) = a.overflowing_rem(b); - c - } else { - U256::zero() + stack.push(match !self.is_zero(&b) { + true => { + let (c, _overflow) = a.overflowing_rem(b); + c + }, + false => U256::zero() }); }, instructions::SDIV => { @@ -979,10 +1034,9 @@ impl Interpreter { instructions::BYTE => { let word = stack.pop_back(); let val = stack.pop_back(); - let byte = if word < U256::from(32) { - (val >> (8 * (31 - word.low_u64() as usize))) & U256::from(0xff) - } else { - U256::zero() + let byte = match word < U256::from(32) { + true => (val >> (8 * (31 - word.low_u64() as usize))) & U256::from(0xff), + false => U256::zero() }; stack.push(byte); }, diff --git a/src/evm/jit.rs b/src/evm/jit.rs index 126e6f5c9..9f990155d 100644 --- a/src/evm/jit.rs +++ b/src/evm/jit.rs @@ -3,43 +3,6 @@ use common::*; use evmjit; use evm; -/// Ethcore representation of evmjit runtime data. -struct RuntimeData { - gas: U256, - gas_price: U256, - call_data: Bytes, - address: Address, - caller: Address, - origin: Address, - call_value: U256, - author: Address, - difficulty: U256, - gas_limit: U256, - number: u64, - timestamp: u64, - code: Bytes -} - -impl RuntimeData { - fn new() -> RuntimeData { - RuntimeData { - gas: U256::zero(), - gas_price: U256::zero(), - call_data: vec![], - address: Address::new(), - caller: Address::new(), - origin: Address::new(), - call_value: U256::zero(), - author: Address::new(), - difficulty: U256::zero(), - gas_limit: U256::zero(), - number: 0, - timestamp: 0, - code: vec![] - } - } -} - /// Should be used to convert jit types to ethcore trait FromJit: Sized { fn from_jit(input: T) -> Self; @@ -126,64 +89,42 @@ impl IntoJit for Address { } } -impl IntoJit for RuntimeData { - fn into_jit(self) -> evmjit::RuntimeDataHandle { - let mut data = evmjit::RuntimeDataHandle::new(); - assert!(self.gas <= U256::from(u64::max_value()), "evmjit gas must be lower than 2 ^ 64"); - assert!(self.gas_price <= U256::from(u64::max_value()), "evmjit gas_price must be lower than 2 ^ 64"); - data.gas = self.gas.low_u64() as i64; - data.gas_price = self.gas_price.low_u64() as i64; - data.call_data = self.call_data.as_ptr(); - data.call_data_size = self.call_data.len() as u64; - mem::forget(self.call_data); - data.address = self.address.into_jit(); - data.caller = self.caller.into_jit(); - data.origin = self.origin.into_jit(); - data.call_value = self.call_value.into_jit(); - data.author = self.author.into_jit(); - data.difficulty = self.difficulty.into_jit(); - data.gas_limit = self.gas_limit.into_jit(); - data.number = self.number; - data.timestamp = self.timestamp as i64; - data.code = self.code.as_ptr(); - data.code_size = self.code.len() as u64; - data.code_hash = self.code.sha3().into_jit(); - mem::forget(self.code); - data - } -} - /// Externalities adapter. Maps callbacks from evmjit to externalities trait. /// /// Evmjit doesn't have to know about children execution failures. /// This adapter 'catches' them and moves upstream. struct ExtAdapter<'a> { ext: &'a mut evm::Ext, - err: &'a mut Option + address: Address } impl<'a> ExtAdapter<'a> { - fn new(ext: &'a mut evm::Ext, err: &'a mut Option) -> Self { + fn new(ext: &'a mut evm::Ext, address: Address) -> Self { ExtAdapter { ext: ext, - err: err + address: address } } } impl<'a> evmjit::Ext for ExtAdapter<'a> { - fn sload(&self, index: *const evmjit::I256, out_value: *mut evmjit::I256) { + fn sload(&self, key: *const evmjit::I256, out_value: *mut evmjit::I256) { unsafe { - let i = H256::from_jit(&*index); + let i = H256::from_jit(&*key); let o = self.ext.storage_at(&i); *out_value = o.into_jit(); } } - fn sstore(&mut self, index: *const evmjit::I256, value: *const evmjit::I256) { - unsafe { - self.ext.set_storage_at(H256::from_jit(&*index), H256::from_jit(&*value)); + fn sstore(&mut self, key: *const evmjit::I256, value: *const evmjit::I256) { + let key = unsafe { H256::from_jit(&*key) }; + let value = unsafe { H256::from_jit(&*value) }; + let old_value = self.ext.storage_at(&key); + // if SSTORE nonzero -> zero, increment refund count + if !old_value.is_zero() && value.is_zero() { + self.ext.inc_sstore_clears(); } + self.ext.set_storage(key, value); } fn balance(&self, address: *const evmjit::H256, out_value: *mut evmjit::I256) { @@ -204,17 +145,29 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { fn create(&mut self, io_gas: *mut u64, - endowment: *const evmjit::I256, + value: *const evmjit::I256, init_beg: *const u8, init_size: u64, address: *mut evmjit::H256) { - unsafe { - let (gas_left, opt_addr) = self.ext.create(&U256::from(*io_gas), &U256::from_jit(&*endowment), slice::from_raw_parts(init_beg, init_size as usize)); - *io_gas = gas_left.low_u64(); - *address = match opt_addr { - Some(addr) => addr.into_jit(), - _ => Address::new().into_jit() - }; + + let gas = unsafe { U256::from(*io_gas) }; + let value = unsafe { U256::from_jit(&*value) }; + let code = unsafe { slice::from_raw_parts(init_beg, init_size as usize) }; + + // check if balance is sufficient and we are not too deep + if self.ext.balance(&self.address) >= value && self.ext.depth() < self.ext.schedule().max_depth { + match self.ext.create(&gas, &value, code) { + evm::ContractCreateResult::Created(new_address, gas_left) => unsafe { + *address = new_address.into_jit(); + *io_gas = gas_left.low_u64(); + }, + evm::ContractCreateResult::Failed => unsafe { + *address = Address::new().into_jit(); + *io_gas = 0; + } + } + } else { + unsafe { *address = Address::new().into_jit(); } } } @@ -228,31 +181,56 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { out_beg: *mut u8, out_size: u64, code_address: *const evmjit::H256) -> bool { - unsafe { - let res = self.ext.call(&U256::from(*io_gas), - &U256::from(call_gas), - &Address::from_jit(&*receive_address), - &U256::from_jit(&*value), - slice::from_raw_parts(in_beg, in_size as usize), - &Address::from_jit(&*code_address), - slice::from_raw_parts_mut(out_beg, out_size as usize)); - match res { - Ok((gas_left, ok)) => { - *io_gas = gas_left.low_u64(); - ok - } - Err(evm::Error::OutOfGas) => { - // hack to propagate out_of_gas to evmjit. - // must be negative - *io_gas = -1i64 as u64; - false - }, - Err(err) => { - // internal error. - *self.err = Some(err); - *io_gas = -1i64 as u64; - false - } + + let mut gas = unsafe { U256::from(*io_gas) }; + let mut call_gas = U256::from(call_gas); + let mut gas_cost = call_gas; + let receive_address = unsafe { Address::from_jit(&*receive_address) }; + let code_address = unsafe { Address::from_jit(&*code_address) }; + let value = unsafe { U256::from_jit(&*value) }; + + // receive address and code address are the same in normal calls + let is_callcode = receive_address != code_address; + if !is_callcode && !self.ext.exists(&code_address) { + gas_cost = gas_cost + U256::from(self.ext.schedule().call_new_account_gas); + } + + if value > U256::zero() { + assert!(self.ext.schedule().call_value_transfer_gas > self.ext.schedule().call_stipend, "overflow possible"); + gas_cost = gas_cost + U256::from(self.ext.schedule().call_value_transfer_gas); + call_gas = call_gas + U256::from(self.ext.schedule().call_stipend); + } + + if gas_cost > gas { + unsafe { + *io_gas = -1i64 as u64; + return false; + } + } + + gas = gas - gas_cost; + + // check if balance is sufficient and we are not too deep + if self.ext.balance(&self.address) < value || self.ext.depth() >= self.ext.schedule().max_depth { + unsafe { + *io_gas = (gas + call_gas).low_u64(); + return false; + } + } + + match self.ext.call(&call_gas, + &receive_address, + &value, + unsafe { slice::from_raw_parts(in_beg, in_size as usize) }, + &code_address, + unsafe { slice::from_raw_parts_mut(out_beg, out_size as usize) }) { + evm::MessageCallResult::Success(gas_left) => unsafe { + *io_gas = (gas + gas_left).low_u64(); + true + }, + evm::MessageCallResult::Failed => unsafe { + *io_gas = gas.low_u64(); + false } } } @@ -302,35 +280,41 @@ impl<'a> evmjit::Ext for ExtAdapter<'a> { pub struct JitEvm; impl evm::Evm for JitEvm { - fn exec(&self, params: &ActionParams, ext: &mut evm::Ext) -> evm::Result { - let mut optional_err = None; + fn exec(&self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result { // Dirty hack. This is unsafe, but we interact with ffi, so it's justified. - let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, &mut optional_err)) }; + let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, params.address.clone())) }; let mut ext_handle = evmjit::ExtHandle::new(ext_adapter); - let mut data = RuntimeData::new(); - data.gas = params.gas; - data.gas_price = params.gas_price; - data.call_data = params.data.clone().unwrap_or(vec![]); - data.address = params.address.clone(); - data.caller = params.sender.clone(); - data.origin = params.origin.clone(); - data.call_value = params.value; - data.code = params.code.clone().unwrap_or(vec![]); + assert!(params.gas <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63"); + assert!(params.gas_price <= U256::from(i64::max_value() as u64), "evmjit max gas is 2 ^ 63"); - data.author = ext.env_info().author.clone(); - data.difficulty = ext.env_info().difficulty; - data.gas_limit = ext.env_info().gas_limit; + let call_data = params.data.unwrap_or(vec![]); + let code = params.code.unwrap_or(vec![]); + + let mut data = evmjit::RuntimeDataHandle::new(); + data.gas = params.gas.low_u64() as i64; + data.gas_price = params.gas_price.low_u64() as i64; + data.call_data = call_data.as_ptr(); + data.call_data_size = call_data.len() as u64; + mem::forget(call_data); + data.code = code.as_ptr(); + data.code_size = code.len() as u64; + data.code_hash = code.sha3().into_jit(); + mem::forget(code); + data.address = params.address.into_jit(); + data.caller = params.sender.into_jit(); + data.origin = params.origin.into_jit(); + data.call_value = params.value.into_jit(); + + data.author = ext.env_info().author.clone().into_jit(); + data.difficulty = ext.env_info().difficulty.into_jit(); + data.gas_limit = ext.env_info().gas_limit.into_jit(); data.number = ext.env_info().number; - data.timestamp = ext.env_info().timestamp; - - let mut context = unsafe { evmjit::ContextHandle::new(data.into_jit(), &mut ext_handle) }; + // don't really know why jit timestamp is int.. + data.timestamp = ext.env_info().timestamp as i64; + + let mut context = unsafe { evmjit::ContextHandle::new(data, &mut ext_handle) }; let res = context.exec(); - // check in adapter if execution of children contracts failed. - if let Some(err) = optional_err { - return Err(err); - } - match res { evmjit::ReturnCode::Stop => Ok(U256::from(context.gas_left())), evmjit::ReturnCode::Return => ext.ret(&U256::from(context.gas_left()), context.output_data()), diff --git a/src/evm/mod.rs b/src/evm/mod.rs index 9a4c090a0..2ed9a1146 100644 --- a/src/evm/mod.rs +++ b/src/evm/mod.rs @@ -14,7 +14,7 @@ mod jit; mod tests; pub use self::evm::{Evm, Error, Result}; -pub use self::ext::{Ext}; +pub use self::ext::{Ext, ContractCreateResult, MessageCallResult}; pub use self::factory::Factory; pub use self::schedule::Schedule; pub use self::factory::VMType; diff --git a/src/evm/tests.rs b/src/evm/tests.rs index cf02d5efa..8e1b5eff4 100644 --- a/src/evm/tests.rs +++ b/src/evm/tests.rs @@ -1,6 +1,6 @@ use common::*; use evm; -use evm::{Ext, Schedule, Factory, VMType}; +use evm::{Ext, Schedule, Factory, VMType, ContractCreateResult, MessageCallResult}; struct FakeLogEntry { topics: Vec, @@ -39,10 +39,14 @@ impl Ext for FakeExt { self.store.get(key).unwrap_or(&H256::new()).clone() } - fn set_storage_at(&mut self, key: H256, value: H256) { + fn set_storage(&mut self, key: H256, value: H256) { self.store.insert(key, value); } + fn exists(&self, _address: &Address) -> bool { + unimplemented!(); + } + fn balance(&self, _address: &Address) -> U256 { unimplemented!(); } @@ -51,18 +55,17 @@ impl Ext for FakeExt { self.blockhashes.get(number).unwrap_or(&H256::new()).clone() } - fn create(&mut self, _gas: &U256, _value: &U256, _code: &[u8]) -> (U256, Option
) { + fn create(&mut self, _gas: &U256, _value: &U256, _code: &[u8]) -> ContractCreateResult { unimplemented!(); } fn call(&mut self, _gas: &U256, - _call_gas: &U256, - _receive_address: &Address, + _address: &Address, _value: &U256, _data: &[u8], _code_address: &Address, - _output: &mut [u8]) -> result::Result<(U256, bool), evm::Error> { + _output: &mut [u8]) -> MessageCallResult { unimplemented!(); } @@ -92,10 +95,17 @@ impl Ext for FakeExt { fn env_info(&self) -> &EnvInfo { &self.info } + + fn depth(&self) -> usize { + unimplemented!(); + } + + fn inc_sstore_clears(&mut self) { + unimplemented!(); + } } #[test] - fn test_stack_underflow() { let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); let code = "01600055".from_hex().unwrap(); @@ -108,7 +118,7 @@ fn test_stack_underflow() { let err = { let vm : Box = Box::new(super::interpreter::Interpreter); - vm.exec(¶ms, &mut ext).unwrap_err() + vm.exec(params, &mut ext).unwrap_err() }; match err { @@ -135,7 +145,7 @@ fn test_add(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_988)); @@ -155,7 +165,7 @@ fn test_sha3(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_961)); @@ -175,7 +185,7 @@ fn test_address(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -197,7 +207,7 @@ fn test_origin(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -219,7 +229,7 @@ fn test_sender(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -254,7 +264,7 @@ fn test_extcodecopy(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_935)); @@ -274,7 +284,7 @@ fn test_log_empty(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(99_619)); @@ -306,7 +316,7 @@ fn test_log_sender(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(98_974)); @@ -331,7 +341,7 @@ fn test_blockhash(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_974)); @@ -353,7 +363,7 @@ fn test_calldataload(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_991)); @@ -374,7 +384,7 @@ fn test_author(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -394,7 +404,7 @@ fn test_timestamp(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -414,7 +424,7 @@ fn test_number(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -434,7 +444,7 @@ fn test_difficulty(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); @@ -454,7 +464,7 @@ fn test_gas_limit(factory: super::Factory) { let gas_left = { let vm = factory.create(); - vm.exec(¶ms, &mut ext).unwrap() + vm.exec(params, &mut ext).unwrap() }; assert_eq!(gas_left, U256::from(79_995)); diff --git a/src/executive.rs b/src/executive.rs index 47a9b0f3e..2a26dd3f0 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -75,8 +75,8 @@ impl<'a> Executive<'a> { } /// Creates `Externalities` from `Executive`. - pub fn to_externalities<'_>(&'_ mut self, params: &'_ ActionParams, substate: &'_ mut Substate, output: OutputPolicy<'_>) -> Externalities { - Externalities::new(self.state, self.info, self.engine, self.depth, params, substate, output) + pub fn to_externalities<'_>(&'_ mut self, origin_info: OriginInfo, substate: &'_ mut Substate, output: OutputPolicy<'_>) -> Externalities { + Externalities::new(self.state, self.info, self.engine, self.depth, origin_info, substate, output) } /// This funtion should be used to execute transaction. @@ -137,7 +137,7 @@ impl<'a> Executive<'a> { code: Some(t.data.clone()), data: None, }; - self.create(¶ms, &mut substate) + self.create(params, &mut substate) }, &Action::Call(ref address) => { let params = ActionParams { @@ -153,7 +153,7 @@ impl<'a> Executive<'a> { }; // TODO: move output upstream let mut out = vec![]; - self.call(¶ms, &mut substate, BytesRef::Flexible(&mut out)) + self.call(params, &mut substate, BytesRef::Flexible(&mut out)) } }; @@ -165,7 +165,7 @@ impl<'a> Executive<'a> { /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// Modifies the substate and the output. /// Returns either gas_left or `evm::Error`. - pub fn call(&mut self, params: &ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result { + pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result { // backup used in case of running out of gas let backup = self.state.clone(); @@ -198,11 +198,11 @@ impl<'a> Executive<'a> { let mut unconfirmed_substate = Substate::new(); let res = { - let mut ext = self.to_externalities(params, &mut unconfirmed_substate, OutputPolicy::Return(output)); - self.engine.vm_factory().create().exec(¶ms, &mut ext) + let mut ext = self.to_externalities(OriginInfo::from(¶ms), &mut unconfirmed_substate, OutputPolicy::Return(output)); + self.engine.vm_factory().create().exec(params, &mut ext) }; - trace!("exec: sstore-clears={}\n", unconfirmed_substate.refunds_count); + trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count); trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate); self.enact_result(&res, substate, unconfirmed_substate, backup); trace!("exec: new substate={:?}\n", substate); @@ -216,7 +216,7 @@ impl<'a> Executive<'a> { /// Creates contract with given contract params. /// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides). /// Modifies the substate. - pub fn create(&mut self, params: &ActionParams, substate: &mut Substate) -> evm::Result { + pub fn create(&mut self, params: ActionParams, substate: &mut Substate) -> evm::Result { // backup used in case of running out of gas let backup = self.state.clone(); @@ -230,8 +230,8 @@ impl<'a> Executive<'a> { self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value); let res = { - let mut ext = self.to_externalities(params, &mut unconfirmed_substate, OutputPolicy::InitContract); - self.engine.vm_factory().create().exec(¶ms, &mut ext) + let mut ext = self.to_externalities(OriginInfo::from(¶ms), &mut unconfirmed_substate, OutputPolicy::InitContract); + self.engine.vm_factory().create().exec(params, &mut ext) }; self.enact_result(&res, substate, unconfirmed_substate, backup); res @@ -242,7 +242,7 @@ impl<'a> Executive<'a> { let schedule = self.engine.schedule(self.info); // refunds from SSTORE nonzero -> zero - let sstore_refunds = U256::from(schedule.sstore_refund_gas) * substate.refunds_count; + let sstore_refunds = U256::from(schedule.sstore_refund_gas) * substate.sstore_clears_count; // refunds from contract suicides let suicide_refunds = U256::from(schedule.suicide_refund_gas) * U256::from(substate.suicides.len()); let refunds_bound = sstore_refunds + suicide_refunds; @@ -381,7 +381,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(¶ms, &mut substate).unwrap() + ex.create(params, &mut substate).unwrap() }; assert_eq!(gas_left, U256::from(79_975)); @@ -439,7 +439,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(¶ms, &mut substate).unwrap() + ex.create(params, &mut substate).unwrap() }; assert_eq!(gas_left, U256::from(62_976)); @@ -492,7 +492,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(¶ms, &mut substate).unwrap() + ex.create(params, &mut substate).unwrap() }; assert_eq!(gas_left, U256::from(62_976)); @@ -543,7 +543,7 @@ mod tests { { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(¶ms, &mut substate).unwrap(); + ex.create(params, &mut substate).unwrap(); } assert_eq!(substate.contracts_created.len(), 1); @@ -602,7 +602,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.call(¶ms, &mut substate, BytesRef::Fixed(&mut [])).unwrap() + ex.call(params, &mut substate, BytesRef::Fixed(&mut [])).unwrap() }; assert_eq!(gas_left, U256::from(73_237)); @@ -645,7 +645,7 @@ mod tests { let gas_left = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.call(¶ms, &mut substate, BytesRef::Fixed(&mut [])).unwrap() + ex.call(params, &mut substate, BytesRef::Fixed(&mut [])).unwrap() }; assert_eq!(gas_left, U256::from(59_870)); @@ -804,7 +804,7 @@ mod tests { let result = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.create(¶ms, &mut substate) + ex.create(params, &mut substate) }; match result { diff --git a/src/externalities.rs b/src/externalities.rs index c6ab2ceed..8b16cc72b 100644 --- a/src/externalities.rs +++ b/src/externalities.rs @@ -3,7 +3,7 @@ use common::*; use state::*; use engine::*; use executive::*; -use evm::{self, Schedule, Ext}; +use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult}; use substate::*; /// Policy for handling output data on `RETURN` opcode. @@ -15,23 +15,31 @@ pub enum OutputPolicy<'a> { InitContract } +/// Transaction properties that externalities need to know about. +pub struct OriginInfo { + address: Address, + origin: Address, + gas_price: U256 +} + +impl OriginInfo { + /// Populates origin info from action params. + pub fn from(params: &ActionParams) -> Self { + OriginInfo { + address: params.address.clone(), + origin: params.origin.clone(), + gas_price: params.gas_price.clone() + } + } +} + /// Implementation of evm Externalities. pub struct Externalities<'a> { - - #[cfg(test)] - pub state: &'a mut State, - #[cfg(not(test))] state: &'a mut State, - - info: &'a EnvInfo, + env_info: &'a EnvInfo, engine: &'a Engine, depth: usize, - - #[cfg(test)] - pub params: &'a ActionParams, - #[cfg(not(test))] - params: &'a ActionParams, - + origin_info: OriginInfo, substate: &'a mut Substate, schedule: Schedule, output: OutputPolicy<'a> @@ -40,20 +48,20 @@ pub struct Externalities<'a> { impl<'a> Externalities<'a> { /// Basic `Externalities` constructor. pub fn new(state: &'a mut State, - info: &'a EnvInfo, + env_info: &'a EnvInfo, engine: &'a Engine, depth: usize, - params: &'a ActionParams, + origin_info: OriginInfo, substate: &'a mut Substate, output: OutputPolicy<'a>) -> Self { Externalities { state: state, - info: info, + env_info: env_info, engine: engine, depth: depth, - params: params, + origin_info: origin_info, substate: substate, - schedule: engine.schedule(info), + schedule: engine.schedule(env_info), output: output } } @@ -61,19 +69,15 @@ impl<'a> Externalities<'a> { impl<'a> Ext for Externalities<'a> { fn storage_at(&self, key: &H256) -> H256 { - trace!("ext: storage_at({}, {}) == {}\n", self.params.address, key, U256::from(self.state.storage_at(&self.params.address, key).as_slice())); - self.state.storage_at(&self.params.address, key) + self.state.storage_at(&self.origin_info.address, key) } - fn set_storage_at(&mut self, key: H256, value: H256) { - let old = self.state.storage_at(&self.params.address, &key); - // if SSTORE nonzero -> zero, increment refund count - if value.is_zero() && !old.is_zero() { - trace!("ext: additional refund. {} -> {}\n", self.substate.refunds_count, self.substate.refunds_count + x!(1)); - self.substate.refunds_count = self.substate.refunds_count + U256::one(); - } - trace!("ext: set_storage_at({}, {}): {} -> {}\n", self.params.address, key, U256::from(old.as_slice()), U256::from(value.as_slice())); - self.state.set_storage(&self.params.address, key, value) + fn set_storage(&mut self, key: H256, value: H256) { + self.state.set_storage(&self.origin_info.address, key, value) + } + + fn exists(&self, address: &Address) -> bool { + self.state.exists(address) } fn balance(&self, address: &Address) -> U256 { @@ -81,109 +85,75 @@ impl<'a> Ext for Externalities<'a> { } fn blockhash(&self, number: &U256) -> H256 { - match *number < U256::from(self.info.number) && number.low_u64() >= cmp::max(256, self.info.number) - 256 { + match *number < U256::from(self.env_info.number) && number.low_u64() >= cmp::max(256, self.env_info.number) - 256 { true => { - let index = self.info.number - number.low_u64() - 1; - let r = self.info.last_hashes[index as usize].clone(); - trace!("ext: blockhash({}) -> {} self.info.number={}\n", number, r, self.info.number); + let index = self.env_info.number - number.low_u64() - 1; + let r = self.env_info.last_hashes[index as usize].clone(); + trace!("ext: blockhash({}) -> {} self.env_info.number={}\n", number, r, self.env_info.number); r }, false => { - trace!("ext: blockhash({}) -> null self.info.number={}\n", number, self.info.number); + trace!("ext: blockhash({}) -> null self.env_info.number={}\n", number, self.env_info.number); H256::from(&U256::zero()) }, } } - fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> (U256, Option
) { - // if balance is insufficient or we are to deep, return - if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth { - return (*gas, None); - } - + fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { // create new contract address - let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address)); + let address = contract_address(&self.origin_info.address, &self.state.nonce(&self.origin_info.address)); // prepare the params let params = ActionParams { code_address: address.clone(), address: address.clone(), - sender: self.params.address.clone(), - origin: self.params.origin.clone(), + sender: self.origin_info.address.clone(), + origin: self.origin_info.origin.clone(), gas: *gas, - gas_price: self.params.gas_price.clone(), + gas_price: self.origin_info.gas_price.clone(), value: value.clone(), code: Some(code.to_vec()), data: None, }; - self.state.inc_nonce(&self.params.address); - let mut ex = Executive::from_parent(self.state, self.info, self.engine, self.depth); - match ex.create(¶ms, self.substate) { - Ok(gas_left) => (gas_left, Some(address)), - _ => (U256::zero(), None) + self.state.inc_nonce(&self.origin_info.address); + let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); + + // TODO: handle internal error separately + match ex.create(params, self.substate) { + Ok(gas_left) => { + self.substate.contracts_created.push(address.clone()); + ContractCreateResult::Created(address, gas_left) + }, + _ => ContractCreateResult::Failed } } fn call(&mut self, gas: &U256, - call_gas: &U256, - receive_address: &Address, + address: &Address, value: &U256, data: &[u8], code_address: &Address, - output: &mut [u8]) -> Result<(U256, bool), evm::Error> { - - let mut gas_cost = *call_gas; - let mut call_gas = *call_gas; - - let is_call = receive_address == code_address; - if is_call && !self.state.exists(&code_address) { - gas_cost = gas_cost + U256::from(self.schedule.call_new_account_gas); - } - - if *value > U256::zero() { - assert!(self.schedule.call_value_transfer_gas > self.schedule.call_stipend, "overflow possible"); - gas_cost = gas_cost + U256::from(self.schedule.call_value_transfer_gas); - call_gas = call_gas + U256::from(self.schedule.call_stipend); - } - - debug!("Externalities::call(gas={}, call_gas={}, recv={}, value={}, data={}, code={})\n", gas, call_gas, receive_address, value, data.pretty(), code_address); - - if gas_cost > *gas { - debug!("Externalities::call: OutOfGas gas_cost={}, gas={}", gas_cost, gas); - return Err(evm::Error::OutOfGas); - } - - let gas = *gas - gas_cost; - - // if balance is insufficient or we are too deep, return - if self.state.balance(&self.params.address) < *value || self.depth >= self.schedule.max_depth { - debug!("Externalities::call: OutOfCash bal({})={}, value={}", self.params.address, self.state.balance(&self.params.address), value); - return Ok((gas + call_gas, false)); - } + output: &mut [u8]) -> MessageCallResult { let params = ActionParams { code_address: code_address.clone(), - address: receive_address.clone(), - sender: self.params.address.clone(), - origin: self.params.origin.clone(), - gas: call_gas, - gas_price: self.params.gas_price.clone(), + address: address.clone(), + sender: self.origin_info.address.clone(), + origin: self.origin_info.origin.clone(), + gas: *gas, + gas_price: self.origin_info.gas_price.clone(), value: value.clone(), code: self.state.code(code_address), data: Some(data.to_vec()), }; + let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth); - trace!("Externalities::call: BEFORE: bal({})={}, bal({})={}\n", params.sender, self.state.balance(¶ms.sender), params.address, self.state.balance(¶ms.address)); - trace!("Externalities::call: CALLING: params={:?}\n", params); - let r = Executive::from_parent(self.state, self.info, self.engine, self.depth).call(¶ms, self.substate, BytesRef::Fixed(output)); - trace!("Externalities::call: AFTER: bal({})={}, bal({})={}\n", params.sender, self.state.balance(¶ms.sender), params.address, self.state.balance(¶ms.address)); - - match r { - Ok(gas_left) => Ok((gas + gas_left, true)), - _ => Ok((gas, false)) + match ex.call(params, self.substate, BytesRef::Fixed(output)) { + Ok(gas_left) => MessageCallResult::Success(gas_left), + _ => MessageCallResult::Failed } } @@ -219,21 +189,20 @@ impl<'a> Ext for Externalities<'a> { ptr::copy(data.as_ptr(), code.as_mut_ptr(), data.len()); code.set_len(data.len()); } - let address = &self.params.address; + let address = &self.origin_info.address; self.state.init_code(address, code); - self.substate.contracts_created.push(address.clone()); Ok(*gas - return_cost) } } } fn log(&mut self, topics: Vec, data: &[u8]) { - let address = self.params.address.clone(); + let address = self.origin_info.address.clone(); self.substate.logs.push(LogEntry::new(address, topics, data.to_vec())); } fn suicide(&mut self, refund_address: &Address) { - let address = self.params.address.clone(); + let address = self.origin_info.address.clone(); let balance = self.balance(&address); self.state.transfer_balance(&address, refund_address, &balance); self.substate.suicides.insert(address); @@ -244,6 +213,14 @@ impl<'a> Ext for Externalities<'a> { } fn env_info(&self) -> &EnvInfo { - &self.info + &self.env_info + } + + fn depth(&self) -> usize { + self.depth + } + + fn inc_sstore_clears(&mut self) { + self.substate.sstore_clears_count = self.substate.sstore_clears_count + U256::one(); } } diff --git a/src/substate.rs b/src/substate.rs index b227afacc..9a1d6741e 100644 --- a/src/substate.rs +++ b/src/substate.rs @@ -8,8 +8,8 @@ pub struct Substate { pub suicides: HashSet
, /// Any logs. pub logs: Vec, - /// Refund counter of SSTORE nonzero->zero. - pub refunds_count: U256, + /// Refund counter of SSTORE nonzero -> zero. + pub sstore_clears_count: U256, /// Created contracts. pub contracts_created: Vec
} @@ -20,7 +20,7 @@ impl Substate { Substate { suicides: HashSet::new(), logs: vec![], - refunds_count: U256::zero(), + sstore_clears_count: U256::zero(), contracts_created: vec![] } } @@ -28,7 +28,7 @@ impl Substate { pub fn accrue(&mut self, s: Substate) { self.suicides.extend(s.suicides.into_iter()); self.logs.extend(s.logs.into_iter()); - self.refunds_count = self.refunds_count + s.refunds_count; + self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; self.contracts_created.extend(s.contracts_created.into_iter()); } } diff --git a/src/tests/executive.rs b/src/tests/executive.rs index b251eb0d2..fe428e199 100644 --- a/src/tests/executive.rs +++ b/src/tests/executive.rs @@ -4,7 +4,7 @@ use executive::*; use spec::*; use engine::*; use evm; -use evm::{Schedule, Ext, Factory, VMType}; +use evm::{Schedule, Ext, Factory, VMType, ContractCreateResult, MessageCallResult}; use ethereum; use externalities::*; use substate::*; @@ -39,7 +39,7 @@ impl Engine for TestEngine { struct CallCreate { data: Bytes, destination: Option
, - _gas_limit: U256, + gas_limit: U256, value: U256 } @@ -47,13 +47,22 @@ struct CallCreate { /// Stores callcreates. struct TestExt<'a> { ext: Externalities<'a>, - callcreates: Vec + callcreates: Vec, + contract_address: Address } impl<'a> TestExt<'a> { - fn new(ext: Externalities<'a>) -> TestExt { + fn new(state: &'a mut State, + info: &'a EnvInfo, + engine: &'a Engine, + depth: usize, + origin_info: OriginInfo, + substate: &'a mut Substate, + output: OutputPolicy<'a>, + address: Address) -> Self { TestExt { - ext: ext, + contract_address: contract_address(&address, &state.nonce(&address)), + ext: Externalities::new(state, info, engine, depth, origin_info, substate, output), callcreates: vec![] } } @@ -64,8 +73,12 @@ impl<'a> Ext for TestExt<'a> { self.ext.storage_at(key) } - fn set_storage_at(&mut self, key: H256, value: H256) { - self.ext.set_storage_at(key, value) + fn set_storage(&mut self, key: H256, value: H256) { + self.ext.set_storage(key, value) + } + + fn exists(&self, address: &Address) -> bool { + self.ext.exists(address) } fn balance(&self, address: &Address) -> U256 { @@ -76,60 +89,30 @@ impl<'a> Ext for TestExt<'a> { self.ext.blockhash(number) } - fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> (U256, Option
) { - // in call and create we need to check if we exited with insufficient balance or max limit reached. - // in case of reaching max depth, we should store callcreates. Otherwise, ignore. - let res = self.ext.create(gas, value, code); - let ext = &self.ext; - match res { - // just record call create - (gas_left, Some(address)) => { - self.callcreates.push(CallCreate { - data: code.to_vec(), - destination: Some(address.clone()), - _gas_limit: *gas, - value: *value - }); - (gas_left, Some(address)) - }, - // creation failed only due to reaching max_depth - (gas_left, None) if ext.state.balance(&ext.params.address) >= *value => { - self.callcreates.push(CallCreate { - data: code.to_vec(), - // callcreate test does not need an address - destination: None, - _gas_limit: *gas, - value: *value - }); - let address = contract_address(&ext.params.address, &ext.state.nonce(&ext.params.address)); - (gas_left, Some(address)) - }, - other => other - } + fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> ContractCreateResult { + self.callcreates.push(CallCreate { + data: code.to_vec(), + destination: None, + gas_limit: *gas, + value: *value + }); + ContractCreateResult::Created(self.contract_address.clone(), *gas) } fn call(&mut self, gas: &U256, - call_gas: &U256, receive_address: &Address, value: &U256, data: &[u8], - code_address: &Address, - output: &mut [u8]) -> Result<(U256, bool), evm::Error> { - let res = self.ext.call(gas, call_gas, receive_address, value, data, code_address, output); - let ext = &self.ext; - if let &Ok((gas_left, _)) = &res { - if ext.state.balance(&ext.params.address) >= *value { - self.callcreates.push(CallCreate { - data: data.to_vec(), - destination: Some(receive_address.clone()), - _gas_limit: *call_gas, - value: *value - }); - return Ok((gas_left, true)) - } - } - res + _code_address: &Address, + _output: &mut [u8]) -> MessageCallResult { + self.callcreates.push(CallCreate { + data: data.to_vec(), + destination: Some(receive_address.clone()), + gas_limit: *gas, + value: *value + }); + MessageCallResult::Success(*gas) } fn extcode(&self, address: &Address) -> Bytes { @@ -155,6 +138,14 @@ impl<'a> Ext for TestExt<'a> { fn env_info(&self) -> &EnvInfo { self.ext.env_info() } + + fn depth(&self) -> usize { + 0 + } + + fn inc_sstore_clears(&mut self) { + self.ext.inc_sstore_clears() + } } fn do_json_test(json_data: &[u8]) -> Vec { @@ -206,7 +197,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { info.timestamp = xjson!(&env["currentTimestamp"]); }); - let engine = TestEngine::new(0, vm.clone()); + let engine = TestEngine::new(1, vm.clone()); // params let mut params = ActionParams::new(); @@ -229,11 +220,17 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { // execute let (res, callcreates) = { - let ex = Externalities::new(&mut state, &info, &engine, 0, ¶ms, &mut substate, OutputPolicy::Return(BytesRef::Flexible(&mut output))); - let mut test_ext = TestExt::new(ex); + let mut ex = TestExt::new(&mut state, + &info, + &engine, + 0, + OriginInfo::from(¶ms), + &mut substate, + OutputPolicy::Return(BytesRef::Flexible(&mut output)), + params.address.clone()); let evm = engine.vm_factory().create(); - let res = evm.exec(¶ms, &mut test_ext); - (res, test_ext.callcreates) + let res = evm.exec(params, &mut ex); + (res, ex.callcreates) }; // then validate @@ -262,11 +259,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec { fail_unless(callcreate.data == Bytes::from_json(&expected["data"]), "callcreates data is incorrect"); fail_unless(callcreate.destination == xjson!(&expected["destination"]), "callcreates destination is incorrect"); fail_unless(callcreate.value == xjson!(&expected["value"]), "callcreates value is incorrect"); - - // TODO: call_gas is calculated in externalities and is not exposed to TestExt. - // maybe move it to it's own function to simplify calculation? - //println!("name: {:?}, callcreate {:?}, expected: {:?}", name, callcreate.gas_limit, U256::from(&expected["gasLimit"])); - //fail_unless(callcreate.gas_limit == U256::from(&expected["gasLimit"]), "callcreates gas_limit is incorrect"); + fail_unless(callcreate.gas_limit == xjson!(&expected["gasLimit"]), "callcreates gas_limit is incorrect"); } } } diff --git a/src/tests/state.rs b/src/tests/state.rs index d4a921add..d0da24128 100644 --- a/src/tests/state.rs +++ b/src/tests/state.rs @@ -4,15 +4,26 @@ use pod_state::*; use state_diff::*; use ethereum; +const HOMESTEAD_BLOCK : u64 = 0x0dbba0; + fn do_json_test(json_data: &[u8]) -> Vec { let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid"); let mut failed = Vec::new(); - let engine = ethereum::new_frontier_test().to_engine().unwrap(); + let engine = |block_number: u64| { + if block_number >= HOMESTEAD_BLOCK { + ethereum::new_homestead_test().to_engine().unwrap() + } else { + ethereum::new_frontier_test().to_engine().unwrap() + } + }; flush(format!("\n")); for (name, test) in json.as_object().unwrap() { + if name != "createNameRegistratorPerTxsAt" { + continue; + } let mut fail = false; { let mut fail_unless = |cond: bool| if !cond && !fail { @@ -24,8 +35,9 @@ fn do_json_test(json_data: &[u8]) -> Vec { flush(format!(" - {}...", name)); - let t = Transaction::from_json(&test["transaction"]); let env = EnvInfo::from_json(&test["env"]); + let engine = engine(env.number); + let t = Transaction::from_json(&test["transaction"]); let _out = Bytes::from_json(&test["out"]); let post_state_root = xjson!(&test["postStateRoot"]); let pre = PodState::from_json(&test["pre"]);