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

More state tests. #122

Merged
merged 5 commits into from
Jan 15, 2016
Merged
Show file tree
Hide file tree
Changes from all 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: 16 additions & 1 deletion src/ethereum/ethash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ impl Ethash {
pub fn new_boxed(spec: Spec) -> Box<Engine> {
Box::new(Ethash{spec: spec})
}

fn u256_param(&self, name: &str) -> U256 { self.spec().engine_params.get(name).map(|a| decode(&a)).unwrap_or(U256::from(0u64)) }
}

impl Engine for Ethash {
Expand All @@ -29,6 +31,20 @@ impl Engine for Ethash {
fn spec(&self) -> &Spec { &self.spec }
fn schedule(&self, _env_info: &EnvInfo) -> Schedule { Schedule::new_frontier() }

fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
header.difficulty = self.calculate_difficuty(header, parent);
header.gas_limit = {
let gas_floor_target: U256 = x!(3141562);
let gas_limit = parent.gas_limit;
let bound_divisor = self.u256_param("gasLimitBoundDivisor");
if gas_limit < gas_floor_target {
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - x!(1))
} else {
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + x!(1) + (header.gas_used * x!(6) / x!(5)) / bound_divisor)
}
};
}

/// Apply the block reward on finalisation of the block.
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
fn on_close_block(&self, block: &mut Block) {
Expand All @@ -45,7 +61,6 @@ impl Engine for Ethash {
}
}


fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
let min_difficulty = decode(self.spec().engine_params.get("minimumDifficulty").unwrap());
if header.difficulty < min_difficulty {
Expand Down
2 changes: 1 addition & 1 deletion src/executive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ impl<'a> Executive<'a> {
let gas_left = match &result { &Ok(x) => x, _ => x!(0) };
let refund = cmp::min(sstore_refunds + suicide_refunds, (t.gas - gas_left) / U256::from(2)) + gas_left;
let refund_value = refund * t.gas_price;
trace!("Refunding sender: gas_left: {}, refund: {}, refund_value: {}, sender: {}", gas_left, refund, refund_value, t.sender().unwrap());
trace!("Refunding sender: sstore0s: {}, suicides: {}, gas_left: {}, refund: {}, refund_value: {}, sender: {}", sstore_refunds, suicide_refunds, gas_left, refund, refund_value, t.sender().unwrap());
self.state.add_balance(&t.sender().unwrap(), &refund_value);

// fees earned by author
Expand Down
10 changes: 4 additions & 6 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl State {
let e = try!(Executive::new(self, env_info, engine).transact(t));
//println!("Executed: {:?}", e);
self.commit();
Ok(Receipt::new(self.root().clone(), e.gas_used, e.logs))
Ok(Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs))
}

pub fn revert(&mut self, backup: State) {
Expand All @@ -156,7 +156,7 @@ impl State {

/// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit.
/// `accounts` is mutable because we may need to commit the code or storage and record that.
pub fn commit_into(db: &mut HashDB, mut root: H256, accounts: &mut HashMap<Address, Option<Account>>) -> H256 {
pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap<Address, Option<Account>>) {
// first, commit the sub trees.
// TODO: is this necessary or can we dispense with the `ref mut a` for just `a`?
for (_, ref mut a) in accounts.iter_mut() {
Expand All @@ -170,21 +170,19 @@ impl State {
}

{
let mut trie = SecTrieDBMut::from_existing(db, &mut root);
let mut trie = SecTrieDBMut::from_existing(db, root);
for (address, ref a) in accounts.iter() {
match a {
&&Some(ref account) => trie.insert(address, &account.rlp()),
&&None => trie.remove(address),
}
}
}
root
}

/// Commits our cached account changes into the trie.
pub fn commit(&mut self) {
let r = self.root.clone(); // would prefer not to do this, really.
self.root = Self::commit_into(&mut self.db, r, self.cache.borrow_mut().deref_mut());
Self::commit_into(&mut self.db, &mut self.root, self.cache.borrow_mut().deref_mut());
}

/// Populate the state from `accounts`.
Expand Down
100 changes: 67 additions & 33 deletions src/tests/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,96 @@ use pod_state::*;
use state_diff::*;
use ethereum;

fn flush(s: String) {
::std::io::stdout().write(s.as_bytes()).unwrap();
::std::io::stdout().flush().unwrap();
}

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();

flush(format!("\n"));

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 mut fail_unless = |cond: bool| if !cond && !fail {
failed.push(name.to_string());
flush(format!("FAIL\n"));
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 = 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();
flush(format!(" - {}...", name));

//println!("Transaction: {:?}", t);
//println!("Env: {:?}", env);
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 = 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();

//println!("Transaction: {:?}", t);
//println!("Env: {:?}", env);

{
let mut s = State::new_temp();
s.populate_from(post.clone());
s.commit();
assert_eq!(&post_state_root, s.root());
}

{
let mut s = State::new_temp();
s.populate_from(post.clone());
s.populate_from(pre);
s.commit();
assert_eq!(&post_state_root, s.root());
}
let res = s.apply(&env, engine.deref(), &t);

let mut s = State::new_temp();
s.populate_from(pre);
let r = s.apply(&env, engine.deref(), &t).unwrap();
if fail_unless(s.root() == &post_state_root) {
println!("!!! {}: State mismatch (got: {}, expect: {}):", name, s.root(), post_state_root);
let our_post = s.to_pod();
println!("Got:\n{}", our_post);
println!("Expect:\n{}", post);
println!("Diff ---expect -> +++got:\n{}", StateDiff::diff_pod(&post, &our_post));
}

if fail_unless(&r.state_root == &post_state_root) {
println!("!!! {}: State mismatch (got: {}, expect: {}):", name, r.state_root, post_state_root);
let our_post = s.to_pod();
println!("Got:\n{}", our_post);
println!("Expect:\n{}", post);
println!("Diff ---expect -> +++got:\n{}", StateDiff::diff_pod(&post, &our_post));
if let Ok(r) = res {
if fail_unless(logs == r.logs) {
println!("!!! {}: Logs mismatch:", name);
println!("Got:\n{:?}", r.logs);
println!("Expect:\n{:?}", logs);
}
}
}

if fail_unless(logs == r.logs) {
println!("!!! {}: Logs mismatch:", name);
println!("Got:\n{:?}", r.logs);
println!("Expect:\n{:?}", logs);
if !fail {
flush(format!("ok\n"));
}

// TODO: Add extra APIs for output
//if fail_unless(out == r.)
}
println!("!!! {:?} tests from failed.", failed.len());
failed
}

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"}
declare_test_ignore!{StateTests_stCallCreateCallCodeTest, "StateTests/stCallCreateCallCodeTest"} //<< Out of stack
declare_test!{StateTests_stDelegatecallTest, "StateTests/stDelegatecallTest"} //<< FAIL - gas too high
declare_test!{StateTests_stExample, "StateTests/stExample"}
declare_test!{StateTests_stInitCodeTest, "StateTests/stInitCodeTest"}
declare_test!{StateTests_stLogTests, "StateTests/stLogTests"}
declare_test!{StateTests_stMemoryStressTest, "StateTests/stMemoryStressTest"}
declare_test!{StateTests_stMemoryTest, "StateTests/stMemoryTest"}
declare_test!{StateTests_stPreCompiledContracts, "StateTests/stPreCompiledContracts"}
declare_test_ignore!{StateTests_stQuadraticComplexityTest, "StateTests/stQuadraticComplexityTest"} //<< Too long
declare_test_ignore!{StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} //<< Out of stack
declare_test!{StateTests_stRefundTest, "StateTests/stRefundTest"}
declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"}
declare_test_ignore!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} //<< Signal 11
declare_test_ignore!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} //<< Signal 11
declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"}
declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"}
declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"}