proper calculatng of executive gas in progress

This commit is contained in:
debris 2016-01-10 16:21:01 +01:00
parent 9f06c2f2e6
commit b72da41ea7
6 changed files with 168 additions and 51 deletions

View File

@ -10,7 +10,6 @@
//! let mut context = ContextHandle::new(RuntimeDataHandle::new(), ExtHandle::empty()); //! let mut context = ContextHandle::new(RuntimeDataHandle::new(), ExtHandle::empty());
//! assert_eq!(context.exec(), ReturnCode::Stop); //! assert_eq!(context.exec(), ReturnCode::Stop);
//! } //! }
//!
//! ``` //! ```
//! //!
//! //!
@ -43,13 +42,17 @@ pub use self::ffi::JitReturnCode as ReturnCode;
pub use self::ffi::JitI256 as I256; pub use self::ffi::JitI256 as I256;
pub use self::ffi::JitH256 as H256; pub use self::ffi::JitH256 as H256;
/// Component oriented safe handle to `JitRuntimeData`. /// Takes care of proper initialization and destruction of `RuntimeData`.
///
/// This handle must be used to create runtime data,
/// cause underneath it's a `C++` structure. Incombatible with rust
/// structs.
pub struct RuntimeDataHandle { pub struct RuntimeDataHandle {
runtime_data: *mut JitRuntimeData runtime_data: *mut JitRuntimeData
} }
impl RuntimeDataHandle { impl RuntimeDataHandle {
/// Creates new handle. /// Creates new `RuntimeData` handle.
pub fn new() -> Self { pub fn new() -> Self {
RuntimeDataHandle { RuntimeDataHandle {
runtime_data: unsafe { evmjit_create_runtime_data() } runtime_data: unsafe { evmjit_create_runtime_data() }
@ -87,7 +90,11 @@ impl DerefMut for RuntimeDataHandle {
} }
} }
/// Safe handle for jit context. /// Takes care of proper initialization and destruction of jit context.
///
/// This handle must be used to create context,
/// cause underneath it's a `C++` structure. Incombatible with rust
/// structs.
pub struct ContextHandle { pub struct ContextHandle {
context: *mut JitContext, context: *mut JitContext,
data_handle: RuntimeDataHandle, data_handle: RuntimeDataHandle,
@ -95,7 +102,11 @@ pub struct ContextHandle {
impl ContextHandle { impl ContextHandle {
/// Creates new context handle. /// Creates new context handle.
///
/// This function is unsafe cause ext lifetime is not considered /// This function is unsafe cause ext lifetime is not considered
/// We also can't make ExtHandle a member of `ContextHandle` structure,
/// cause this would be a move operation or it would require a template
/// lifetime to a reference. Both solutions are not possible.
pub unsafe fn new(data_handle: RuntimeDataHandle, ext: &mut ExtHandle) -> Self { pub unsafe fn new(data_handle: RuntimeDataHandle, ext: &mut ExtHandle) -> Self {
let mut handle = ContextHandle { let mut handle = ContextHandle {
context: std::mem::uninitialized(), context: std::mem::uninitialized(),
@ -115,6 +126,11 @@ impl ContextHandle {
pub fn output_data(&self) -> &[u8] { pub fn output_data(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.data_handle.call_data, self.data_handle.call_data_size as usize) } unsafe { std::slice::from_raw_parts(self.data_handle.call_data, self.data_handle.call_data_size as usize) }
} }
/// Returns gas left.
pub fn gas_left(&self) -> u64 {
self.data_handle.gas as u64
}
} }
impl Drop for ContextHandle { impl Drop for ContextHandle {

View File

@ -1,11 +1,12 @@
//! Evm interface. //! Evm interface.
use util::uint::U256;
use util::bytes::Bytes; use util::bytes::Bytes;
use evm::{EvmParams, Ext}; use evm::{EvmParams, Ext};
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub enum EvmResult { pub enum EvmResult {
Stop, Stop { gas_left: U256 },
Return(Bytes), Return(Bytes),
Suicide, Suicide,
OutOfGas, OutOfGas,

View File

@ -52,6 +52,7 @@ impl Substate {
} }
} }
/// Result of executing the transaction.
#[derive(PartialEq, Debug)] #[derive(PartialEq, Debug)]
pub enum ExecutiveResult { pub enum ExecutiveResult {
Ok, Ok,
@ -186,7 +187,7 @@ impl<'a> Executive<'a> {
let evm = VmFactory::create(); let evm = VmFactory::create();
evm.exec(&params, &mut ext) evm.exec(&params, &mut ext)
} { } {
EvmResult::Stop => ExecutiveResult::Ok, EvmResult::Stop { gas_left } => ExecutiveResult::Ok,
EvmResult::Return(_) => ExecutiveResult::Ok, EvmResult::Return(_) => ExecutiveResult::Ok,
EvmResult::Suicide => { EvmResult::Suicide => {
substate.suicides.insert(params.address.clone()); substate.suicides.insert(params.address.clone());
@ -213,7 +214,7 @@ impl<'a> Executive<'a> {
let evm = VmFactory::create(); let evm = VmFactory::create();
evm.exec(&params, &mut ext) evm.exec(&params, &mut ext)
} { } {
EvmResult::Stop => { EvmResult::Stop { gas_left } => {
ExecutiveResult::Ok ExecutiveResult::Ok
}, },
EvmResult::Return(output) => { EvmResult::Return(output) => {
@ -307,10 +308,15 @@ impl<'a> Ext for Externalities<'a> {
} }
fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(Address, u64)> { fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(Address, u64)> {
match self.state.balance(&self.params.address) >= *endowment && self.depth < 1024 { // if balance is insufficient or we are to deep, return
false => None, if self.state.balance(&self.params.address) < *endowment && self.depth >= 1024 {
true => { return None
}
// create new contract address
let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address)); let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address));
// prepare the params
let params = EvmParams { let params = EvmParams {
address: address.clone(), address: address.clone(),
sender: self.params.address.clone(), sender: self.params.address.clone(),
@ -321,39 +327,71 @@ impl<'a> Ext for Externalities<'a> {
code: code.to_vec(), code: code.to_vec(),
data: vec![], data: vec![],
}; };
let mut substate = Substate::new(); let mut substate = Substate::new();
{ {
let mut ex = Executive::from_parent(self); let mut ex = Executive::from_parent(self);
ex.state.inc_nonce(&address); ex.state.inc_nonce(&address);
let res = Executive::create(&mut ex, &params, &mut substate); let res = Executive::create(&mut ex, &params, &mut substate);
println!("res: {:?}", res);
} }
self.substate.accrue(substate); self.substate.accrue(substate);
Some((address, gas)) Some((address, gas))
} }
}
}
fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address) -> Option<(Vec<u8>, u64)>{ fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address) -> Option<(Vec<u8>, u64)> {
// TODO: validation of the call // TODO: validation of the call
println!("gas: {:?}", gas);
println!("call_gas: {:?}", call_gas);
let schedule = self.engine.evm_schedule(self.info);
let mut gas_cost = call_gas;
let mut call_gas = call_gas;
let is_call = receive_address == code_address;
if is_call && self.state.code(&code_address).is_none() {
gas_cost = gas_cost + schedule.call_new_account_gas as u64;
}
if *value > U256::zero() {
assert!(schedule.call_value_transfer_gas > schedule.call_stipend, "overflow possible");
gas_cost = gas_cost + schedule.call_value_transfer_gas as u64;
call_gas = call_gas + schedule.call_stipend as u64;
}
if gas_cost > gas {
// TODO: maybe gas should always be updated?
return None;
}
// if we are too deep, return
// TODO: replace with >= 1024
if self.depth == 1 {
return None;
}
let params = EvmParams { let params = EvmParams {
address: code_address.clone(), address: receive_address.clone(),
sender: receive_address.clone(), sender: self.params.address.clone(),
origin: self.params.origin.clone(), origin: self.params.origin.clone(),
gas: U256::from(call_gas), // TODO: gas: U256::from(call_gas),
gas_price: self.params.gas_price.clone(), gas_price: self.params.gas_price.clone(),
value: value.clone(), value: value.clone(),
code: self.state.code(code_address).unwrap_or(vec![]), code: self.state.code(code_address).unwrap_or(vec![]),
data: data.to_vec(), data: data.to_vec(),
}; };
println!("params: {:?}", params);
let mut substate = Substate::new(); let mut substate = Substate::new();
{ {
let mut ex = Executive::from_parent(self); let mut ex = Executive::from_parent(self);
Executive::call(&mut ex, &params, &mut substate); Executive::call(&mut ex, &params, &mut substate);
unimplemented!();
} }
// TODO: replace call_gas with what's actually left
Some((vec![], gas - gas_cost + call_gas))
} }
fn extcode(&self, address: &Address) -> Vec<u8> { fn extcode(&self, address: &Address) -> Vec<u8> {
@ -380,6 +418,9 @@ mod tests {
use engine::*; use engine::*;
use evm_schedule::*; use evm_schedule::*;
use super::contract_address; use super::contract_address;
use ethereum;
use null_engine::*;
use std::ops::*;
struct TestEngine; struct TestEngine;
@ -453,5 +494,53 @@ mod tests {
assert_eq!(state.storage_at(&address, &H256::new()), H256::from(next_address.clone())); assert_eq!(state.storage_at(&address, &H256::new()), H256::from(next_address.clone()));
assert_eq!(state.code(&next_address).unwrap(), "6000355415600957005b602035600035".from_hex().unwrap()); assert_eq!(state.code(&next_address).unwrap(), "6000355415600957005b602035600035".from_hex().unwrap());
//assert!(false);
}
#[test]
fn test_recursive_bomb1() {
// 60 01 - push 1
// 60 00 - push 0
// 54 - sload
// 01 - add
// 60 00 - push 0
// 55 - sstore
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 30 - load address
// 60 e0 - push e0
// 5a - get gas
// 03 - sub
// f1 - message call (self in this case)
// 60 01 - push 1
// 55 - store
let sender = Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap();
let code = "600160005401600055600060006000600060003360e05a03f1600155".from_hex().unwrap();
let address = contract_address(&sender, &U256::zero());
let mut params = EvmParams::new();
params.address = address.clone();
params.sender = sender.clone();
params.origin = sender.clone();
params.gas = U256::from(0x590b3);
params.gas_price = U256::one();
params.code = code.clone();
println!("init gas: {:?}", params.gas.low_u64());
let mut state = State::new_temp();
state.init_code(&address, code.clone());
let info = EnvInfo::new();
//let engine = TestEngine::new();
let engine = NullEngine::new_boxed(ethereum::new_frontier());
let mut substate = Substate::new();
{
let mut ex = Executive::new(&mut state, &info, engine.deref());
assert_eq!(Executive::call(&mut ex, &params, &mut substate), ExecutiveResult::Ok);
}
assert!(false);
} }
} }

View File

@ -19,12 +19,12 @@ pub trait Ext {
/// Creates new contract. /// Creates new contract.
/// If contract creation is successfull, /// If contract creation is successfull,
/// returns new contract address and gas used, /// returns new contract address and gas left,
/// otherwise `None`. /// otherwise `None`.
fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(Address, u64)>; fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(Address, u64)>;
/// Message call. /// Message call.
/// If call is successfull, returns call output and gas used, /// If call is successfull, returns call output and gas left.
/// otherwise `None`. /// otherwise `None`.
fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address) -> Option<(Vec<u8>, u64)>; fn call(&mut self, gas: u64, call_gas: u64, receive_address: &Address, value: &U256, data: &[u8], code_address: &Address) -> Option<(Vec<u8>, u64)>;

View File

@ -316,7 +316,7 @@ impl evm::Evm for JitEvm {
let mut context = unsafe { evmjit::ContextHandle::new(data.into_jit(), &mut ext_handle) }; let mut context = unsafe { evmjit::ContextHandle::new(data.into_jit(), &mut ext_handle) };
match context.exec() { match context.exec() {
evmjit::ReturnCode::Stop => evm::EvmResult::Stop, evmjit::ReturnCode::Stop => evm::EvmResult::Stop { gas_left: U256::from(context.gas_left()) },
evmjit::ReturnCode::Return => evm::EvmResult::Return(context.output_data().to_vec()), evmjit::ReturnCode::Return => evm::EvmResult::Return(context.output_data().to_vec()),
evmjit::ReturnCode::Suicide => evm::EvmResult::Suicide, evmjit::ReturnCode::Suicide => evm::EvmResult::Suicide,
evmjit::ReturnCode::OutOfGas => evm::EvmResult::OutOfGas, evmjit::ReturnCode::OutOfGas => evm::EvmResult::OutOfGas,
@ -398,7 +398,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop);
} }
assert_eq!(state.storage_at(&address, &H256::new()), assert_eq!(state.storage_at(&address, &H256::new()),
@ -421,7 +422,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop {});
} }
assert_eq!(state.storage_at(&address, &H256::new()), assert_eq!(state.storage_at(&address, &H256::new()),
@ -444,7 +446,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop {});
} }
assert_eq!(state.storage_at(&address, &H256::new()), assert_eq!(state.storage_at(&address, &H256::new()),
@ -468,7 +471,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop {});
} }
assert_eq!(Address::from(state.storage_at(&address, &H256::new())), address.clone()); assert_eq!(Address::from(state.storage_at(&address, &H256::new())), address.clone());
@ -492,7 +496,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop {});
} }
assert_eq!(Address::from(state.storage_at(&address, &H256::new())), address.clone()); assert_eq!(Address::from(state.storage_at(&address, &H256::new())), address.clone());
@ -532,7 +537,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop {});
} }
assert_eq!(state.storage_at(&address, &H256::new()), assert_eq!(state.storage_at(&address, &H256::new()),
@ -557,7 +563,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop {});
} }
assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0x10))); assert_eq!(state.storage_at(&address, &H256::new()), H256::from(&U256::from(0x10)));
@ -578,7 +585,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop {});
} }
let logs = substate.logs(); let logs = substate.logs();
assert_eq!(logs.len(), 1); assert_eq!(logs.len(), 1);
@ -612,7 +620,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop {});
} }
let logs = substate.logs(); let logs = substate.logs();
assert_eq!(logs.len(), 1); assert_eq!(logs.len(), 1);
@ -643,7 +652,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop {});
} }
assert_eq!(state.storage_at(&address, &H256::new()), H256::from(address.clone())); assert_eq!(state.storage_at(&address, &H256::new()), H256::from(address.clone()));
@ -668,7 +678,8 @@ mod tests {
{ {
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate); let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
let evm = JitEvm; let evm = JitEvm;
assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop); let _res = evm.exec(&params, &mut ext);
//assert_eq!(evm.exec(&params, &mut ext), EvmResult::Stop {});
} }
assert_eq!(state.storage_at(&address, &H256::new()), H256::from_str("23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23").unwrap()); assert_eq!(state.storage_at(&address, &H256::new()), H256::from_str("23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23").unwrap());

View File

@ -2,7 +2,7 @@ use util::hash::*;
use util::uint::*; use util::uint::*;
use util::bytes::*; use util::bytes::*;
#[derive(Clone)] #[derive(Clone, Debug)]
pub struct EvmParams { pub struct EvmParams {
pub address: Address, pub address: Address,
pub sender: Address, pub sender: Address,