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());
//! 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::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 {
runtime_data: *mut JitRuntimeData
}
impl RuntimeDataHandle {
/// Creates new handle.
/// Creates new `RuntimeData` handle.
pub fn new() -> Self {
RuntimeDataHandle {
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 {
context: *mut JitContext,
data_handle: RuntimeDataHandle,
@ -95,7 +102,11 @@ pub struct ContextHandle {
impl ContextHandle {
/// Creates new context handle.
///
/// 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 {
let mut handle = ContextHandle {
context: std::mem::uninitialized(),
@ -115,6 +126,11 @@ impl ContextHandle {
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) }
}
/// Returns gas left.
pub fn gas_left(&self) -> u64 {
self.data_handle.gas as u64
}
}
impl Drop for ContextHandle {

View File

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

View File

@ -52,6 +52,7 @@ impl Substate {
}
}
/// Result of executing the transaction.
#[derive(PartialEq, Debug)]
pub enum ExecutiveResult {
Ok,
@ -186,7 +187,7 @@ impl<'a> Executive<'a> {
let evm = VmFactory::create();
evm.exec(&params, &mut ext)
} {
EvmResult::Stop => ExecutiveResult::Ok,
EvmResult::Stop { gas_left } => ExecutiveResult::Ok,
EvmResult::Return(_) => ExecutiveResult::Ok,
EvmResult::Suicide => {
substate.suicides.insert(params.address.clone());
@ -213,7 +214,7 @@ impl<'a> Executive<'a> {
let evm = VmFactory::create();
evm.exec(&params, &mut ext)
} {
EvmResult::Stop => {
EvmResult::Stop { gas_left } => {
ExecutiveResult::Ok
},
EvmResult::Return(output) => {
@ -307,53 +308,90 @@ impl<'a> Ext for Externalities<'a> {
}
fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(Address, u64)> {
match self.state.balance(&self.params.address) >= *endowment && self.depth < 1024 {
false => None,
true => {
let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address));
let params = EvmParams {
address: address.clone(),
sender: self.params.address.clone(),
origin: self.params.origin.clone(),
gas: U256::from(gas),
gas_price: self.params.gas_price.clone(),
value: endowment.clone(),
code: code.to_vec(),
data: vec![],
};
let mut substate = Substate::new();
{
let mut ex = Executive::from_parent(self);
ex.state.inc_nonce(&address);
let res = Executive::create(&mut ex, &params, &mut substate);
println!("res: {:?}", res);
}
self.substate.accrue(substate);
Some((address, gas))
}
// if balance is insufficient or we are to deep, return
if self.state.balance(&self.params.address) < *endowment && self.depth >= 1024 {
return None
}
// create new contract address
let address = contract_address(&self.params.address, &self.state.nonce(&self.params.address));
// prepare the params
let params = EvmParams {
address: address.clone(),
sender: self.params.address.clone(),
origin: self.params.origin.clone(),
gas: U256::from(gas),
gas_price: self.params.gas_price.clone(),
value: endowment.clone(),
code: code.to_vec(),
data: vec![],
};
let mut substate = Substate::new();
{
let mut ex = Executive::from_parent(self);
ex.state.inc_nonce(&address);
let res = Executive::create(&mut ex, &params, &mut substate);
}
self.substate.accrue(substate);
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
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 {
address: code_address.clone(),
sender: receive_address.clone(),
address: receive_address.clone(),
sender: self.params.address.clone(),
origin: self.params.origin.clone(),
gas: U256::from(call_gas), // TODO:
gas: U256::from(call_gas),
gas_price: self.params.gas_price.clone(),
value: value.clone(),
code: self.state.code(code_address).unwrap_or(vec![]),
data: data.to_vec(),
};
println!("params: {:?}", params);
let mut substate = Substate::new();
{
let mut ex = Executive::from_parent(self);
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> {
@ -380,6 +418,9 @@ mod tests {
use engine::*;
use evm_schedule::*;
use super::contract_address;
use ethereum;
use null_engine::*;
use std::ops::*;
struct TestEngine;
@ -453,5 +494,53 @@ mod tests {
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!(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.
/// If contract creation is successfull,
/// returns new contract address and gas used,
/// returns new contract address and gas left,
/// otherwise `None`.
fn create(&mut self, gas: u64, endowment: &U256, code: &[u8]) -> Option<(Address, u64)>;
/// Message call.
/// If call is successfull, returns call output and gas used,
/// If call is successfull, returns call output and gas left.
/// 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)>;

View File

@ -316,7 +316,7 @@ impl evm::Evm for JitEvm {
let mut context = unsafe { evmjit::ContextHandle::new(data.into_jit(), &mut ext_handle) };
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::Suicide => evm::EvmResult::Suicide,
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 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()),
@ -421,7 +422,8 @@ mod tests {
{
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
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()),
@ -444,7 +446,8 @@ mod tests {
{
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
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()),
@ -468,7 +471,8 @@ mod tests {
{
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
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());
@ -492,7 +496,8 @@ mod tests {
{
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
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());
@ -532,7 +537,8 @@ mod tests {
{
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
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()),
@ -557,7 +563,8 @@ mod tests {
{
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
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)));
@ -578,7 +585,8 @@ mod tests {
{
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
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();
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 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();
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 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()));
@ -668,7 +678,8 @@ mod tests {
{
let mut ext = Externalities::new(&mut state, &info, &engine, 0, &params, &mut substate);
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());

View File

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