Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

refactored loading of execution tests #803

Merged
merged 3 commits into from
Mar 25, 2016
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions ethcore/src/action_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

//! Evm input params.
use common::*;
use ethjson;

/// Transaction value
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -67,3 +68,19 @@ impl Default for ActionParams {
}
}
}

impl From<ethjson::vm::Transaction> for ActionParams {
fn from(t: ethjson::vm::Transaction) -> Self {
ActionParams {
code_address: Address::new(),
address: t.address.into(),
sender: t.sender.into(),
origin: t.origin.into(),
code: Some(t.code.into()),
data: Some(t.data.into()),
gas: t.gas.into(),
gas_price: t.gas_price.into(),
value: ActionValue::Transfer(t.value.into()),
}
}
}
16 changes: 16 additions & 0 deletions ethcore/src/env_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use util::*;
use header::BlockNumber;
use ethjson;

/// Simple vector of hashes, should be at most 256 items large, can be smaller if being used
/// for a block whose number is less than 257.
Expand Down Expand Up @@ -69,6 +70,21 @@ impl FromJson for EnvInfo {
}
}

impl From<ethjson::vm::Env> for EnvInfo {
fn from(e: ethjson::vm::Env) -> Self {
let number = e.number.into();
EnvInfo {
number: number,
author: e.author.into(),
difficulty: e.difficulty.into(),
gas_limit: e.gas_limit.into(),
timestamp: e.timestamp.into(),
last_hashes: (1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().sha3()).collect(),
gas_used: U256::zero(),
}
}
}

#[cfg(test)]
mod tests {
extern crate rustc_serialize;
Expand Down
4 changes: 2 additions & 2 deletions ethcore/src/json_tests/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
let tests = ethjson::blockchain::Test::load(json_data).unwrap();
let mut failed = Vec::new();

for (name, blockchain) in tests.deref() {
for (name, blockchain) in tests.into_iter() {
let mut fail = false;
{
let mut fail_unless = |cond: bool| if !cond && !fail {
Expand Down Expand Up @@ -61,7 +61,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
client.import_verified_blocks(&IoChannel::disconnected());
}
}
fail_unless(client.chain_info().best_block_hash == blockchain.best_block.clone().into());
fail_unless(client.chain_info().best_block_hash == blockchain.best_block.into());
}
}

Expand Down
105 changes: 35 additions & 70 deletions ethcore/src/json_tests/executive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ use ethereum;
use externalities::*;
use substate::*;
use tests::helpers::*;
use state_diff::StateDiff;
use ethjson;

struct TestEngineFrontier {
vm_factory: Factory,
Expand Down Expand Up @@ -53,13 +55,26 @@ impl Engine for TestEngineFrontier {
}
}

#[derive(Debug, PartialEq)]
struct CallCreate {
data: Bytes,
destination: Option<Address>,
gas_limit: U256,
value: U256
}

impl From<ethjson::vm::Call> for CallCreate {
fn from(c: ethjson::vm::Call) -> Self {
let dst: Option<_> = c.destination.into();
CallCreate {
data: c.data.into(),
destination: dst.map(Into::into),
gas_limit: c.gas_limit.into(),
value: c.value.into()
}
}
}

/// Tiny wrapper around executive externalities.
/// Stores callcreates.
struct TestExt<'a> {
Expand Down Expand Up @@ -174,58 +189,26 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
.collect()
}

fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
fn do_json_test_for(vm_type: &VMType, json_data: &[u8]) -> Vec<String> {
let tests = ethjson::vm::Test::load(json_data).unwrap();
let mut failed = Vec::new();
for (name, test) in json.as_object().unwrap() {

for (name, vm) in tests.into_iter() {
println!("name: {:?}", name);
// sync io is usefull when something crashes in jit
// ::std::io::stdout().write(&name.as_bytes());
// ::std::io::stdout().write(b"\n");
// ::std::io::stdout().flush();
let mut fail = false;
//let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.to_string()); fail = true };

let mut fail_unless = |cond: bool, s: &str | if !cond && !fail {
failed.push(format!("[{}] {}: {}", vm, name, s));
failed.push(format!("[{}] {}: {}", vm_type, name, s));
fail = true
};

// test env
let out_of_gas = vm.out_of_gas();
let mut state_result = get_temp_state();
let mut state = state_result.reference_mut();

test.find("pre").map(|pre| for (addr, s) in pre.as_object().unwrap() {
let address = Address::from(addr.as_ref());
let balance = xjson!(&s["balance"]);
let code = xjson!(&s["code"]);
let _nonce: U256 = xjson!(&s["nonce"]);

state.new_contract(&address, balance);
state.init_code(&address, code);
BTreeMap::from_json(&s["storage"]).into_iter().foreach(|(k, v)| state.set_storage(&address, k, v));
});

let info = test.find("env").map(|env| {
EnvInfo::from_json(env)
}).unwrap_or_default();

let engine = TestEngineFrontier::new(1, vm.clone());

// params
let mut params = ActionParams::default();
test.find("exec").map(|exec| {
params.address = xjson!(&exec["address"]);
params.sender = xjson!(&exec["caller"]);
params.origin = xjson!(&exec["origin"]);
params.code = xjson!(&exec["code"]);
params.data = xjson!(&exec["data"]);
params.gas = xjson!(&exec["gas"]);
params.gas_price = xjson!(&exec["gasPrice"]);
params.value = ActionValue::Transfer(xjson!(&exec["value"]));
});

let out_of_gas = test.find("callcreates").map(|_calls| {
}).is_none();
state.populate_from(From::from(vm.pre_state.clone()));
let info = From::from(vm.env);
let engine = TestEngineFrontier::new(1, vm_type.clone());
let params = ActionParams::from(vm.transaction);

let mut substate = Substate::new(false);
let mut output = vec![];
Expand All @@ -247,44 +230,26 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
(res, ex.callcreates)
};

// then validate
match res {
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
Ok(gas_left) => {
// println!("name: {}, gas_left : {:?}", name, gas_left);
fail_unless(!out_of_gas, "expected to run out of gas.");
fail_unless(gas_left == xjson!(&test["gas"]), "gas_left is incorrect");
fail_unless(output == Bytes::from_json(&test["out"]), "output is incorrect");

test.find("post").map(|pre| for (addr, s) in pre.as_object().unwrap() {
let address = Address::from(addr.as_ref());

fail_unless(state.code(&address).unwrap_or_else(|| vec![]) == Bytes::from_json(&s["code"]), "code is incorrect");
fail_unless(state.balance(&address) == xjson!(&s["balance"]), "balance is incorrect");
fail_unless(state.nonce(&address) == xjson!(&s["nonce"]), "nonce is incorrect");
BTreeMap::from_json(&s["storage"]).iter().foreach(|(k, v)| fail_unless(&state.storage_at(&address, &k) == v, "storage is incorrect"));
});

let cc = test["callcreates"].as_array().unwrap();
fail_unless(callcreates.len() == cc.len(), "callcreates does not match");
for i in 0..cc.len() {
let callcreate = &callcreates[i];
let expected = &cc[i];
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");
fail_unless(callcreate.gas_limit == xjson!(&expected["gasLimit"]), "callcreates gas_limit is incorrect");
}
fail_unless(Some(gas_left) == vm.gas_left.map(Into::into), "gas_left is incorrect");
let vm_output: Option<Vec<u8>> = vm.output.map(Into::into);
fail_unless(Some(output) == vm_output, "output is incorrect");

let diff = StateDiff::diff_pod(&state.to_pod(), &From::from(vm.post_state.unwrap()));
fail_unless(diff.is_empty(), format!("diff should be empty!: {:?}", diff).as_ref());
let calls: Option<Vec<CallCreate>> = vm.calls.map(|c| c.into_iter().map(From::from).collect());
fail_unless(Some(callcreates) == calls, "callcreates does not match");
}
}
};
}


for f in &failed {
println!("FAILED: {:?}", f);
}

//assert!(false);
failed
}

Expand Down
2 changes: 1 addition & 1 deletion ethcore/src/pod_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use account::*;
use account_db::*;
use ethjson;

#[derive(Debug,Clone,PartialEq,Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
/// An account, expressed as Plain-Old-Data (hence the name).
/// Does not have a DB overlay cache, code hash or anything like that.
pub struct PodAccount {
Expand Down
10 changes: 9 additions & 1 deletion ethcore/src/state_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use pod_state::*;
use account_diff::*;

#[derive(Debug,Clone,PartialEq,Eq)]
/// Expression for the delta between two system states. Encoded the
/// Expression for the delta between two system states. Encoded the
/// delta of every altered account.
pub struct StateDiff (BTreeMap<Address, AccountDiff>);

Expand All @@ -41,6 +41,14 @@ impl fmt::Display for StateDiff {
}
}

impl Deref for StateDiff {
type Target = BTreeMap<Address, AccountDiff>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

#[cfg(test)]
mod test {
use common::*;
Expand Down
10 changes: 5 additions & 5 deletions json/src/blockchain/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@
//! Blockchain test state deserializer.

use std::collections::BTreeMap;
use std::ops::Deref;
use hash::Address;
use blockchain::account::Account;

/// Blockchain test state deserializer.
#[derive(Debug, PartialEq, Deserialize, Clone)]
pub struct State(pub BTreeMap<Address, Account>);

impl Deref for State {
type Target = BTreeMap<Address, Account>;
impl IntoIterator for State {
type Item = <BTreeMap<Address, Account> as IntoIterator>::Item;
type IntoIter = <BTreeMap<Address, Account> as IntoIterator>::IntoIter;

fn deref(&self) -> &Self::Target {
&self.0
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
10 changes: 5 additions & 5 deletions json/src/blockchain/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
//! Blockchain test deserializer.

use std::collections::BTreeMap;
use std::ops::Deref;
use std::io::Read;
use serde_json;
use serde_json::Error;
Expand All @@ -27,11 +26,12 @@ use blockchain::blockchain::BlockChain;
#[derive(Debug, PartialEq, Deserialize)]
pub struct Test(BTreeMap<String, BlockChain>);

impl Deref for Test {
type Target = BTreeMap<String, BlockChain>;
impl IntoIterator for Test {
type Item = <BTreeMap<String, BlockChain> as IntoIterator>::Item;
type IntoIter = <BTreeMap<String, BlockChain> as IntoIterator>::IntoIter;

fn deref(&self) -> &Self::Target {
&self.0
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}

Expand Down
2 changes: 1 addition & 1 deletion json/src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ macro_rules! impl_hash {
($name: ident, $inner: ident) => {
/// Lenient hash json deserialization for test json files.
#[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
pub struct $name($inner);
pub struct $name(pub $inner);

impl Into<$inner> for $name {
fn into(self) -> $inner {
Expand Down
2 changes: 2 additions & 0 deletions json/src/lib.rs.in
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ pub mod uint;
pub mod bytes;
pub mod blockchain;
pub mod spec;
pub mod vm;
pub mod maybe;
Loading