merged with mk

This commit is contained in:
Tomusdrw
2016-01-16 20:11:12 +01:00
parent 1d53d806b2
commit 3979b787f7
12 changed files with 484 additions and 422 deletions

View File

@@ -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<Address>,
_gas_limit: U256,
gas_limit: U256,
value: U256
}
@@ -47,13 +47,22 @@ struct CallCreate {
/// Stores callcreates.
struct TestExt<'a> {
ext: Externalities<'a>,
callcreates: Vec<CallCreate>
callcreates: Vec<CallCreate>,
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<Address>) {
// 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<String> {
@@ -206,7 +197,7 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
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<String> {
// execute
let (res, callcreates) = {
let ex = Externalities::new(&mut state, &info, &engine, 0, &params, &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(&params),
&mut substate,
OutputPolicy::Return(BytesRef::Flexible(&mut output)),
params.address.clone());
let evm = engine.vm_factory().create();
let res = evm.exec(&params, &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<String> {
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");
}
}
}

View File

@@ -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<String> {
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<String> {
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"]);