From d2e53f95e0e4230684ef052684758c469d747260 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 15 Jan 2016 01:02:14 +0100 Subject: [PATCH 1/4] More State tests! --- src/executive.rs | 2 +- src/tests/state.rs | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/executive.rs b/src/executive.rs index cbaa1058d..65bc71aa2 100644 --- a/src/executive.rs +++ b/src/executive.rs @@ -252,7 +252,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 diff --git a/src/tests/state.rs b/src/tests/state.rs index ce89003e1..1e3b6da6a 100644 --- a/src/tests/state.rs +++ b/src/tests/state.rs @@ -58,8 +58,22 @@ fn do_json_test(json_data: &[u8]) -> Vec { 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"} // << XXX FIXME +declare_test!{StateTests_stDelegatecallTest, "StateTests/stDelegatecallTest"} +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"} // << XXX FIXME +declare_test_ignore!{StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} // << XXX FIXME +declare_test!{StateTests_stRefundTest, "StateTests/stRefundTest"} +declare_test!{StateTests_stSolidityTest, "StateTests/stSolidityTest"} +declare_test!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} +declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} +declare_test!{StateTests_stTransactionTest, "StateTests/stTransactionTest"} +declare_test!{StateTests_stTransitionTest, "StateTests/stTransitionTest"} +declare_test!{StateTests_stWalletTest, "StateTests/stWalletTest"} From 02e2b75407bec92fcd5658d6f6667bac60c21774 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 15 Jan 2016 01:44:23 +0100 Subject: [PATCH 2/4] Fix state test. --- src/state.rs | 2 +- src/tests/state.rs | 30 ++++++++++++++++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/state.rs b/src/state.rs index fdf71a496..3a4ad1833 100644 --- a/src/state.rs +++ b/src/state.rs @@ -140,7 +140,7 @@ impl State { /// This will change the state accordingly. pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult { let e = try!(Executive::new(self, env_info, engine).transact(t)); - //println!("Executed: {:?}", e); + println!("Executed: {:?}", e); self.commit(); Ok(Receipt::new(self.root().clone(), e.gas_used, e.logs)) } diff --git a/src/tests/state.rs b/src/tests/state.rs index 1e3b6da6a..8aeb20560 100644 --- a/src/tests/state.rs +++ b/src/tests/state.rs @@ -35,22 +35,24 @@ fn do_json_test(json_data: &[u8]) -> Vec { let mut s = State::new_temp(); s.populate_from(pre); - let r = s.apply(&env, engine.deref(), &t).unwrap(); + s.commit(); + let res = s.apply(&env, engine.deref(), &t); - if fail_unless(&r.state_root == &post_state_root) { - println!("!!! {}: State mismatch (got: {}, expect: {}):", name, r.state_root, post_state_root); + 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(logs == r.logs) { - println!("!!! {}: Logs mismatch:", name); - println!("Got:\n{:?}", r.logs); - println!("Expect:\n{:?}", logs); + if let Ok(r) = res { + if fail_unless(logs == r.logs) { + println!("!!! {}: Logs mismatch:", name); + println!("Got:\n{:?}", r.logs); + println!("Expect:\n{:?}", logs); + } } - // TODO: Add extra APIs for output //if fail_unless(out == r.) } @@ -60,20 +62,20 @@ fn do_json_test(json_data: &[u8]) -> Vec { declare_test!{StateTests_stBlockHashTest, "StateTests/stBlockHashTest"} declare_test!{StateTests_stCallCodes, "StateTests/stCallCodes"} -declare_test_ignore!{StateTests_stCallCreateCallCodeTest, "StateTests/stCallCreateCallCodeTest"} // << XXX FIXME -declare_test!{StateTests_stDelegatecallTest, "StateTests/stDelegatecallTest"} +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"} // << XXX FIXME -declare_test_ignore!{StateTests_stRecursiveCreate, "StateTests/stRecursiveCreate"} // << XXX FIXME +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!{StateTests_stSpecialTest, "StateTests/stSpecialTest"} -declare_test!{StateTests_stSystemOperationsTest, "StateTests/stSystemOperationsTest"} +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"} From 7c5c2bd9b8459b9b93d3699da3c58c5fd257be74 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 15 Jan 2016 01:53:52 +0100 Subject: [PATCH 3/4] Ethash populate_from_parent implementation. --- src/ethereum/ethash.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ethereum/ethash.rs b/src/ethereum/ethash.rs index f2f5eeafd..80ebcb4a2 100644 --- a/src/ethereum/ethash.rs +++ b/src/ethereum/ethash.rs @@ -14,6 +14,8 @@ impl Ethash { pub fn new_boxed(spec: Spec) -> Box { 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 { @@ -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) { @@ -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 { From b6139d20648106e1cbe5bc9dc96cd7c8bfd2dcbc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 15 Jan 2016 04:02:06 +0100 Subject: [PATCH 4/4] Remove debug stuff. --- src/state.rs | 12 +++---- src/tests/state.rs | 88 ++++++++++++++++++++++++++++------------------ 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/src/state.rs b/src/state.rs index 3a4ad1833..648caa20a 100644 --- a/src/state.rs +++ b/src/state.rs @@ -140,9 +140,9 @@ impl State { /// This will change the state accordingly. pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &Transaction) -> ApplyResult { let e = try!(Executive::new(self, env_info, engine).transact(t)); - println!("Executed: {:?}", e); + //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) { @@ -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>) -> H256 { + pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap>) { // 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() { @@ -170,7 +170,7 @@ 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()), @@ -178,13 +178,11 @@ impl State { } } } - 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`. diff --git a/src/tests/state.rs b/src/tests/state.rs index 8aeb20560..fdedd7a83 100644 --- a/src/tests/state.rs +++ b/src/tests/state.rs @@ -4,54 +4,72 @@ 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 { 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 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 fail_unless = |cond: bool| if !cond && !fail { + failed.push(name.to_string()); + flush(format!("FAIL\n")); + fail = true; + true + } else {false}; - let mut s = State::new_temp(); - s.populate_from(pre); - s.commit(); - let res = s.apply(&env, engine.deref(), &t); + flush(format!(" - {}...", name)); - 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)); - } + 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(); - if let Ok(r) = res { - if fail_unless(logs == r.logs) { - println!("!!! {}: Logs mismatch:", name); - println!("Got:\n{:?}", r.logs); - println!("Expect:\n{:?}", logs); + //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(pre); + s.commit(); + let res = s.apply(&env, engine.deref(), &t); + + 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 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 { + flush(format!("ok\n")); } // TODO: Add extra APIs for output //if fail_unless(out == r.)