executive tests
This commit is contained in:
parent
09662ace50
commit
68a2c843ef
@ -14,7 +14,7 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
|
|||||||
|
|
||||||
/// State changes which should be applied in finalize,
|
/// State changes which should be applied in finalize,
|
||||||
/// after transaction is fully executed.
|
/// after transaction is fully executed.
|
||||||
struct Substate {
|
pub struct Substate {
|
||||||
/// Any accounts that have suicided.
|
/// Any accounts that have suicided.
|
||||||
suicides: HashSet<Address>,
|
suicides: HashSet<Address>,
|
||||||
/// Any logs.
|
/// Any logs.
|
||||||
@ -27,7 +27,7 @@ struct Substate {
|
|||||||
|
|
||||||
impl Substate {
|
impl Substate {
|
||||||
/// Creates new substate.
|
/// Creates new substate.
|
||||||
fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Substate {
|
Substate {
|
||||||
suicides: HashSet::new(),
|
suicides: HashSet::new(),
|
||||||
logs: vec![],
|
logs: vec![],
|
||||||
@ -172,7 +172,7 @@ impl<'a> Executive<'a> {
|
|||||||
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
||||||
/// Modifies the substate and the output.
|
/// Modifies the substate and the output.
|
||||||
/// Returns either gas_left or `evm::Error`.
|
/// Returns either gas_left or `evm::Error`.
|
||||||
fn call(&mut self, params: &ActionParams, substate: &mut Substate, output: &mut [u8]) -> evm::Result {
|
pub fn call(&mut self, params: &ActionParams, substate: &mut Substate, output: &mut [u8]) -> evm::Result {
|
||||||
// at first, transfer value to destination
|
// at first, transfer value to destination
|
||||||
self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value);
|
self.state.transfer_balance(¶ms.sender, ¶ms.address, ¶ms.value);
|
||||||
|
|
||||||
@ -332,12 +332,12 @@ impl<'a> Ext for Externalities<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn blockhash(&self, number: &U256) -> H256 {
|
fn blockhash(&self, number: &U256) -> H256 {
|
||||||
match *number < U256::from(self.info.number) {
|
match *number < U256::from(self.info.number) && number.low_u64() >= cmp::max(256, self.info.number) - 256 {
|
||||||
false => H256::from(&U256::zero()),
|
|
||||||
true => {
|
true => {
|
||||||
let index = U256::from(self.info.number) - *number - U256::one();
|
let index = self.info.number - number.low_u64() - 1;
|
||||||
self.info.last_hashes[index.low_u32() as usize].clone()
|
self.info.last_hashes[index as usize].clone()
|
||||||
}
|
},
|
||||||
|
false => H256::from(&U256::zero()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,7 +415,6 @@ impl<'a> Ext for Externalities<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ret(&mut self, gas: u64, data: &[u8]) -> Result<u64, evm::Error> {
|
fn ret(&mut self, gas: u64, data: &[u8]) -> Result<u64, evm::Error> {
|
||||||
println!("ret");
|
|
||||||
match &mut self.output {
|
match &mut self.output {
|
||||||
&mut OutputPolicy::Return(ref mut slice) => unsafe {
|
&mut OutputPolicy::Return(ref mut slice) => unsafe {
|
||||||
let len = cmp::min(slice.len(), data.len());
|
let len = cmp::min(slice.len(), data.len());
|
||||||
@ -472,7 +471,7 @@ mod tests {
|
|||||||
use engine::*;
|
use engine::*;
|
||||||
use spec::*;
|
use spec::*;
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
use super::Substate;
|
//use super::Substate;
|
||||||
|
|
||||||
struct TestEngine {
|
struct TestEngine {
|
||||||
spec: Spec,
|
spec: Spec,
|
||||||
@ -482,7 +481,7 @@ mod tests {
|
|||||||
impl TestEngine {
|
impl TestEngine {
|
||||||
fn new(stack_limit: usize) -> TestEngine {
|
fn new(stack_limit: usize) -> TestEngine {
|
||||||
TestEngine {
|
TestEngine {
|
||||||
spec: ethereum::new_frontier(),
|
spec: ethereum::new_frontier_test(),
|
||||||
stack_limit: stack_limit
|
stack_limit: stack_limit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
125
src/tests/executive.rs
Normal file
125
src/tests/executive.rs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
use super::test_common::*;
|
||||||
|
use state::*;
|
||||||
|
use executive::*;
|
||||||
|
use spec::*;
|
||||||
|
use engine::*;
|
||||||
|
use evm::{Schedule};
|
||||||
|
use ethereum;
|
||||||
|
|
||||||
|
struct TestEngine {
|
||||||
|
spec: Spec,
|
||||||
|
stack_limit: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestEngine {
|
||||||
|
fn new(stack_limit: usize) -> TestEngine {
|
||||||
|
TestEngine {
|
||||||
|
spec: ethereum::new_frontier_test(),
|
||||||
|
stack_limit: stack_limit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine for TestEngine {
|
||||||
|
fn name(&self) -> &str { "TestEngine" }
|
||||||
|
fn spec(&self) -> &Spec { &self.spec }
|
||||||
|
fn schedule(&self, _env_info: &EnvInfo) -> Schedule {
|
||||||
|
let mut schedule = Schedule::new_frontier();
|
||||||
|
schedule.stack_limit = self.stack_limit;
|
||||||
|
schedule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
for (name, test) in json.as_object().unwrap() {
|
||||||
|
::std::io::stdout().write(&name.as_bytes());
|
||||||
|
::std::io::stdout().write(b"\n");
|
||||||
|
::std::io::stdout().flush();
|
||||||
|
//println!("name: {:?}", name);
|
||||||
|
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(name.to_string() + ": "+ s); fail = true };
|
||||||
|
|
||||||
|
// test env
|
||||||
|
let mut state = State::new_temp();
|
||||||
|
|
||||||
|
test.find("pre").map(|pre| for (addr, s) in pre.as_object().unwrap() {
|
||||||
|
let address = address_from_str(addr);
|
||||||
|
let balance = u256_from_json(&s["balance"]);
|
||||||
|
let code = bytes_from_json(&s["code"]);
|
||||||
|
let nonce = u256_from_json(&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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
|
||||||
|
let engine = TestEngine::new(0);
|
||||||
|
|
||||||
|
// 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"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
let out_of_gas = test.find("callcreates").map(|calls| {
|
||||||
|
}).is_none();
|
||||||
|
|
||||||
|
let mut substate = Substate::new();
|
||||||
|
|
||||||
|
// execute
|
||||||
|
let res = {
|
||||||
|
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||||
|
ex.call(¶ms, &mut substate, &mut [])
|
||||||
|
};
|
||||||
|
|
||||||
|
// then validate
|
||||||
|
match res {
|
||||||
|
Err(_) => fail_unless(out_of_gas, "didn't expect to run out of gas."),
|
||||||
|
Ok(gas_left) => {
|
||||||
|
fail_unless(!out_of_gas, "expected to run out of gas.");
|
||||||
|
fail_unless(gas_left == u256_from_json(&test["gas"]), "gas_left is incorrect");
|
||||||
|
println!("name: {}, gas_left : {:?}, expected: {:?}", name, gas_left, u256_from_json(&test["gas"]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for f in failed.iter() {
|
||||||
|
println!("FAILED: {:?}", f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//assert!(false);
|
||||||
|
failed
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_test!{ExecutiveTests_vmArithmeticTest, "VMTests/vmArithmeticTest"}
|
||||||
|
declare_test!{ExecutiveTests_vmSha3Test, "VMTests/vmSha3Test"}
|
||||||
|
declare_test!{ExecutiveTests_vmBitwiseLogicOperationTest, "VMTests/vmBitwiseLogicOperationTest"}
|
||||||
|
//declare_test!{ExecutiveTests_vmBlockInfoTest, "VMTests/vmBlockInfoTest"}
|
||||||
|
declare_test!{ExecutiveTests_vmEnvironmentalInfoTest, "VMTests/vmEnvironmentalInfoTest"}
|
@ -1,4 +1,5 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod test_common;
|
mod test_common;
|
||||||
|
|
||||||
mod transaction;
|
mod transaction;
|
||||||
|
mod executive;
|
||||||
|
@ -18,7 +18,10 @@ pub fn bytes_from_json(json: &Json) -> Bytes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn address_from_json(json: &Json) -> Address {
|
pub fn address_from_json(json: &Json) -> Address {
|
||||||
let s = json.as_string().unwrap();
|
address_from_str(json.as_string().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn address_from_str<'a>(s: &'a str) -> Address {
|
||||||
if s.len() % 2 == 1 {
|
if s.len() % 2 == 1 {
|
||||||
address_from_hex(&("0".to_string() + &(clean(s).to_string()))[..])
|
address_from_hex(&("0".to_string() + &(clean(s).to_string()))[..])
|
||||||
} else {
|
} else {
|
||||||
@ -27,7 +30,10 @@ pub fn address_from_json(json: &Json) -> Address {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn u256_from_json(json: &Json) -> U256 {
|
pub fn u256_from_json(json: &Json) -> U256 {
|
||||||
let s = json.as_string().unwrap();
|
u256_from_str(json.as_string().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn u256_from_str<'a>(s: &'a str) -> U256 {
|
||||||
if s.len() >= 2 && &s[0..2] == "0x" {
|
if s.len() >= 2 && &s[0..2] == "0x" {
|
||||||
// hex
|
// hex
|
||||||
U256::from_str(&s[2..]).unwrap()
|
U256::from_str(&s[2..]).unwrap()
|
||||||
|
@ -8,7 +8,7 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
|
|||||||
let new_schedule = evm::Schedule::new_homestead();
|
let new_schedule = evm::Schedule::new_homestead();
|
||||||
for (name, test) in json.as_object().unwrap() {
|
for (name, test) in json.as_object().unwrap() {
|
||||||
let mut fail = false;
|
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| if !cond && !fail { failed.push(name.to_string()); fail = true };
|
||||||
let schedule = match test.find("blocknumber")
|
let schedule = match test.find("blocknumber")
|
||||||
.and_then(|j| j.as_string())
|
.and_then(|j| j.as_string())
|
||||||
.and_then(|s| BlockNumber::from_str(s).ok())
|
.and_then(|s| BlockNumber::from_str(s).ok())
|
||||||
|
Loading…
Reference in New Issue
Block a user