Merge branch 'master' into evm

Conflicts:
	src/executive.rs
	src/tests/state.rs
This commit is contained in:
Tomusdrw
2016-01-15 02:05:32 +01:00
21 changed files with 782 additions and 733 deletions

View File

@@ -36,7 +36,7 @@ impl Engine for TestEngine {
struct CallCreate {
data: Bytes,
destination: Address,
destination: Option<Address>,
_gas_limit: U256,
value: U256
}
@@ -74,33 +74,33 @@ impl<'a> Ext for TestExt<'a> {
self.ext.blockhash(number)
}
fn create(&mut self, gas: &U256, value: &U256, code: &[u8]) -> Result<(U256, Option<Address>), evm::Error> {
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
Ok((gas_left, Some(address))) => {
(gas_left, Some(address)) => {
self.callcreates.push(CallCreate {
data: code.to_vec(),
destination: address.clone(),
destination: Some(address.clone()),
_gas_limit: *gas,
value: *value
});
Ok((gas_left, Some(address)))
(gas_left, Some(address))
},
// creation failed only due to reaching max_depth
Ok((gas_left, None)) if ext.state.balance(&ext.params.address) >= *value => {
let address = contract_address(&ext.params.address, &ext.state.nonce(&ext.params.address));
(gas_left, None) if ext.state.balance(&ext.params.address) >= *value => {
self.callcreates.push(CallCreate {
data: code.to_vec(),
// TODO: address is not stored here?
destination: Address::new(),
// callcreate test does not need an address
destination: None,
_gas_limit: *gas,
value: *value
});
Ok((gas_left, Some(address)))
let address = contract_address(&ext.params.address, &ext.state.nonce(&ext.params.address));
(gas_left, Some(address))
},
other => other
}
@@ -113,21 +113,20 @@ impl<'a> Ext for TestExt<'a> {
value: &U256,
data: &[u8],
code_address: &Address,
output: &mut [u8]) -> Result<U256, evm::Error> {
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;
match res {
Ok(gas_left) if ext.state.balance(&ext.params.address) >= *value => {
if let &Ok(_some) = &res {
if ext.state.balance(&ext.params.address) >= *value {
self.callcreates.push(CallCreate {
data: data.to_vec(),
destination: receive_address.clone(),
destination: Some(receive_address.clone()),
_gas_limit: *call_gas,
value: *value
});
Ok(gas_left)
},
other => other
}
}
res
}
fn extcode(&self, address: &Address) -> Vec<u8> {
@@ -168,6 +167,7 @@ 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");
let mut failed = Vec::new();
for (name, test) in json.as_object().unwrap() {
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");
@@ -184,29 +184,24 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
test.find("pre").map(|pre| for (addr, s) in pre.as_object().unwrap() {
let address = Address::from(addr.as_ref());
let balance = u256_from_json(&s["balance"]);
let code = bytes_from_json(&s["code"]);
let _nonce = u256_from_json(&s["nonce"]);
let balance = xjson!(&s["balance"]);
let code = xjson!(&s["code"]);
let _nonce: U256 = xjson!(&s["nonce"]);
state.new_contract(&address);
state.add_balance(&address, &balance);
state.init_code(&address, code);
for (k, v) in s["storage"].as_object().unwrap() {
let key = H256::from(&u256_from_str(k));
let val = H256::from(&u256_from_json(v));
state.set_storage(&address, key, val);
}
BTreeMap::from_json(&s["storage"]).into_iter().foreach(|(k, v)| state.set_storage(&address, k, v));
});
let mut info = EnvInfo::new();
test.find("env").map(|env| {
info.author = address_from_json(&env["currentCoinbase"]);
info.difficulty = u256_from_json(&env["currentDifficulty"]);
info.gas_limit = u256_from_json(&env["currentGasLimit"]);
info.number = u256_from_json(&env["currentNumber"]).low_u64();
info.timestamp = u256_from_json(&env["currentTimestamp"]).low_u64();
info.author = xjson!(&env["currentCoinbase"]);
info.difficulty = xjson!(&env["currentDifficulty"]);
info.gas_limit = xjson!(&env["currentGasLimit"]);
info.number = xjson!(&env["currentNumber"]);
info.timestamp = xjson!(&env["currentTimestamp"]);
});
let engine = TestEngine::new(0, vm.clone());
@@ -214,14 +209,14 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
// params
let mut params = ActionParams::new();
test.find("exec").map(|exec| {
params.address = address_from_json(&exec["address"]);
params.sender = address_from_json(&exec["caller"]);
params.origin = address_from_json(&exec["origin"]);
params.code = bytes_from_json(&exec["code"]);
params.data = bytes_from_json(&exec["data"]);
params.gas = u256_from_json(&exec["gas"]);
params.gas_price = u256_from_json(&exec["gasPrice"]);
params.value = u256_from_json(&exec["value"]);
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 = xjson!(&exec["value"]);
});
let out_of_gas = test.find("callcreates").map(|_calls| {
@@ -243,41 +238,33 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
match res {
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
Ok(gas_left) => {
//println!("name: {}, gas_left : {:?}, expected: {:?}", name, gas_left, u256_from_json(&test["gas"]));
//println!("name: {}, gas_left : {:?}, expected: {:?}", name, gas_left, U256::from(&test["gas"]));
fail_unless(!out_of_gas, "expected to run out of gas.");
fail_unless(gas_left == u256_from_json(&test["gas"]), "gas_left is incorrect");
fail_unless(output == bytes_from_json(&test["out"]), "output is incorrect");
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());
//let balance = u256_from_json(&s["balance"]);
fail_unless(state.code(&address).unwrap_or(vec![]) == bytes_from_json(&s["code"]), "code is incorrect");
fail_unless(state.balance(&address) == u256_from_json(&s["balance"]), "balance is incorrect");
fail_unless(state.nonce(&address) == u256_from_json(&s["nonce"]), "nonce is incorrect");
for (k, v) in s["storage"].as_object().unwrap() {
let key = H256::from(&u256_from_str(k));
let val = H256::from(&u256_from_json(v));
fail_unless(state.storage_at(&address, &key) == val, "storage is incorrect");
}
fail_unless(state.code(&address).unwrap_or(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 is = &callcreates[i];
let callcreate = &callcreates[i];
let expected = &cc[i];
fail_unless(is.data == bytes_from_json(&expected["data"]), "callcreates data is incorrect");
fail_unless(is.destination == address_from_json(&expected["destination"]), "callcreates destination is incorrect");
fail_unless(is.value == u256_from_json(&expected["value"]), "callcreates value is incorrect");
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: {:?}, is {:?}, expected: {:?}", name, is.gas_limit, u256_from_json(&expected["gasLimit"]));
//fail_unless(is.gas_limit == u256_from_json(&expected["gasLimit"]), "callcreates gas_limit is incorrect");
//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");
}
}
}

View File

@@ -1,5 +1,7 @@
use super::test_common::*;
use state::*;
use pod_state::*;
use state_diff::*;
use ethereum;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
@@ -9,13 +11,14 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
let engine = ethereum::new_frontier_test().to_engine().unwrap();
for (name, test) in json.as_object().unwrap() {
println!("name: {:?}", name);
let mut fail = false;
let mut fail_unless = |cond: bool| if !cond && !fail { failed.push(name.to_string()); fail = true; true } else {false};
let t = Transaction::from_json(&test["transaction"]);
let env = EnvInfo::from_json(&test["env"]);
let _out = bytes_from_json(&test["out"]);
let post_state_root = h256_from_json(&test["postStateRoot"]);
let _out = Bytes::from_json(&test["out"]);
let post_state_root = xjson!(&test["postStateRoot"]);
let pre = PodState::from_json(&test["pre"]);
let post = PodState::from_json(&test["post"]);
let logs: Vec<_> = test["logs"].as_array().unwrap().iter().map(&LogEntry::from_json).collect();
@@ -39,7 +42,7 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
let our_post = s.to_pod();
println!("Got:\n{}", our_post);
println!("Expect:\n{}", post);
println!("Diff ---expect -> +++got:\n{}", pod_state_diff(&post, &our_post));
println!("Diff ---expect -> +++got:\n{}", StateDiff::diff_pod(&post, &our_post));
}
if fail_unless(logs == r.logs) {
@@ -56,4 +59,7 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
}
declare_test!{StateTests_stExample, "StateTests/stExample"}
declare_test!{StateTests_stBlockHashTest, "StateTests/stBlockHashTest"}
declare_test!{StateTests_stLogTests, "StateTests/stLogTests"}
declare_test!{StateTests_stCallCodes, "StateTests/stCallCodes"}
declare_test_ignore!{StateTests_stCallCreateCallCodeTest, "StateTests/stCallCreateCallCodeTest"}

View File

@@ -14,23 +14,23 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
.and_then(|j| j.as_string())
.and_then(|s| BlockNumber::from_str(s).ok())
.unwrap_or(0) { x if x < 900000 => &old_schedule, _ => &new_schedule };
let rlp = bytes_from_json(&test["rlp"]);
let rlp = Bytes::from_json(&test["rlp"]);
let res = UntrustedRlp::new(&rlp).as_val().map_err(|e| From::from(e)).and_then(|t: Transaction| t.validate(schedule, schedule.have_delegate_call));
fail_unless(test.find("transaction").is_none() == res.is_err());
if let (Some(&Json::Object(ref tx)), Some(&Json::String(ref expect_sender))) = (test.find("transaction"), test.find("sender")) {
let t = res.unwrap();
fail_unless(t.sender().unwrap() == address_from_hex(clean(expect_sender)));
fail_unless(t.data == bytes_from_json(&tx["data"]));
fail_unless(t.gas == u256_from_json(&tx["gasLimit"]));
fail_unless(t.gas_price == u256_from_json(&tx["gasPrice"]));
fail_unless(t.nonce == u256_from_json(&tx["nonce"]));
fail_unless(t.value == u256_from_json(&tx["value"]));
fail_unless(t.data == Bytes::from_json(&tx["data"]));
fail_unless(t.gas == xjson!(&tx["gasLimit"]));
fail_unless(t.gas_price == xjson!(&tx["gasPrice"]));
fail_unless(t.nonce == xjson!(&tx["nonce"]));
fail_unless(t.value == xjson!(&tx["value"]));
if let Action::Call(ref to) = t.action {
*ot.borrow_mut() = t.clone();
fail_unless(to == &address_from_json(&tx["to"]));
fail_unless(to == &xjson!(&tx["to"]));
} else {
*ot.borrow_mut() = t.clone();
fail_unless(bytes_from_json(&tx["to"]).len() == 0);
fail_unless(Bytes::from_json(&tx["to"]).len() == 0);
}
}
}